对象缓存
MediaWiki在多个组件和多个层之中使用缓存。 本页面记录了我们在MediaWiki PHP应用程序內部所使用的各种缓存。
概述
在MediaWiki中的物件缓存的上下文中,描述了两种類型的存储體:
- 缓存(Cache):是一個存储计算结果或获取自外部源的数据(用于更高的存取速度)的地方。 这是计算机科学定义中的“缓存”。
- 贮存(Stash)。一个存储轻量级数据的地方、不會將它存储到其他的地方。 也称为藏匿(或“囤积”物件)。 这些值是不可能(或不允许)在需要時重新计算。
术语
如果程序能够验证该值是否过期,则称缓存鍵为“可验证”。
当某个鍵只可能有一个值时(例如在计算π的第100位),該值可被快取於鍵math_pi_digit:100之下。
其结果可以安全地存储在高速存取的存储體之中,无需协调機制,因为你永远不需要將它更新或清除。
如果它在缓存中过期,你可以重新计算它然後产生相同的结果。
这同样适用于将某个修訂版本的Wikitext存储到页面之中。
修訂版本123已经降臨,然後将始终包含相同的内容。
如果程序知道它正在查找的修订ID,那么像revision_content:123这样的缓存鍵也可以是個可验证的缓存鍵。
存储结构化数据
MediaWiki支持存储数组的原始值(bool、int、string)和(可能是嵌套的)结构。 技术上也可以存储普通物件(stdClass)和任意类的实例,这依赖于PHP序列化,但出于安全原因(T161647)和稳定性原因,不推荐使用这种机制,因为很难以不破坏与该类缓存物件的前向或后向兼容性的方式更改类(例如T264257等)。
写入或读取缓存的代码必须前后兼容。 通常,读取缓存数据的代码将具有与写入缓存数据的相同或更新的代码(需要向后兼容的读取逻辑,或提前转发兼容的写入),但有两种重要情况也需要相反的情况:
- 在部署过程中,不同的服务器和数据中心使用相同的共享数据库和缓存服务短暂地并行运行旧版本和新版本。
因此,在这段时间内,缓存很可能同时写入旧版本和从新版本中读取。
- 站点的操作员必须能够将软件最後一次的部署或升级回滚到以前的版本。
最佳实践:
- 請避免在各個缓存的键之中放置版本常量。 利用
WANObjectCache::getWithSet的习惯用法及其“版本”选项,它自动处理前向和后向兼容性,包括在软件的各个版本中使缓存密钥无效。 - 請避免存储类物件。 存储原始值或(嵌套的)原始值数组。 类应该转换为简单数组或从简单数组转换,然後以这些简单数组或JSON字符串二擇一的格式存储。 编码和序列化必须由用户完成,而不是由例如BagOStuff或WANObjectCache接口完成。 (未来,MediaWiki可能会自动为实现JsonUnserializable的类执行此操作,这是在MediaWiki1.36中引入的)。
服务设施
这些是MediaWiki功能可用的抽象存储,请参见用途部分了解示例。
本地服务器
- 通过
MediaWikiServices->getLocalServerObjectCache()或MediaWikiServices->getObjectCacheFactory()->getLocalServerInstance( $fallback );存取。 - 可配置:否(自动检测)。
- 行为:非常快(<0.1ms,来自本地内存),低容量,不在应用程序服务器之间共享。
此存储中的值仅保存在任何给定的web服务器的本地RAM中(通常使用php-apcu)。 这些不会被复制到其他服务器或集群、并且没有更新或清除的协调选项。
如果web服务器没有安装php-apcu(或等效的),则该接口会返回到一个空的占位符,其中不會有键被存储。 它还被设置为维护脚本和其他命令行模式的空界面。 MediaWiki支持APCu和WinCache。 WinCache只被MediaWiki≤1.42支持。
本地集群
本地集群缓存通常是由記憶體快取(Memcached)支援,但也可能使用数据库。
- 通过
MediaWikiServices->getObjectCacheFactory()->getLocalClusterInstance()存取。 - 可配置:是,通过$wgMainCacheType。
- 行为:快速(~1ms,来自服务内存),中等容量,在应用程序服务器之间共享,但不跨数据中心复制。
廣域網路(WAN)缓存
- 通过
MediaWikiServices->getMainWANObjectCache()存取。 - 可配置:是,通过$wgWANObjectCache,默认为$wgMainCacheType。
- 行为:快速(~1ms,来自服务内存),中等容量,在应用程序服务器之间共享,失效事件跨数据中心复制
此存储中的值集中存储在当前数据中心(通常使用Memcached作为后端)。 虽然值不会被复制到其他集群,但密钥的“删除”和“清除”事件会被广播到其他数据中心,以使缓存失效。 请参见WANObjectCache类參考以了解如何使用它。
简而言之:通过getWithSet方法去计算和存储值。
要使缓存无效,请使用鍵清除(而不是直接设置某個鍵)。
另请参见wikitech.wikimedia.org上的WANObjectCache。
MicroStash
- 通过
MediaWikiServices->getMicroStash()存取。 - 可配置:是,通过$wgMicroStashType,默认为
CACHE_ANYTHING。 - 行为:快速(~1ms,来自服务内存),中等容量,在应用程序服务器之间共享,透過存活時間(TTL)實現失效處理。 儲存的資料僅會在存活時間(TTL)到期時被清除,無論該資料是否被使用。
此存储中的值集中存储在初級的数据中心(通常使用Memcached作为后端)。 值不会被复制到其他的数据中心,且数据僅在存活時間(TTL)屆滿時才會被清除。
MainStash
- 通过
MediaWikiServices->getMainObjectStash()存取。 - 可配置:是,通过$wgMainStash。
- 行为:可能涉及磁盘读取(1-10ms)、半持久性、在应用程序服务器之间共享以及跨数据中心复制。
此存储中的值在同一个数据中心中读取和写入,写入操作预计将复制到其他数据中心或从其他数据中心复制。 它通常使用 MySQL 作为后端。 (請參見wikitech:MariaDB#MainStash以了解維基媒體的配置。) 默认情况下,使用objectcache表。 它必须能容忍读取可能会过时,例如,由于缓存写入的短暫不可用、或重叠请求无序完成的竞争条件、或是來自其他資料中心的寫入需要一秒鐘才能完成複製。
此存储理應具有强大的持久性,通常用于无法重新生成且未存储在其他位置的数据。 但是,存储在MainStash中的数据必须是非关键的,如果丢失,对用户的影响最小,因此,如果在操作压力下,后端有时会部分不可用或被擦除,而不会造成事故。
使用
会话(Session)存储
- 透過
Session物件存取,該物件本身是透過SessionManager或RequestContext->getRequest()->getSession()存取的 - 透過
$wgSessionCacheType進行配置。
這並非真正的快取,因為資料並未儲存在其他位置。
跨维基缓存
請參閱跨维基缓存以了解更多訊息,另有ClearInterwikiCache.php。
解析器缓存
- 通过
ParserCache类存取。 - 後端由
$wgParserCacheType配置(通常為MySQL)。 - 鍵是以頁面ID為規範,並在解析頁面時填入。
- 修訂版本ID於檢索時進行驗證。
請參閱Manual:Parser cache以了解更多訊息 請另見Manual:PurgeParserCache.php。
消息缓存
- 通过
MessageCache存取。 - 後端可由$wgMessageCacheType配置(預設為$wgMainCacheType,其可回退至MySQL)。
修訂文本
- 通过
SqlBlobStore::getBlob存取。 - 儲存於廣域網路(WAN)快取中,使用鍵类
SqlBlobStore-blob。 - 鍵是可驗證的、值是不可變的。 快取會依需求進行填充。
背景
快取修訂版本文字的主要應用場景(相較於直接從text表或外部儲存裝置擷取),在於處理單次網頁請求需調用眾多不同頁面文字內容的情境。
- 最初於2006年實作(r16549, commit 376014e)。
- 2016年加入进程的快取(git #I77575d6, git #Ic61ee91)。
- 於2017年由MessageCache採用(git #Ib668e69)。
主要由以下對象使用:
- Parsing wikitext: 在解析指定維基頁面時,解析器不僅需要當前頁面的原始碼,還需遞迴取得所有嵌入模板頁面(以及Lua模組頁面)的原始碼。 一篇熱門的條目間接嵌入了超過300個此類頁面,此乃是司空見慣。 Memcached的使用可在儲存編輯的內容與渲染頁面的檢視時節省時間。
- MessageCache: 這是建立在LocalisationCache之上的維基專屬層級,主要是由特定維基上「MediaWiki:」命名空間頁面的訊息覆寫所組成。 在建立此二進位大型物件(Blob)時,需要擷取許多不同頁面的原始文字內容。 此資料在 Memcached 中以叢集為單位快取,然後在本地端以伺服器為單位快取(以降低 Memcached 頻寬消耗;參見 r11678, commit 6d82fa2)。
示例
鍵:WANCache:v:global:SqlBlobStore-blob:<wiki>:<content address>
「content address」指的是維基主資料庫中的「content.content_address」(例如「tt:1123」)。
這依次指的是text資料表或(外部儲存裝置)。
要逆向工程找出此內容所屬的頁面/修訂版本,請先針對內容位址(SELECT content_id FROM content WHERE content_address = "tt:963546992";)查找content.content_id,再找出該內容槽位的修訂版本ID(SELECT slot_revision_id FROM slots WHERE slot_content_id = 943285896;)。
修訂版本ID可直接用於維基站點的網址中,例如https://en.wikipedia.org/w/index.php?oldid=951705319,或你可在revision和page資料表中查詢它。
修訂元資料
- 通过
RevisionStore::getKnownCurrentRevision存取。 - 儲存於廣域網路(WAN)快取中,透過鍵类
revision-row-1.29的使用。 - 鍵是可驗證的(透過頁面和修訂版本ID)、值是不可變的。 快取會依需求進行填充。
訊息二進位大型物件(Blob)儲存體
儲存著由資源載入器模組所使用的介面文字。 它類似於 LocalisationCache,但包含維基專屬的覆寫設定。 (LocalisationCache 與維基平台無關)。 這些覆寫設定來自資料庫,以維基頁面形式存在於MediaWiki命名空間中。
- 通过
MessageBlobStore存取。 - 儲存於廣域網路(WAN)快取中,使用鍵类
MessageBlobStore。 - 鍵是可驗證的(透過資源載入器的模組名稱及訊息鍵的雜湊值)。 值是可變的,且會在一週後失效。 快取會依需求進行填充。
- 當重建LocalisationCache時,所有的鍵都會被清除。 當使用者在維基上儲存對 MediaWiki 命名空間頁面的變更時,鍵的某個子集合也會被清除。
壓縮快取
資源載入器會將原始JavaScript與CSS輸入檔案的壓縮版本儲存於快取中。
- 通过
ResourceLoader::filter存取。 - 儲存在伺服器本地端(APCu)。
- 鍵是可驗證的(具有確定性的值)。 無需採用清除策略。 快取會依需求進行填充。
LESS 編譯快取
資源載入器會將其編譯過的LESS檔案的元資料與解析器輸出結果進行快取。
- 通过
ResourceLoaderFileModule::compileLessFile存取。 - 儲存在伺服器本地端(APCu)。
檔案內容雜湊函數
資源載入器會將模組直接或間接使用的任何檔案之"核對和"進行快取。 當向用戶提供啟動清單時,需要數以千計個檔案的雜湊值。 為降低輸入/輸出開銷,系統會根據路徑與修改時間作為索引,將此內容雜湊值快取於本地端。
- 通过
FileContentsHasher存取。 - 儲存在伺服器本地端(APCu)。
参见
- Manual:Architectural modules/Cache
- Manual:性能调优 – 如何設定您的網頁伺服器和/或快取代理伺服器與MediaWiki,以提升效能。
- 手册:文件缓存 – 簡易快取機制,將HTTP回應快取至磁碟。
- 手冊:組態設定#快取:各種組態設定,用於建立快取後端並啟用應用程式各部分使用這些後端。
- 維基媒體 BagOStuff (物件快取), 提供此功能的函式庫