SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 已更新 2026-08-30

WordPress VPS 如何設定 Redis 物件快取

在自有 VPS 上為 WordPress 設定 Redis 物件快取:綁定 localhost、設定 maxmemory 與驅逐策略,並用 WP-CLI 驗證快取確實運作。

WordPress 的 Redis 物件快取用途

WordPress 的 Redis 物件快取會將資料庫查詢結果儲存在記憶體中,讓下一次請求直接從 Redis 讀取,而不必再次查詢 MySQL。WordPress 核心本身已提供物件快取 WP_Object_Cache,但該快取位於 PHP 記憶體中,請求結束後就會被丟棄。drop-in 檔案會將它替換成可與 Redis 通訊的版本,讓快取能在不同請求之間持續存在。

物件快取不是頁面快取。這項差異會決定本指南是否適合你的情況。頁面快取會儲存 URL 已產生的完整 HTML,之後直接再次提供,不必執行 PHP。這比 Redis 能做到的任何處理都快,而且適用於尚未登入的訪客。使用者登入、將商品加入購物車或開啟管理介面後,頁面快取就不再介入,WordPress 必須完整處理請求:啟動程序、外掛與查詢。物件快取能降低這類請求的成本。它適用於頁面快取無法處理的流量,包括已登入工作階段、購物車、結帳流程與 wp-admin。對 WooCommerce 商店而言,這通常是大部分成本較高的流量。

兩者可以搭配使用,忙碌的網站通常都需要它們。請先確認要解決的是哪個問題。只有匿名讀者的形象網站,幾乎所有速度提升都來自頁面快取;加入 Redis 後,變化通常很小。

開始前先說明一項限制。物件快取無法讓緩慢的查詢變快。它只能避免重複執行已經完成的查詢。快取未命中後的第一個請求仍須支付完整成本,因此,使用未建立索引查詢的外掛,仍會在每個快取生命週期中執行該查詢一次。

執行前的需求

  • 具備 shell 與 sudo 的 Linux VPS。不需要控制台。
  • 使用 PHP-FPM 提供服務的 WordPress,例如 Ubuntu 24.04 上的 LAMP 堆疊。
  • 伺服器上已安裝 WP-CLI。這裡的每個步驟都有管理介面中的對應操作,但使用 shell 會更快。
  • Redis 與 PHP 位於同一台機器上。此設定的重點在於低延遲,經過網路跳轉會抵銷這項優勢。

以下指令以 Ubuntu 24.04、PHP 8.3 及 www-data Web 使用者為例。請依伺服器實際環境調整 PHP 版本與使用者。請在 WordPress 目錄中執行 wp 指令,也就是包含 wp-config.php 的目錄。

安裝 Redis 與 PHP 擴充功能

sudo apt update
sudo apt install -y redis-server php-redis
sudo systemctl enable --now redis-server
redis-cli ping

redis-cli ping 應回應 PONG。如果輸出 Could not connect to Redis at 127.0.0.1:6379: Connection refused,表示伺服器尚未執行,因此請先閱讀 systemctl status redis-server,再繼續操作。

php-redis 是 PhpRedis,也就是來自 PECL 的 C 擴充功能。它比完全以 PHP 撰寫的 Predis 更快。外掛程式在偵測到它時會自動使用。PHP-FPM 會在啟動時載入擴充功能,因此重新啟動 pool 前,新擴充功能不會生效。

sudo systemctl restart php8.3-fpm
php -m | grep redis

請注意最後一項檢查:php -m 列出的是命令列 PHP 載入的模組,而 FPM 可能載入不同的模組集合。真正應採信的是外掛程式自己的診斷結果,該結果會在下文顯示。

截至 2026 年 8 月,Ubuntu 24.04 提供 Redis 7.0.15。這個版本適合用作物件快取。如果需要較新的版本,Redis 也提供自己的 APT 套件庫。

sudo apt install -y lsb-release curl gpg
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
sudo apt update
sudo apt install -y redis

