第3章 — 進階快取主題
「電腦科學中只有兩個硬性專案:快取失效和命名專案。」
— 菲爾·卡爾頓
概觀
這是AEM快取的三部分之系列的第3部分。 前兩個部分的重點在於Dispatcher中的普通http快取,以及限制有哪些。 本節探討如何克服這些限制的一些想法。
一般快取
此系列的第1章和第第2章主要著重於Dispatcher。 我們已說明基本知識、限制以及您需要進行某些取捨的位置。
快取複雜性和複雜性並非Dispatcher特有的問題。 一般而言,快取相當困難。
將Dispatcher作為工具箱中唯一工具實際上是一種限制。
在本章中,我們想要進一步擴大快取檢視的範圍,並提出一些如何克服Dispatcher某些缺點的想法。 沒有靈丹妙藥 — 您必須在專案中進行權衡。 請記住,快取和失效準確性永遠伴隨著複雜性,複雜性也伴隨著錯誤的可能性。
您需要在這些領域進行取捨,
- 效能和延遲
- 資源消耗/CPU負載/磁碟使用量
- 準確性/貨幣/過時/安全性
- 簡易性/複雜性/成本/可維護性/錯誤傾向
這些維度在一個相當複雜的系統中相互連結。 沒有簡單的if-this-then-that。 讓系統更簡單可讓速度更快或更慢。 它可以降低您的開發成本,但會增加服務檯的成本,例如,如果客戶看到過時內容或抱怨網站速度緩慢,就會增加成本。 所有這些因素都需要相互考量和平衡。 但現在您應該已經有了好主意,沒有萬靈丹妙藥,也沒有單一的「最佳實務」 — 只有許多不良實務,以及少數好實務。
鏈結快取
概觀
資料流程
從伺服器傳送頁面至使用者端的瀏覽器,可跨越許多系統和子系統。 若您仔細檢視,有許多躍點資料需要從來源移至漏出,每個躍點資料都可能是快取的候選專案。
典型CMS應用程式的資料流程
讓我們從硬碟上需要顯示在瀏覽器中的資料片段開始歷程。
硬體與作業系統
首先,硬碟機(HDD)本身在硬體中有一些內建快取記憶體。 第二,裝載硬碟的作業系統使用可用的記憶體來快取經常存取的區塊,以加快存取速度。
內容儲存庫
下一個層級是CRX或Oak - AEM使用的檔案資料庫。 CRX和Oak將資料分割成可快取到記憶體中的區段,以避免存取硬碟的速度變慢。
第三方資料
大多數大型的Web安裝也有第三方資料;資料來自產品資訊系統、客戶關係管理系統、舊版資料庫或任何其他任意Web服務。 我們不需要在需要這些資料時隨時從來源提取這些資料,尤其是在我們已知這些資料的變更頻率不太高時。 因此,如果它未在CRX資料庫中同步,則可快取。
業務層 — 應用程式/模型
通常您的範本指令碼不會透過JCR API轉譯來自CRX的原始內容。 最有可能的情況是,您之間有業務層,可合併、計算及/或轉換業務領域物件中的資料。 猜猜看,如果這些操作很昂貴,您應該考慮快取它們。
標籤片段
模型現在是呈現元件標示的基礎。 為什麼不同時快取演算後的模型?
Dispatcher、CDN和其他代理人
關閉會將轉譯的HTML頁面前往Dispatcher。 我們已討論,Dispatcher的主要用途是快取HTML頁面和其他網路資源(儘管其名稱)。 在資源到達瀏覽器之前,它可能會傳遞反向Proxy (可以快取)和CDN (也用於快取)。 使用者端可能位於辦公室中,僅透過Proxy授與Web存取權,該Proxy也可能決定快取並儲存流量。
瀏覽器快取
最後但並非最不重要的一點是,瀏覽器也會快取。 這是一項容易被忽略的資產。 但這是您在快取鏈結中最接近且最快的快取。 很遺憾,使用者之間不共用,但一位使用者的不同請求之間仍會共用。
快取的位置及原因
這是一長串潛在快取記憶體。 我們都遇到過問題,看到過時的內容。 但是考慮到這個階段有很多,它大部分時間都運作起來是個奇蹟。
但快取在鏈條的哪個角落有意義? 在開頭? 在結尾? 到處都是? 這取決於……而且取決於許多因素。 即使是相同網站中的兩個資源,也可能希望以不同的方式回答此問題。
讓您大致瞭解可能考量的因素,
存留時間 — 如果物件的固有存留時間較短(流量資料的存留時間可能比天氣資料短),則可能不值得快取。
生產成本 — 物件的重新生產與傳遞是多麼昂貴(就CPU週期和I/O而言)。 如果是便宜的快取,可能就不需要了。
大小 — 大型物件需要快取更多資源。 這可能是限制因素,必須與其收益相平衡。
存取頻率 — 如果物件很少被存取,則快取可能無效。 在第二次從快取存取之前,它們只會過時或失效。 這類專案只會封鎖記憶體資源。
共用存取 — 一個以上實體使用的資料應該快取到鏈結的上方。 實際上,快取鏈不是鏈,而是樹。 一個以上模型可能會使用存放庫中的一個資料。 這些模型接著便可由多個轉譯器指令碼用來產生HTML片段。 這些片段包含在多個頁面中,這些頁面透過瀏覽器的私人快取分配給多個使用者。 因此,「共用」並不表示只在不同人之間共用,而是在不同軟體之間共用。 如果您想要尋找潛在的「共用」快取,只要將樹追溯到根並尋找共同祖項 — 也就是您應該快取的位置。
地理空間分佈 — 如果您的使用者分散在世界各地,使用分散式快取網路可能有助於減少延遲。
網路頻寬和延遲 — 說到延遲,您的客戶是誰,他們使用哪種網路? 或許您的客戶是使用3G連線的舊版智慧型手機的缺發達國家行動客戶? 請考慮建立較小的物件,並在瀏覽器快取中快取它們。
這份清單目前尚不完整,但我們認為您現在已經有了想法。
鏈結快取的基本規則
再說一次 — 快取是硬的。 讓我們分享我們從先前專案擷取的一些基本規則,這些規則可協助您避免專案中的問題。
避免雙重快取
上一章介紹的每個層都會提供快取鏈結中的某些值。 藉由節省運算週期或讓資料更貼近消費者。 在鏈結的多個階段快取資料片段並沒有錯,但您應該一律考慮下一個階段的好處與成本。 在Publish系統中快取完整頁面通常沒有任何好處,因為這項操作在Dispatcher中已經完成。
混合失效策略
有三種基本失效策略:
- TTL,存留時間: 物件會在固定時間後到期(例如「從現在起的2小時」)
- 到期日: 物件會在未來的指定時間到期(例如「2019年6月10日下午5:00」)
- 以事件為基礎: 物件因平台中發生的事件而明確失效(例如,當頁面變更並啟動時)
現在您可以對不同快取層使用不同策略,但有一些「有毒」策略。
事件型失效
純事件型失效:從內部快取到外層失效
純事件型失效是最容易理解、在理論上最容易正確且最準確的失效方式。
簡而言之,物件變更後,快取會逐一失效。
您只需要記住一個規則:
永遠從內部到外部快取失效。 如果您先讓外部快取失效,它可能會從內部快取重新快取過時的內容。 不要在快取重新整理的時間做任何假設 — 請確定。 最好在 使內部快取失效之後,觸發外部快取失效。
這就是理論。 但實際上有許多疑問。 事件必須分發 — 可能透過網路分發。 在實務中,這會使其成為最難實施的失效方案。
自動 — 修復
若使用事件型失效,您應該有應急計畫。 如果遺漏失效事件,該怎麼辦? 簡單的策略可能是在一段時間後讓無效或清除。 因此,您可能已錯過該活動,現在提供過時的內容。 但您的物件也只有數小時(天)的隱含TTL。 所以最終系統會自動自我修復。
純TTL型失效
未同步的TTL型失效
這個也是相當常見的配置。 您可以棧疊數個快取圖層,每個圖層都有權在特定時間內提供物件。
實作容易。 不幸的是,很難預測資料片段的有效壽命。
外部快取會延長內部物件的壽命
請考量上圖。 每個快取層都會引入2分鐘的TTL。 現在 — 整體TTL也必須2分鐘,對嗎? 不盡然。 如果外層在物件過期之前擷取物件,則外層實際上會延長物件的有效存留時間。 在這種情況下,有效上線時間可介於2到4分鐘之間。 假設您同意業務部門的意見,一天是可以容忍的 — 而且您有四個快取階層。 每個圖層上的實際TTL不可超過六小時……增加快取遺漏率……
我們並不是說這是個糟糕的配置。 您應該知道它的限制。 而且這是一個簡單好用的開始策略。 只有在網站的流量增加時,您才會考慮更精確的策略。
設定特定日期,以同步處理失效時間
以到期日為基準的失效
如果您在內部物件上設定特定日期,並將此日期傳播至外部快取,即可獲得更可預測的有效期限。
正在同步處理到期日期
不過,並非所有快取都能傳播日期。 而且,當外部快取彙總了兩個具有不同到期日的內部物件時,可能會變得非常糟糕。
混合事件型和TTL型失效
混合事件型與TTL型策略
此外,AEM世界中的常見配置是在內部快取(例如記憶體中的快取,其事件可以近乎即時地處理)中使用事件型失效,而在外部則使用TTL型快取,因此您可能沒有明確失效的存取權。
在AEM世界中,當基礎資源變更時,您在Publish系統中將有用於商業物件和HTML片段的記憶體內快取,並且您將此變更事件傳播到也可使用基於事件的排程程式,這會失效。 例如,您之前會有TTL型CDN。
在Dispatcher前面有一層(短)TTL型快取,能夠有效地軟化自動失效後通常會出現的尖峰。
混合TTL — 和事件型失效
有毒:混合TTL — 和事件型失效
這種組合是有毒的。 切勿在TTL或到期型快取之後放置和事件型快取。 還記得我們在「純TTL」策略中所具有的溢位效應嗎? 在這裡可以觀察到相同的效果。 只有已發生的外部快取失效事件才不會再次發生。如此一來,您快取物件的生命週期就會無限延長。
TTL型和事件型合併:溢位至無限
部分快取和記憶體內部快取
您可以掛接至演算程式的階段,以新增快取圖層。 從取得遠端資料傳輸物件或建立本機企業物件,到快取單一元件的演算標籤。 我們將在稍後的教學課程中討論具體實施。 但或許您打算自己已經實作這些快取階層中的幾個。 因此,我們在這裡至少可以介紹基本原則,以及格鬥原則。
警告字詞
遵循存取控制
這裡說明的技術非常強大,每個AEM開發人員的工具箱中都有 必須有。 但別太興奮,明智地使用它們。 將物件儲存在快取中,並在後續請求中分享給其他使用者,實際上意味著規避存取控制。 這通常不是公開網站上的問題,但在使用者需要登入才能存取的情況下,可能會發生問題。
假設您將網站主功能表的HTML標籤儲存在記憶體中的快取中,以便在不同頁面之間共用。 實際上,這是儲存部分轉譯HTML的完美範例,因為建立導覽通常很昂貴,因為需要遍歷許多頁面。
您並非在所有頁面之間共用相同的功能表結構,而是要與所有使用者共用,使其更有效率。 不過,請稍候……但功能表中可能有些專案僅供特定使用者群組使用。 在這種情況下,快取可能會變得較為複雜。
僅快取自訂商務物件
如果有的話 — 這是最重要的建議,我們可以提供您:
這是什麼意思?
-
您不知道其他人物件的預期即時週期。 假設您取得請求物件的參考,並決定快取該參考。 現在,請求已結束,並且servlet容器想要將該物件循環用於下一個傳入請求。 在這種情況下,其他人會變更您認為擁有獨家控制的內容。 請勿將此忽略 — 我們曾在專案中看到過類似的情況。 客戶看到其他客戶資料,而不是他們自己的資料。
-
只要物件被其他參照鏈所參照,就無法從棧積中移除它。 如果您在快取中保留參考的所謂小型物件,假設影像以4MB呈現,您很有可能遇到記憶體洩漏的問題。 快取應該以弱參照為基礎。 但 — 弱參考無法如預期運作。 這是產生記憶體洩漏並結束記憶體不足錯誤的最佳方法。 而且 — 您不知道外部物件的保留記憶體大小是多少,對吧?
-
特別是在Sling中,您可以互相調整(幾乎)每個物件。 假設您將資源放入快取中。 下一個請求(具有不同的存取許可權)會擷取該資源,並將其調整為resourceResolver或工作階段以存取他無法存取的其他資源。
-
即使您從AEM在資源周圍建立精簡「包裝函式」,也不得快取該專案,即使它是您自己的且不可變動。 包裝的物件將成為參考(我們之前禁止使用),如果我們看起來很銳利,基本上會產生與最後一個專案所述相同的問題。
-
如果您想要快取,請將原始資料複製到您自己的快取物件中,以建立您自己的物件。 您可能想要透過參照來連結您自己的物件之間 — 例如,您可能想要快取物件的樹狀結構。 沒關係 — 但只有您剛在相同請求中建立的快取物件 — 而且沒有從其他位置請求的物件(即使是「您的」物件的名稱空間)。 複製物件 是索引鍵。 同時請務必一次清除連結物件的整個結構,並避免對結構的傳入和傳出參照。
-
是 — 並且讓您的物件不可變動。 私有屬性,僅限且無設定器。
這是許多規則,但值得遵循。 即使您經驗豐富、超級聰明,並且一切都在掌控之中。 您專案中的年輕同事剛從大學畢業。 他不知道這些陷阱。 如果沒有陷阱,就無可避免。 保持簡單明瞭。
工具和程式庫
此系列旨在瞭解概念,並讓您能夠構建最適合您使用案例的架構。
我們並未特別推廣任何工具。 但是會提供如何評估它們的提示。 例如,AEM有一個簡單的內建快取,自6.0版以來具有固定的TTL。您是否要使用它? 可能不在事件型快取跟隨在鏈結中的發佈上(提示: Dispatcher)。 但對於作者來說,這或許是個不錯的選擇。 此外,AdobeACS Commons的HTTP快取可能也值得考慮。
或者,您也可以根據成熟的快取架構(例如Ehcache)建置您自己的架構。 這可用來快取Java物件和演算標籤(String
個物件)。
在某些簡單情況下,您也可以使用同時雜湊對應,在這裡,您很快就會看到工具或技能的限制。 和命名和快取一樣難以掌握並行性。
參考
基本術語
我們不會在此深入討論快取理論,但覺得必須提供幾個流行語,以便您有一個良好的開端。
快取搬出
我們經常談到失效和清除。 快取撤出 與下列詞語有關:撤出專案後,將無法再使用。 但是逐出不會發生在專案過期時,而是當快取已滿時。 較新或「較重要」的專案會將較舊或較不重要的專案推出快取。 您必須犧牲哪些專案,取決於個案決定。 您可能會想要逐出最舊的,或是很少使用或最後存取時間很長的專案。
先佔式快取
先佔式快取表示在專案失效或被視為過期時,以新的內容重新建立專案。 當然 — 您只需使用少數資源,確保可以經常且立即存取。 否則,您會在建立可能永遠不會被請求的快取專案時浪費資源。 透過先發制人地建立快取專案,您可以減少快取失效後對資源的第一個要求的延遲。
快取預熱
快取預熱與先佔式快取密切相關。 不過您不會將該辭彙用於即時系統。 而且時間限制也比前一個少。 您不會在失效後立即重新快取,而是在時間允許時逐漸填入快取。
例如,您從負載平衡器取出Publish / Dispatcher程式碼加以更新。 在重新整合之前,您會自動對最常存取的頁面進行編目,以便將其重新放入快取。 當快取為「溫暖」(填滿)時,您將腿部重新整合到負載平衡器中。
或者,您可以一次重新整合該條腿,但是您將流量限制在該條腿上,這樣它就有機會根據正常使用來暖化其快取。
或者,您也可以在系統閒置時,快取某些不常存取的頁面,以減少實際請求存取這些頁面時的延遲。
快取物件身分、承載、失效相依性和TTL
一般而言,快取物件或「專案」有五個主要屬性,
索引鍵
此身分是您用來識別和物件的屬性。 擷取其裝載或從快取中將其清除。 例如,Dispatcher使用頁面的URL作為索引鍵。 請注意,Dispatcher不會使用頁面路徑。 這不足以區分不同的呈現。 其他快取可能使用不同的索引鍵。 我們稍後會看到一些範例。
值/裝載
這是物件的寶庫,也就是您要擷取的資料。 如果是Dispatcher,則為檔案內容。 但它也可以是Java物件樹。
TTL
我們已經涵蓋TTL。 在此時間後,系統會將專案視為過時,且不應再傳送專案。
相依性
這與事件型失效相關。 物件會根據哪些原始資料? 我們已經說過,在第一部分中,真實且精確的相依性追蹤太複雜。 但根據我們對系統的瞭解,您可以使用更簡單的模型來近似相依性。 我們讓足夠多的物件失效,足以清除過時的內容……而且可能無意中超過必要的數量。 然而,我們仍會儘量避免使用「清除所有內容」這種字眼。
哪些物件取決於每個單一應用程式中其他物件的真偽。 我們稍後會提供幾個範例,說明如何實作相依性策略。
HTML片段快取
在不同頁面上重複使用轉譯的片段
HTML片段快取是一個強大的工具。 其想法是快取由記憶體內部快取中的元件產生的HTML標籤。 您可能會問,為什麼我應該那麼做? 反正我在Dispatcher中快取整個頁面的標籤 — 包括該元件的標籤。 我們同意。 您可以 — 但每頁一次。 您未在頁面之間共用該標籤。
想像一下,您正在每個頁面上方轉譯導覽。 每個頁面上的標籤看起來都一樣。 但是您會針對每個頁面重複轉譯,這不在Dispatcher中。 並記住:自動失效後,所有頁面都需要重新呈現。 基本上,您執行相同的程式碼會產生數百次相同的結果。
根據我們的經驗,演算巢狀頂端導覽是一項非常昂貴的工作。 通常您會遍歷檔案樹狀結構的好部份來產生瀏覽專案。 即使您只需要導覽標題和URL — 頁面必須載入記憶體。 而在這裡,它們正在阻塞寶貴的資源。 一遍又一遍。
但元件會在許多頁面之間共用。 而共用某物件即表示使用快取。 因此 — 您要做的就是檢查導覽元件是否已轉譯及快取,而不要重新轉譯只發出快取值。
這個方案有兩個很棒的細節,很容易錯過:
-
您正在快取Java字串。 String沒有任何外寄參考,且不可變動。 因此,考慮到上述警告,這是超級安全的。
-
此外,失效也是超級簡單的操作。 無論何時發生網站變更,您都想要讓此快取專案失效。 重建相對便宜,因為它只需要執行一次,然後會被數百頁重複使用。
這讓您的Publish伺服器鬆了一口氣。
片段快取實作
自訂標籤
過去,當您使用JSP作為範本引擎時,經常使用自訂JSP標籤來包住元件轉譯程式碼。
<!-- Pseudo Code -->
<myapp:cache
key=' ${info.homePagePath} + ${component.path}'
cache='main-navigation'
dependency='${info.homePagePath}'>
… original components code ..
</myapp:cache>
比會擷取其內文並將其寫入快取或阻止執行其內文並輸出快取專案的裝載的自訂標籤。
「索引鍵」是其在首頁上的元件路徑。 我們不使用目前頁面上的元件路徑,因為這麼做會在每頁建立一個快取專案,與我們共用該元件的意圖相衝突。 我們也不只是使用元件相對路徑(jcr:conten/mainnavigation
),因為這會防止我們在不同的網站中使用不同的導覽元件。
「快取」是儲存專案的指示器。 您通常有多個快取,可將專案儲存至其中。 其中每個專案的行為可能會有點不同。 因此,最好能區分儲存的內容,即使最終只是字串。
「相依性」是快取專案相依的專案。 「主要導覽」快取可能有規則,如果節點「相依性」底下有任何變更,則必須清除相應的專案。 因此,您的快取實作需要將其本身註冊為存放庫中的事件偵聽程式,以瞭解變更,然後套用快取特定規則以找出需要失效的內容。
以上只是範例。 您也可以選擇擁有快取樹狀結構。 其中第一層用來分隔網站(或租使用者),第二層則分成不同的內容型別(例如「主要導覽」),讓您能夠省去新增首頁路徑的麻煩,如上例所示。
順便一提,您也可以將此方法用於更現代化的HTL型元件。 接著,您的HTL指令碼周圍會有一個JSP包裝函式。
元件篩選器
但在純HTL方法中,您寧可使用Sling元件篩選器建置片段快取。 我們尚未看到這點,但我們將針對此問題採取此方法。
Sling動態包含
如果您在不斷變化的環境(不同頁面)的情境下有一些常數(導覽),則會使用片段快取。
但您也可能有相反的情況,相對固定的內容(很少變更的頁面)和該頁面上的某些不斷變化的片段(例如,即時捲軸)。
在此情況下,您可能會給Sling Dynamic Include一個機會。 本質上,這是元件篩選器,它會包裝動態元件,而不是將元件轉譯成它建立參照的頁面。 此參考可為Ajax呼叫,好讓瀏覽器包含元件,並靜態快取周圍的頁面。 或者,也可以使用Sling動態包含來產生SSI指令(伺服器端包含)。 此指示詞會在Apache伺服器中執行。 如果您運用Varnish或支援ESI指令碼的CDN,您甚至可以使用ESI - Edge Side Include指令。
使用Sling Dynamic Include的請求的
使用Sling Dynamic Include的請求的 序列圖表
SDI檔案指出您應停用結尾為"*.nocache.html"之URL的快取,因為當您處理動態元件時,這是合理的。
您可能會看到另一個如何使用SDI的選項:如果您 不 停用包含的Dispatcher快取,Dispatcher的動作會像片段快取一樣,類似於我們在上一章中所述的片段:頁面和元件片段會平等且獨立地快取在Dispatcher中,並在請求頁面時由Apache伺服器中的SSI指令碼拼接在一起。 如此一來,您就可以實作共用元件,例如主要導覽(因為您一律使用相同的元件URL)。
理論上應該有效。 但是……
我們建議您不要這麼做:您將失去為真實動態元件略過快取的能力。 SDI已全域設定,您對「por-mans-fragment-cache」所做的變更也會套用至動態元件。
建議您仔細研究SDI檔案。 還有其他幾項限制,但SDI在某些情況下是很有價值的工具。
參考
模型快取
以模型為基礎的快取:一個商業物件,具有兩個不同的轉譯
讓我們再次透過導覽重新造訪案例。 我們假設每個頁面都需要相同的導覽標籤。
但或許情況並非如此。 您可能想要呈現代表 目前頁面 之導覽中專案的不同標示。
Travel Destinations
<ul class="maninnav">
<li class="currentPage">Travel Destinations
<ul>
<li>Finland
<li>Canada
<li>Norway
</ul>
<li>News
<li>About us
<ul>
News
<ul class="maninnav">
<li>Travel Destinations
<li class="currentPage">News
<ul>
<li>Winter is coming>
<li>Calm down in the wild
</ul>
<li>About us
<is
以下是兩種完全不同的呈現。 然而,企業物件 (完整的導覽樹狀結構)是相同的。 此處的 企業物件 會是代表樹狀結構中節點的物件圖表。 此圖表可輕鬆儲存在記憶體中的快取記憶體中。 不過請記住,此圖表不得包含任何物件,或參考您未自行建立的任何物件,尤其是現在的JCR節點。
在瀏覽器中快取
我們之前已談到瀏覽器中快取的重要性,並且推出許多不錯的教學課程。 最後,對於瀏覽器,Dispatcher只是一個遵循HTTP通訊協定的網頁伺服器。
然而,儘管有上述理論,我們還是收集了一些知識,這些知識是我們獨一無二的,而且我們想要分享。
本質上,瀏覽器快取可以透過兩種不同的方式運用,
-
瀏覽器已快取其知道確切到期日的資源。 在這種情況下,不會再請求資源。
-
瀏覽器有資源,但不確定它是否仍然有效。 在這種情況下,它會詢問網頁伺服器(在此案例中為Dispatcher)。 如果資源在您上次傳遞後已修改,請將其提供。 如果未變更,則伺服器會回答「304 — 未變更」,並且只傳輸中繼資料。
偵錯
如果您正在最佳化Dispatcher的瀏覽器快取設定,在瀏覽器與網頁伺服器之間使用案頭Proxy伺服器將非常有用。 我們偏好使用Karl von Randow的「Charles Web Debugging Proxy」。
您可以使用Charles讀取傳送到伺服器或從伺服器傳輸的要求和回應。 此外,您還可以深入瞭解HTTP通訊協定。 現代瀏覽器也提供一些偵錯功能,但案頭Proxy的功能是前所未有的。 您可以操控傳輸的資料、限制傳輸、重播單一請求等等。 而且使用者介面配置清晰且相當全面。
最基本的測試是以一般使用者的身分使用網站(Proxy介於兩者之間),並在靜態要求(至/etc/…)的數量隨著時間推移而減少時簽入Proxy — 因為這些要求應該在快取中,而不再要求。
我們發現,Proxy可提供更清楚的概述,因為快取的要求未出現在記錄中,而某些瀏覽器內建的偵錯工具仍會以「0毫秒」或「從磁碟」顯示這些要求。 這很正常且準確,但可能會使您的檢視變得有點模糊。
然後,您可以向下展開並檢查已傳輸檔案的標頭,以檢視「Expires」http標頭是否正確。 您可以使用if-modified-since標頭來重播請求,以檢視伺服器是否正確回應304或200回應代碼。 您可以觀察非同步呼叫的時間,也可以在某種程度上測試您的安全性假設。 請記住,我們告訴您不要接受所有非明確預期的選取器? 您可以在這裡使用URL和引數來玩,看看您的應用程式是否運作良好。
當您對快取進行偵錯時,我們只會要求您不要做一件事:
請勿在瀏覽器中重新載入頁面!
「瀏覽器重新載入」、簡單重新載入 以及 強制重新載入 ("shift — 重新載入")與一般頁面要求不同。 簡單的重新載入要求會設定標頭
Cache-Control: max-age=0
按住Shift鍵(同時按住Shift鍵並按一下重新載入按鈕)通常會設定請求標題
Cache-Control: no-cache
兩個標題的效果相似但稍微不同,但最重要的是,當您從URL位置開啟URL或使用網站上的連結時,它們與一般請求完全不同。 一般瀏覽不會設定Cache-Control標頭,但可能會設定if-modified-since標頭。
因此,如果您想要偵錯正常的瀏覽行為,您應該完全這麼做: 正常瀏覽。 使用瀏覽器的重新載入按鈕是避免在設定中看到快取設定錯誤的最佳方式。
使用您的Charles Proxy來檢視我們正在討論的內容。 可以 — 而且當您開啟它時,您可以在此重新執行請求。 不需從瀏覽器重新載入。
效能測試
透過使用Proxy,您可以瞭解頁面的時間行為。 當然,這遠不是效能測試。 效能測試需要多個使用者端同時請求您的頁面。
一個常見的錯誤,我們經常看到,效能測試僅包括極少數的頁面,而且這些頁面僅從Dispatcher快取傳送。
如果您將應用程式提升至即時系統,則載入將與您測試過的完全不同。
在即時系統上,存取模式並非是您在測試中有為數不多且平均分佈的頁面(首頁和少數內容頁面)。 頁數較多且請求分佈非常不均勻。 當然,快取記憶體無法提供即時頁面100%的服務:來自Publish系統的失效請求會使您大部分的寶貴資源自動失效。
是的,重建您的Dispatcher快取時,您會發現Publish系統的行為也完全不同,這取決於您請求的是少數頁面還是較大數字。 即使所有頁面都同樣複雜,它們的數量也會發揮作用。 還記得我們說過關於鏈式快取的話嗎? 如果您一律要求相同數量的頁面,則硬碟快取記憶體中的原始資料區塊或作業系統快取這些區塊的可能性相當高。 此外,存放庫也很可能已快取其主記憶體中的對應區段。 因此,重新呈現的速度會顯著快於其他頁面偶爾從不同快取中逐出時的速度。
快取和測試依賴快取的系統一樣困難。 那麼,如何才能擁有更精確的真實情境?
我們認為您必須進行多項測試,而且您必須提供多項績效指數,以衡量解決方案的品質。
如果您已有網站,請測量要求數量及其分配方式。 嘗試模型化使用類似請求分佈的測試。 加入一些隨機性不會造成傷害。 您不必模擬會載入JS和CSS等靜態資源的瀏覽器,這些其實並不重要。 最後會在瀏覽器或Dispatcher中快取這些值,且這些值的加總不會大幅增加負載。 但是參照的影像很重要。 找出它們在舊記錄檔中的分佈,並建立類似請求模式的模型。
現在使用Dispatcher執行測試,且完全不快取。 這是您最壞的情況。 瞭解在此最惡劣的狀況下,您的系統會在哪一個尖峰負載變得不穩定。 如果您想要的話,也可以選擇選擇走幾條Dispatcher/Publish腿來雪上加霜。
接著,執行相同的測試,將所有必要的快取設定設為「開啟」。 慢慢增加平行請求,讓快取變熱,看看在這類最佳情況下,您的系統可以接受多少。
一般而言,執行測試時,除了會啟用Dispatcher之外,也會發生一些無效狀況。 您可以透過Cronjob接觸statfiles或不定時將失效請求傳送到Dispatcher來模擬這種情況。 別忘了偶爾也會清除一些非自動失效的資源。
您可以透過增加失效請求和增加負載來改變最後一種情況。
這比線性負載測試更複雜,但解決方案的可信度更高。
您可能避免費力。 但您至少應針對大量頁面(平均分佈)的Publish系統進行最壞情況的測試,以檢視系統的限制。 請確定您正確解讀最佳案例的數量,並為您的系統提供足夠的空間。