問題描述

我們假設有一個插件,顯示 20 個相關的帖子 (每個帖子) 與一個非常複雜的查詢。然後使用此查詢中的數據,它構建複雜的 HTML 佈局。另外,應該注意的是,該插件是公共的,可以安裝在任何配置的任何服務器上。

就像是:

/* complex and large query */
$related_posts = get_posts( ... );

$html_output = '';
foreach($related_posts as $key => $item) {
     /* complex layout rendering logic (but not as slow as the previous query) */
     $html_output .= ...;
}

所以我的問題是:

  • 緩存這些數據最安全和最正確的方法是什麼?

  • 應該使用 Transient API 緩存 $related_posts 數組,還是 $html_output 字符串?如果我會緩存 $html_ouput 字符串,它會達到一些 max-size 限制嗎?我應該可以 gzip 它,然後保存?

  • 我應該在這裏使用 Transient API 嗎?

最佳解決方案

Should I use Transient API at all here?

沒有。

在一個庫存 WordPress 安裝瞬態存儲在 wp_options 表中,只有在核心升級期間才被清理。假設你有 50,000 個帖子,在選項表中有 5 萬個附加行。顯然,它們設置為 autoload = no,所以它不會消​​耗你所有的 memory ,但還有一個警告。

選項表中的自動加載字段沒有索引,這意味着對 wp_load_alloptions()的調用將執行全表掃描。你擁有的行越多,需要的時間越長。寫入選項表的次數越多,MySQL 內部緩存效率越低。

如果緩存的數據與帖子直接相關,那麼最好將其存儲在後期元數據中。這也將在您每次顯示緩存的內容時保存一個查詢,因為在 WP_Query 中的後檢索期間,通常會發送緩存 (通常) 。

您的數據結構的元值可能會有所不同,如果緩存的值過時,那麼您可以擁有時間戳並執行昂貴的查詢,就像一個暫時的行為一樣。

另一個重要的想法是記住,WordPress 瞬態可以在具有持久性對象緩存的環境中變化。這意味着如果您將緩存的數據存儲在短暫的 24 小時內,絕對不保證它將在 23 小時或 12 個甚至 5 分鐘內可用。許多安裝的對象緩存後端是 in-memory key-value 存儲,如 Redis 或 Memcached,如果沒有足夠的分配內存來適應較新的對象,較舊的項目將被逐出。這是元存儲方法的巨大勝利。

無效也可以更聰明,即為什麼在 X 小時內無效相關的帖子緩存?是因為有些內容有所改變嗎?添加了一個新帖子?已分配一個新標籤?根據您的 「複雜和大查詢」,您可以選擇僅在發生改變查詢結果的事情時才使其無效。

Should I use Transient API to cache $related_posts array, or $html_output string? If I’ll cache $html_ouput string, will it reach some max-size limit? Should I maybe gzip it, before saving?

這取決於您的字符串的大小,因為這將是 PHP,MySQL 等之間的數據。您需要努力達到 MySQL 的限制,但例如 Memcached 默認的 per-object 限制只有 1 MB 。

您的 「複雜佈局渲染邏輯」 實際需要多長時間?通過分析器運行它來查找。有可能是非常快速的將永遠不會成為瓶頸。

如果是這樣,我建議緩存帖子 ID 。不是 WP_Post 對象,因為那些將包含完整的帖子內容,而只是一個數組的帖子 ID 。然後只需使用 WP_Querypost__in,這將導致通過主鍵快速的 MySQL 查詢。

也就是説,如果每個項目所需的數據相當簡單,那麼您可以只存儲這三個數據,而不需要額外的 round-trip 到 MySQL 的開銷,並且沒有緩存非常長的 HTML 字符串的開銷。

哇這是很多話,希望有所幫助。

次佳解決方案

不是所有的 WP 代碼都是公共代碼

如果你要發佈公開的東西,那麼 kovshenin 所説的一切都是完全有效的。

如果您要為自己或您的公司編寫私人密碼,情況會有所不同。

外部對象緩存是一個很大的好處,在任何情況下

設置外部持久對象緩存是非常推薦的,可以的時候。