如果您的發行版提供 Valkey,這是 2024 年授權變更後建立的分支。它使用相同的通訊協定,因此以下內容均可直接套用。

將 Redis 綁定至不對外開放

Redis 預設沒有密碼。任何能連線至 6379 埠的對象,都能讀取所有快取值並執行 FLUSHALL。暴露在網際網路上的執行個體通常會在數小時內被掃描器發現,因此應先設定網路存取,再進行效能調校。

開啟 /etc/redis/redis.conf,確認其中包含以下設定:

bind 127.0.0.1 -::1
protected-mode yes

接著檢查實際處於監聽狀態的項目,因為設定檔只是宣告,ss 才是實際證據。

sudo ss -lntp | grep 6379

127.0.0.1:6379 才是預期結果。0.0.0.0:6379 表示 Redis 正在公開介面上回應:修正 bind 行,然後重新啟動服務。

PHP 與 Redis 位於同一台主機時,Unix socket 優於 loopback TCP。資料傳輸不必經過 TCP stack,存取權限由檔案權限決定,不會受日後可能變更的防火牆規則影響。

unixsocket /run/redis/redis-server.sock
unixsocketperm 770

socket 的擁有者與群組是 redis,因此網頁服務使用者必須加入該群組。

sudo systemctl restart redis-server
sudo usermod -aG redis www-data
sudo systemctl restart php8.3-fpm
redis-cli -s /run/redis/redis-server.sock ping

該指令也必須輸出 PONG。Could not connect to Redis at /run/redis/redis-server.sock: Permission denied 表示群組設定尚未生效。檢查 id www-data,並注意執行中的 PHP-FPM 會保留啟動時取得的群組,因此清單中才需要重新啟動。確認 socket 可正常使用前,請保留 TCP 啟用狀態,否則拼寫錯誤可能會同時中斷兩條連線路徑。

Redis 應配置多少記憶體?

請根據實際主機推算數值。若未設定 maxmemory,Redis 會持續成長,直到核心耗盡記憶體並由 OOM killer 終止程序。通常被終止的是占用記憶體最多的程序;在 WordPress 伺服器上,這通常是 MySQL。journalctl -k | grep -i "out of memory" 只能事後顯示這次終止事件,而網站屆時已經中斷。

從總 RAM 開始逐項扣除。MySQL 或 MariaDB 會保留 innodb_buffer_pool_size,另加每個連線的緩衝區。PHP-FPM 的記憶體需求為 pm.max_children 乘以單一 worker 的實際常駐大小。使用大量外掛的網站通常是每個 worker 64 MB 到 128 MB。核心與 Web 伺服器需要數百 MB。剩餘容量就是上限,Redis 只能使用其中一部分。

以執行單一商店的 4 GB VPS 為例計算預算

以下是範例數值,不是從您的伺服器測得的結果。請將每個數值替換為主機回報的值。

  • MariaDB 使用 1 GB buffer pool:1024 MB
  • PHP-FPM,10 個 worker,每個 96 MB:960 MB
  • 核心、nginx 或 Apache、sshd、日誌:512 MB
  • 剩餘:約 1.5 GB

在此情況下,maxmemory 設為 256 MB 是合理的起始值。這會保留足夠的餘裕,單一 WordPress 網站通常也不需要更多記憶體。

現在請透過測量取代猜測。讓網站承受一天的實際流量後:

redis-cli info memory | grep -E 'used_memory_human|maxmemory_human|maxmemory_policy'
redis-cli dbsize

如果 used_memory_human 遠低於上限,請降低上限,並將 RAM 還給 MySQL,因為 MySQL 能更有效地使用這些記憶體。如果它持續達到上限,且 evicted_keys 整天上升,請提高上限。將數值設定在 /etc/redis/redis.conf。

maxmemory 256mb
maxmemory-policy allkeys-lru

