讓清漆在獲取新數據時從記憶體中發送舊數據?
我正在記憶體動態生成的頁面(PHP-FPM、NGINX)並在它們前面有清漆,這很好用。
但是,一旦達到記憶體超時,我會看到:
- 新客戶請求頁面
- varnish 辨識記憶體超時
- 客戶等待
- varnish 從後端獲取新頁面
- varnish 向客戶端提供新頁面(並且也記憶體了頁面,以供下一個立即獲取它的請求)
我想做的是:
- 客戶請求頁面
- varnish 辨識超時
- varnish 將舊頁面傳遞給客戶端
- varnish 從後端獲取新頁面並將其放入記憶體中
就我而言,過時資訊不是一個大問題的網站,尤其是當我們談論幾分鐘後的記憶體超時時。
但是,我不想懲罰使用者排隊等候,而是立即傳遞一些東西。這在某種程度上可能嗎?
為了說明,下面是對我的伺服器執行 siege 5 分鐘的範例輸出,該伺服器配置為記憶體一分鐘:
HTTP/1.1,200, 1.97, 12710,/,1,2013-06-24 00:21:06 ... HTTP/1.1,200, 1.88, 12710,/,1,2013-06-24 00:21:20 ... HTTP/1.1,200, 1.93, 12710,/,1,2013-06-24 00:22:08 ... HTTP/1.1,200, 1.89, 12710,/,1,2013-06-24 00:22:22 ... HTTP/1.1,200, 1.94, 12710,/,1,2013-06-24 00:23:10 ... HTTP/1.1,200, 1.91, 12709,/,1,2013-06-24 00:23:23 ... HTTP/1.1,200, 1.93, 12710,/,1,2013-06-24 00:24:12 ...
我忽略了數百個正在執行的請求
0.02
。但我仍然擔心會有使用者不得不等待將近 2 秒才能獲得原始 HTML。我們不能在這裡做得更好嗎?
(我遇到了Varnish send while cache,聽起來很相似,但不完全是我想要做的。)
解決方案
Shane Madden 的回答包含了解決方案,但我沒有立即意識到。還有一個細節我沒有包含在我的問題中,因為我認為它不相關,但實際上它是。
我目前使用的 CMS 解決方案有一個 varnish 數據庫偵聽器,因此能夠通知 varnish 禁止內容已更改的頁面。它使用一些正則表達式發送
PURGE
請求以禁止某些頁面。總結一下,有兩種情況我遇到了不幸的使用者:
- 頁面的普通清漆 TTL 過期
- 後端使用者更改內容,這會向清漆發送清除請求
在這兩種情況下,我都有“不幸”的使用者。在第二種情況下,後端使用者通常會在頁面更改後檢查頁面,從而緩解了這種情況;但不一定。
儘管如此,對於第二種情況,我創建了一個解決方案(是的,我意識到這個問題始於為第一種情況尋求答案……我的問題表述不佳):
我沒有發送清除請求,而是使用 Shanes 建議並調整了 VCL,以便我的 varnish 數據庫偵聽器可以發送特殊請求來獲取
hash_always_miss
設置為的頁面true
。在目前架構下,我並沒有真正做一個真正的非同步請求的奢侈,但是在我如何在 PHP 中發出非同步 GET 請求的幫助下?我能夠製作一個 GET 請求來清漆,它不會等待頁面載入,但足以觸發清漆從後端獲取頁面並記憶體它。
最終結果是數據庫偵聽器將請求發送到清漆,當我輪詢特定頁面時,它從來沒有讓我的請求“不走運”,但一旦清漆從後端完全獲取頁面(這可能從 300 毫秒到 2 秒)它突然出現了。
我還必須找到一個解決方案如何在正常 TTL 用完時避免同樣的問題,但我想這個解決方案也完全像 Shane 建議的那樣:使用 wget 觸發
hash_always_miss
,我只需要足夠聰明就可以獲取列表我必須刷新的頁面。
我用來解決此問題的解決方案是確保頁面上的 TTL 在刷新之前永遠不會過期 - 強制在我的一個系統上執行的 HTTP 客戶端獲得緩慢的負載,而不是不幸的客戶端要求。
就我而言,這涉及
wget
到一個 cron,發送一個特殊的標頭來標記請求並req.hash_always_miss
基於此進行設置,強制將內容的新副本提取到記憶體中。acl purge { "localhost"; } sub vcl_recv { /* other config here */ if (req.http.X-Varnish-Nuke == "1" && client.ip ~ purge) { set req.hash_always_miss = true; } /* ... */ }
對於您的內容,這可能意味著將 Varnish TTL 設置為 5 分鐘左右,但將 cron 的 wget 配置為每分鐘發出一次記憶體刷新請求。