所有關於 kovshenin 關於瞬態和 MySQL 的答案都是非常真實的,考慮到 WP 本身和一堆插件使用對象緩存… 然後性能提升,絕對值得 (小) 努力設置像 Redis 或 Memcached 這樣的現代緩存系統。

緩存值可能不在那裏:沒關係

而且,是的,外部對象緩存是不可靠的。你不應該依賴於一個瞬間的事實。如果緩存不在其中,則需要確保它有效。

緩存是 notstorage,緩存是緩存。

選擇使用緩存

看這個例子:

function my_get_some_value($key) {
   // by default no cache when debug and if no external object_cache
   $defUse = ! (defined('WP_DEBUG') && WP_DEBUG) && wp_using_ext_object_cache();
   // make the usage of cache filterable
   $useCache = apply_filters('my_use_cache', $defUse);
   // return cached value if any
   if ($useCache && ($cached = get_transient($key))) {
     return $cached;
   }
   // no cached value, make sure your code works with no cache
   $value = my_get_some_value_in_some_expensive_way();
   // set cache, if allowed
   $useCache and set_transient($key, $value, HOUR_IN_SECONDS);

   return $value;
}

使用這樣的代碼,在您的私人網站中,網站性能可以提高很多,特別是如果您有很多用户。

注意:

  • 默認情況下,調試開啓時不使用緩存,因此希望在您的開發環境中。相信我,緩存可以讓調試成為一個地獄

  • 默認情況下,當 WP 未設置為使用外部對象緩存時,緩存也不會被使用。這意味着與 MySQL 連接的所有問題都不存在,因為當 MySQL 使用 MySQL 時,不會出現任何瞬態問題。使用 wp_cache_*功能可能更容易一些,所以如果沒有設置外部緩存,那麼緩存就會在內存中發生,數據庫永遠都不會涉及。

  • 緩存的使用是可過濾的,可以處理您可能遇到的一些邊情況

沒有 Webscale 如果沒有緩存

您不應該嘗試解決緩存的速度問題。如果你有速度問題,那麼你應該 re-think 你的代碼。

但是,要在 webscale 上擴展一個網站,緩存是非常需要的。

而且很多次 (但不總是) 片段,context-aware 緩存比攻擊性全頁緩存更靈活和合適。

你的問題:

Should I use Transient API at all here?

這取決於。

您的代碼是否耗用大量資源?如果沒有,也可能不需要緩存。如上所述,不僅僅是速度的問題。如果你的代碼運行速度很快,但是對於幾個用户來説,它需要一堆 CPU 和內存?當你有 100 或 1000 個併發用户時會發生什麼?

如果你認識緩存會是個好主意..

… 是公共代碼:大概沒有。您可以考慮緩存緩存,就像上面在公共代碼中的示例一樣,但是如果您對實現者做出這樣的決定,通常會更好。

… 是私人密碼:很可能是的。但即使是私人代碼,選擇性緩存仍然是一件好事,例如調試。

記住,無論如何,wp_cache_*功能可以讓您訪問緩存,而不會有數據庫污染的風險。

Should I use Transient API to cache $related_posts array, or $html_output string?

這取決於很多事情。字符串有多大?你使用哪個外部緩存?如果要緩存帖子,將 ID 存儲為數組可能是一個好主意,通過其 ID 來查詢適當數量的帖子是相當快的。

最終註解

瞬態 API 可能是 WordPress 最好的之一。感謝您可以為任何類型的緩存系統找到的插件,它將成為可以在引擎蓋下工作的大量軟件的一個愚蠢的簡單 API 。

在 WordPress 外部,這種使用一堆不同的緩存系統開箱即用的抽象,並且允許您從一個系統切換到另一個系統,而不用努力就很難找到。

你很少聽到我説 WordPress 比其他現代的東西更好,但是當我不使用 WordPress 時,瞬態 API 是我想念的幾件事之一。

當然緩存很難,不解決代碼問題,而不是一個銀彈,但是你需要構建一個可以工作的 high-traffic 站點。

使用 under-optimized MySQL 表進行緩存的 WordPress 想法是非常瘋狂的,但是不要因為 WordPress 默認情況下使其遠離高速緩存。

你只需要瞭解事情的運作方式,然後做出選擇。

參考文獻

注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。