redis-cli config set maxmemory 256mb 只會立即套用,下一次重新啟動時就會失效;這與單獨使用 sysctl -w 的問題相同。請編輯檔案,接著執行 sudo systemctl restart redis-server,再讀回數值確認。設定第二道限制也很有用:在 systemd unit 上設定 MemoryMax 上限,可避免設定錯誤的 Redis 使整台主機停止運作。請將它設在 maxmemory 之上,不要設為相同值,因為 cgroup 限制會終止程序,而不是驅逐 key。若 Redis 與 WordPress 一起執行於容器中,請將相同數值設定在 Compose 檔案中的記憶體限制,並以相同的判斷方式決定 將資料庫執行於 Docker 或主機上。

刻意選擇驅逐政策

全新的 Redis 預設為 noeviction。請檢查目前的設定:

redis-cli config get maxmemory-policy

在 noeviction 下,記憶體用滿的執行個體會停止接受寫入,並回傳以下訊息:

(error) OOM command not allowed when used memory > 'maxmemory'.

這是本指南中最嚴重的失效模式,因為網站不會停止服務,而是變慢。每次快取寫入都會失敗,因此 WordPress 會回到資料庫讀取值,接著在下一次請求時再次嘗試儲存,並再次失敗。此時,網站除了原本的所有資料庫工作外,還會為每個 key 額外付出一次 Redis 往返延遲。WordPress 管理介面不會告訴你正在發生這種情況。這段字串會出現在 PHP error log 中,因此網站在加入快取後變慢時,請搜尋 OOM command not allowed。

allkeys-lru 是此處適合的預設值。記憶體不足時,Redis 會丟棄最近最少使用的 key。這正是物件快取需要的行為,因為其中每個值都是 MySQL 中仍然存在的資料副本。遺失一個 key 只需多執行一次查詢。拒絕寫入則會讓每次請求的所有查詢持續發生,直到有人察覺問題。

請避免在此用途使用 volatile-* 政策。這些政策只會考慮帶有到期時間的 key;Redis 文件指出,當沒有任何 key 設定到期時間時,它們的行為會像 noeviction。WordPress 儲存大多數物件快取項目時不會設定 TTL,因此物件快取使用 volatile-lru 可能會填滿,並開始拒絕寫入。如果流量經常集中在少數 key 上,allkeys-lfu 是合理的替代方案,因為它會依使用頻率而非最近使用時間進行驅逐。請刻意選擇一項,並記錄選擇原因。

持久化:除非有明確理由,否則關閉

套件提供的 redis.conf 會透過 save 900 1 這類設定啟用 RDB snapshot,並關閉 append-only file。對純物件快取而言,snapshot 沒有實際效益。資料本來就能重新產生,而從 20 分鐘前的檔案還原的快取,會包含過期值,WordPress 仍會信任這些值。

Snapshot 也會消耗資源。BGSAVE 會 fork 程序,而 copy-on-write 會讓子程序寫入資料時的記憶體使用量大幅上升。在小型 VPS 上,Redis 日誌通常會出現:

Can't save in background: fork: Cannot allocate memory

啟動時也常會出現以下警告。這表示 Redis 判斷後續的 fork 可能會失敗:

WARNING overcommit_memory is set to 0! Background save may fail under low memory condition.

若要關閉 snapshot,請在 /etc/redis/redis.conf 中設定空白的 save 排程,重新啟動,並確認該值恢復為空白。

save ""
sudo systemctl restart redis-server
redis-cli config get save

只有在同一個 instance 還存放無法重建的資料時,才保留持久化功能,例如 job queue 或 rate-limit counters。這種情況下,請將兩者分開。快取需要淘汰 keys,而持久資料需要保留 keys;maxmemory 與 eviction 會套用至整個 instance,而不是單一 database index。讓兩個 instance 分別使用兩個 socket,是最乾淨的做法。

安裝外掛並了解 drop-in

wp plugin install redis-cache --activate
wp redis enable
wp redis status

