Performance

讓清漆在獲取新數據時從記憶體中發送舊數據?

  • July 30, 2013

我正在記憶體動態生成的頁面(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請求以禁止某些頁面。

總結一下,有兩種情況我遇到了不幸的使用者:

  1. 頁面的普通清漆 TTL 過期
  2. 後端使用者更改內容,這會向清漆發送清除請求

在這兩種情況下,我都有“不幸”的使用者。在第二種情況下,後端使用者通常會在頁面更改後檢查頁面,從而緩解了這種情況;但不一定。

儘管如此,對於第二種情況,我創建了一個解決方案(是的,我意識到這個問題始於為第一種情況尋求答案……我的問題表述不佳):

我沒有發送清除請求,而是使用 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 配置為每分鐘發出一次記憶體刷新請求。

引用自:https://serverfault.com/questions/517963