wp redis enable 成功時會輸出 Object cache enabled.。它實際上會將 wp-content/plugins/redis-cache/includes/object-cache.php 複製到 wp-content/object-cache.php。該副本就是 drop-in,而 drop-in 才是實際執行工作的部分。WordPress 會在非常早期載入 wp-content/object-cache.php,早於任何外掛程式碼執行,因此整個請求期間都能使用快取。已啟用但沒有 drop-in 的外掛不會快取任何內容。

錯誤訊息會指出哪一部分發生故障。Object cache could not be enabled. 表示複製失敗,因此執行 WP-CLI 的使用者無法寫入 wp-content。A foreign object cache drop-in was found. 表示已有其他快取外掛使用該檔名,修正方式是 wp redis update-dropin。若訊息以 Redis server is unreachable: 結尾,接著出現用戶端錯誤,表示連線設定錯誤,請返回 redis-cli ping。

如果複製因權限問題失敗,請手動放置該檔案,並將檔案擁有者設為網頁服務使用者。

cp wp-content/plugins/redis-cache/includes/object-cache.php wp-content/object-cache.php
sudo chown www-data:www-data wp-content/object-cache.php

移除外掛不會移除 drop-in。先執行 wp redis disable,該指令會輸出 Object cache disabled. 並刪除檔案。如果在 drop-in 留存的情況下刪除外掛目錄,網站仍會執行舊的快取程式碼,且沒有外掛可供更新。

wp-config.php 中的連線設定

請將以下內容加在寫有 /* That's all, stop editing! */ 的那一行之前,因為在該行之後定義常數已經太晚。

define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_DATABASE', 0 );
define( 'WP_REDIS_PREFIX', 'shop_prod:' );

使用 Unix socket 時,請設定 scheme 和路徑。此時會忽略主機與連接埠。

define( 'WP_REDIS_SCHEME', 'unix' );
define( 'WP_REDIS_PATH', '/run/redis/redis-server.sock' );
define( 'WP_REDIS_PREFIX', 'shop_prod:' );

WP_REDIS_MAXTTL 會以秒為單位,強制所有 key 設定到期時間。搭配 allkeys-lru 時不需要設定此常數;如果需要嚴格限制快取值可能過期多久,則可使用此設定。

一個 Redis、多個網站:前綴與資料庫

Redis 預設提供 16 個編號資料庫,每個資料庫內都有一個扁平的鍵空間。兩個 WordPress 安裝若都指向資料庫 0,且未設定前綴,就會在同一個空間寫入相同的鍵名。因此,一個網站可能讀取另一個網站的選項並提供給訪客。請為每個網站設定專屬前綴。

define( 'WP_REDIS_PREFIX', 'shopA_prod:' );
define( 'WP_REDIS_DATABASE', 1 );

前綴會區隔鍵名。資料庫索引會區隔鍵空間,這在清除資料時很重要:清空其中一個索引不會影響其他索引。外掛程式也說明了 WP_REDIS_SELECTIVE_FLUSH;這只會刪除符合前綴的鍵,而不是整個資料庫,但必須掃描這些鍵。

前綴與索引都無法區隔記憶體。maxmemory 與淘汰政策套用於整個執行個體,因此忙碌的網站可能讓安靜網站的鍵被淘汰,而且兩者都不會回報這種情況。若網站之間不得互相影響,請使用個別的 Redis 執行個體;每個執行個體都應有自己的 socket 與限制。

讓 staging 排除在 production 的快取之外

staging 網站通常是 production 檔案與資料庫的複本,因此也會複製 wp-config.php,使用相同的前綴與資料庫索引。若將它指向相同的 Redis,staging 就會以測試環境的值寫入 production 的 key。測試價格或變更選項可能因此直接出現在正式網站,無須部署,也不會留下記錄。

請手動為各環境設定不同的 salt。在 staging 的 wp-config.php 中:

define( 'WP_REDIS_PREFIX', 'shop_staging:' );
define( 'WP_REDIS_DATABASE', 5 );

更好的做法是讓 staging 使用獨立的 Redis instance,或完全不使用 object cache。define( 'WP_REDIS_DISABLED', true ); 會在執行階段關閉快取,但保留 drop-in。這也是最快確認問題是否由快取造成的方法。

較舊的教學會為此設定 WP_CACHE_KEY_SALT。該 plugin 的 readme 將此 constant 標示為 deprecated,並指出已由 WP_REDIS_PREFIX 取代,因此請使用新的名稱。

驗證,而不是盲目信任

先從外掛本身的診斷資訊開始。

wp redis status

最重要的是 Drop-in。Drop-in: Valid 表示 WordPress 正在載入此外掛的檔案。Drop-in: Not installed 表示複製動作從未完成,網站沒有持久性快取,即使管理介面顯示為綠色狀態也是如此。Status 回報連線狀態,Client 則指出正在使用的擴充功能。請在此確認使用的是 PhpRedis,而不是 Predis。

接著直接詢問 WordPress 核心,因為核心不會在意外掛的判斷。

wp eval 'var_dump( wp_using_ext_object_cache() );'

bool(true) 表示核心正在使用外部物件快取。

接著使用你設定的前綴,確認金鑰確實已寫入。

redis-cli -n 0 dbsize
redis-cli -n 0 --scan --pattern 'shop_prod:*' | head

你在網站上點選操作時,dbsize 持續上升就是證據。有效的 drop-in 搭配 0 個金鑰,表示連線正在靜默失敗,或是使用的前綴並不是你以為的那個。

最後查看 Redis 為你統計的資料。

redis-cli info stats | grep -E 'keyspace_hits|keyspace_misses|evicted_keys|expired_keys'

命中率是 keyspace_hits / (keyspace_hits + keyspace_misses),Redis 文件提供了這個公式。解讀時請注意兩點。這些計數器涵蓋整個執行個體自上次重新啟動以來的資料,因此會混合所有共用該執行個體的網站與應用程式。清除快取或重新啟動後立即查看的比率沒有意義,因為快取仍在填充中。請讓它運作一個正常的流量日。

不要將你的數值與託管公司公布的命中率或查詢數量比較。那些數據描述的是該公司的網站與外掛組合。真正重要的是你自己的數值,並且要在頁面快取無法提供內容的頁面上,分別於啟用前後進行測量。

curl -o /dev/null -s -w '%{time_starttransfer}\n' -b cookies.txt https://example.com/my-account/

使用已登入的 cookie jar 執行數次,先關閉快取(WP_REDIS_DISABLED),再開啟快取。兩者的差異就是結果。

Redis 讓 WordPress 變慢的情況

錯誤的 eviction policy 導致 Redis instance 已滿,是最常見的原因,前文已說明:日誌中會出現 OOM command not allowed when used memory > 'maxmemory'.,而網站同時支付資料庫與 cache 的費用。

Redis 位於其他主機是第二個原因。WordPress 會在單一請求中執行數百次 object cache 呼叫。若一個請求執行 500 次呼叫,且每次 round trip 需時 1 ms,等待時間就會達到半秒;使用 local socket 則不會有這段延遲。請將 Redis 保留在同一台主機,或放在具有 sub-millisecond latency 的 private network 上。同一主機的情況能從 kernel 獲得多少效益,則是另一個問題:Linux 7.2 新增的 cache aware scheduling 會嘗試將 PHP-FPM 與 Redis 等頻繁互動的程序安排在共用 cache 的核心上,而 VPS guest 能獲得的這類效益少於 bare metal。

巨大的 autoloaded options table 是第三個原因,在舊網站上很常見。WordPress 會將所有 autoloaded options 以單一 key 進行 cache,因此每個請求都會透過連線傳送數 MB 的資料。請測量:

wp db query "SELECT ROUND(SUM(LENGTH(option_value))/1024) AS kb FROM wp_options WHERE autoload IN ('yes','on','auto','auto-on');"

WordPress 6.6 新增了 autoload 值,因此較舊的查詢只比對 'yes',在現代安裝上會低估數值。超過 1 MB 的資料表示應修正 options table,而不是修正 Redis。

重新啟動會清空所有內容,因此 systemctl restart redis-server 後的幾分鐘內,所有請求都是 cache miss,且都會增加資料庫負載。請在流量較低時重新啟動。此外,object cache 不會阻止 wp-cron.php 在訪客載入頁面時執行,這也是請求變慢的另一個原因:請趁此機會將 WP-Cron 移至真正的 system cron job。

日常維護

部署會變更選項或主題程式碼時,使用 wp cache flush 清除快取。外掛程式更新後,如果 drop-in 沒有自行更新,請執行 wp redis update-dropin。較舊外掛程式版本的 drop-in 搭配較新的外掛程式使用,確實可能造成異常行為。使用 redis-cli --stat 監看執行中的伺服器;它每秒輸出一行。redis-cli monitor 會輸出每個命令,忙碌的執行個體會因此消耗實際 CPU 資源。重現問題時,讓它執行幾秒後停止即可。

最後還有一個值得了解的數值:redis-cli info clients 會回報 connected_clients。PHP-FPM 會為每個 worker 維持一個連線,因此這個數值應與 pm.max_children 大致一致,不應高出一個數量級。若確實高出許多,表示有某個元件正在建立連線,卻沒有將其關閉。

FAQ

如果使用 Redis 物件快取,還需要頁面快取嗎?

需要,匿名流量仍然需要。頁面快取可直接提供已儲存的 HTML,不必執行 PHP,成本始終低於在物件快取已有資料的情況下執行 WordPress。物件快取則處理頁面快取必須略過的請求:已登入使用者、購物車、結帳流程和 wp-admin。在商店或會員網站上,兩者都值得使用。若網站訪客從未登入,幾乎所有工作都由頁面快取處理。

WordPress 應該分配多少記憶體給 Redis?

請根據自己的伺服器計算,不要直接套用固定數值。先取總 RAM,扣除 MySQL buffer pool 和每個連線的 buffer,再扣除 pm.max_children 乘以單一 PHP-FPM worker 的常駐大小,最後扣除核心和 Web 伺服器所需的數百 MB。將剩餘記憶體的一部分分配給 Redis,運作一天後檢查 redis-cli info memory 中的 used_memory_human,再依結果調整。單一 WordPress 網站通常只需要數十 MB,因此在 4 GB 伺服器上,256 MB 的 maxmemory 是寬裕的起始值。

為什麼啟用 Redis 物件快取後,網站反而變慢?

最常見的原因是執行 noeviction 政策的 Redis instance 已經用滿。Redis 會拒絕新的寫入並回傳 OOM command not allowed when used memory > 'maxmemory'.,因此 WordPress 對每個值都改向資料庫查詢,還要額外承擔一次無效的 Redis 往返。請檢查 redis-cli config get maxmemory-policy、設定 allkeys-lru,並確認 maxmemory 不是過小。其他常見原因包括 Redis 伺服器位於遠端主機,導致每個請求累積數百次往返延遲;以及 autoload 的 options 值達到數 MB,導致每個請求都必須透過連線傳送這些資料。

多個 WordPress 網站可以共用一台 Redis 伺服器嗎?

可以,但必須謹慎設定。為每個網站指定唯一的 WP_REDIS_PREFIX,避免 key 名稱互相衝突;同時使用不同的 WP_REDIS_DATABASE index,讓清除一個網站的資料時不會清空其他網站的資料。各網站仍會共用記憶體:maxmemory 和 eviction 會套用到整個 instance,因此流量大的網站可能驅逐流量小網站的 keys。若網站之間不得互相影響,應使用各自設有限制的獨立 Redis instances。

可以安全刪除 wp-content/object-cache.php 嗎?

可以。這是 drop-in,不屬於 WordPress core。刪除後,WordPress 會恢復使用內建的每次請求快取。網站仍可正常運作,只是會執行更多資料庫查詢。建議使用 wp redis disable,它會乾淨地刪除檔案,並回報 Object cache disabled.。如果 Redis 停止服務或運作異常,且無法進入管理介面,手動刪除檔案是正確的緊急處理方式。