إعداد Redis كـ Object Cache لـWordPress على VPS
ثبّت Redis كـ object cache لـWordPress على VPS، واربطه بـ localhost، واضبط maxmemory وسياسة الإخلاء، ثم تحقّق من أن التخزين المؤقت يعمل فعلاً.
ما الذي يفعله Redis object cache في WordPress
يخزّن Redis object cache الخاص بـWordPress نتائج استعلامات قاعدة البيانات في الذاكرة، ولذلك يقرأها الطلب التالي من Redis بدلاً من طلبها من MySQL مرة أخرى. يحتوي WordPress أساساً على object cache في النواة، WP_Object_Cache، لكنه يعيش في ذاكرة PHP ويُحذف عند انتهاء الطلب. يستبدله ملف drop-in بملف يتصل بـRedis، ولذلك تبقى ذاكرة التخزين المؤقت من طلب إلى الطلب التالي.
لا تعني object caching تخزين الصفحات مؤقتاً، وهذا الفرق يحدد ما إذا كان هذا الدليل يستحق وقتك. يخزّن page cache كود HTML النهائي لعنوان URL، ويقدّمه مرة أخرى من دون تشغيل PHP إطلاقاً. وهذا أسرع من أي شيء يستطيع Redis فعله، ويعمل مع الزوار الذين لم يسجّلوا الدخول. عند تسجيل شخص الدخول، أو وضعه عنصراً في سلة التسوق، أو فتحه لوحة الإدارة، يتنحى page cache جانباً ويشغّل WordPress الطلب كاملاً: bootstrap، وplugins، والاستعلامات. تجعل object cache هذا الطلب أقل تكلفة. وهي الأداة اللازمة للتعامل مع حركة المرور التي لا يستطيع page cache تخزينها مؤقتاً: الجلسات التي سجّل أصحابها الدخول، وسلال التسوق، وcheckout، وwp-admin. في متجر WooCommerce، تمثل هذه معظم حركة المرور المكلفة.
تعمل الآليتان معاً، وتحتاج إلى كلتيهما في الموقع المزدحم. حدّد المشكلة التي تعمل على إصلاحها بوضوح. يحصل الموقع التعريفي الذي يضم قراء مجهولين على معظم سرعته من page cache، ولن تؤدي إضافة Redis إليه إلى تغيير كبير.
هناك حد مهم يجب معرفته قبل البدء. لا يجعل object cache الاستعلام البطيء سريعاً. فهو يزيل تكرار استعلام سبق تشغيله. يدفع الطلب الأول بعد فقدان الإدخال التكلفة الكاملة، ولذلك يظل plugin الذي يشغّل استعلاماً بلا فهرس ينفّذه مرة واحدة في كل مدة صلاحية للتخزين المؤقت.
ما تحتاج إليه أولاً
- VPS يعمل بنظام Linux مع shell و
sudo. لا تحتاج إلى لوحة تحكم. - WordPress يعمل عبر PHP-FPM، مثل مكدس LAMP على Ubuntu 24.04.
- WP-CLI مثبت على الخادم. لكل خطوة هنا مقابل في شاشة الإدارة، لكن إصدار shell أسرع.
- Redis على الجهاز نفسه الذي يعمل عليه PHP. تكمن الفائدة الأساسية في تقليل زمن الاستجابة، وتؤدي قفزة عبر الشبكة إلى إلغاء هذه الفائدة.
الأوامر أدناه مخصصة لـUbuntu 24.04 مع PHP 8.3 ومستخدم الويب www-data. عدّل إصدار PHP واسم المستخدم ليتوافقا مع خادمك. شغّل أوامر wp من مجلد WordPress الذي يحتوي على 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، وهي إضافة C من PECL. وهي أسرع من Predis، المكتوبة بالكامل بلغة PHP، وتستخدمها الإضافة تلقائياً عند توفرها. يحمّل PHP-FPM الإضافات عند بدء التشغيل، لذلك لن تظهر الإضافة الجديدة قبل إعادة تشغيل pool.
sudo systemctl restart php8.3-fpm
php -m | grep redisانتبه إلى الفحص الأخير: يعرض php -m وحدات PHP الخاصة بـسطر الأوامر، وقد يحمّل FPM مجموعة مختلفة. الفحص الحاسم هو تشخيص الإضافة نفسه، وستجده لاحقاً.
اعتباراً من August 2026، توفّر 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، وهي fork بدأ بعد تغيير الترخيص في 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 أفضل من TCP عبر loopback. لا يمر الاتصال عبر مكدس TCP، وتُحدَّد إمكانية الوصول بواسطة أذونات الملف بدلاً من قاعدة جدار ناري قد تغيّرها لاحقاً.
unixsocket /run/redis/redis-server.sock
unixsocketperm 770يملك المستخدم والمجموعة redis الـsocket، لذلك يجب إضافة مستخدم الويب إلى تلك المجموعة.
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 قيد التشغيل يحتفظ بالمجموعات التي كانت لديه عند بدء التشغيل، ولذلك يظهر أمر إعادة التشغيل في القائمة. اترك TCP مفعّلاً إلى أن تتأكد من عمل الـsocket، وإلا فقد يؤدي خطأ مطبعي إلى تعطيل المسارين معاً.
ما مقدار الذاكرة التي ينبغي تخصيصها لـRedis؟
اشتق الرقم من خادمك نفسه. ينمو Redis من دون maxmemory حتى تنفد ذاكرة النواة، ثم ينهي OOM killer إحدى العمليات، وغالباً ما ينهي العملية الأكبر، وهي MySQL في خادم WordPress. يعرض journalctl -k | grep -i "out of memory" عملية الإنهاء هذه بعد وقوعها، لكن الموقع يكون متوقفاً حينها.
ابدأ بإجمالي RAM ثم اطرح منه. يحجز MySQL أو MariaDB مقدار innodb_buffer_pool_size، إضافة إلى المخازن المؤقتة لكل اتصال. تستهلك PHP-FPM مقدار pm.max_children مضروباً في الحجم المقيم الفعلي لعامل واحد، وغالباً ما يتراوح ذلك بين 64 MB و128 MB في موقع يحتوي على عدد كبير من الإضافات. تحتاج النواة وخادم الويب إلى بضع مئات من الميغابايت. ما يتبقى هو الحد الأقصى لديك، ويأخذ Redis جزءاً منه.
ميزانية محسوبة لخادم VPS بسعة 4 GB يشغّل متجراً واحداً
هذه أرقام توضيحية وليست قياسات من خادمك. استبدل كل رقم منها بالقيمة التي يعرضها خادمك.
- MariaDB مع buffer pool بسعة 1 GB: 1024 MB
- PHP-FPM، مع 10 عمال بحجم 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، إذ سيستخدمها بصورة أفضل. وإذا بلغ الحد وظل 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، ثم اقرأ القيمة مرة أخرى. من المفيد وضع حد ثانٍ: يوقف حد MemoryMax على وحدة systemd Redis الذي أُسيء ضبطه من إسقاط الخادم. اضبطه فوق maxmemory، وليس مساوياً له، لأن حد cgroup ينهي العملية بدلاً من إخلاء مفتاح. إذا كان Redis يعمل في حاوية بجانب WordPress، فاستخدم الرقم نفسه في حدود الذاكرة في ملف Compose، ويحدد المنطق نفسه اختيار تشغيل قاعدة البيانات في Docker أو على الخادم المضيف.
اختر سياسة الإخلاء عن قصد
تستخدم نسخة Redis الجديدة القيمة الافتراضية noeviction. تحقّق من إعدادك:
redis-cli config get maxmemory-policyعند استخدام noeviction، تتوقف النسخة الممتلئة عن قبول عمليات الكتابة وتُرجع الرسالة التالية:
(error) OOM command not allowed when used memory > 'maxmemory'.هذا السطر هو أسوأ نمط فشل في هذا الدليل، لأن الموقع لا يتوقف. بل يصبح أبطأ. تفشل كل عملية كتابة إلى الذاكرة المخبئية، لذلك يعود WordPress إلى قاعدة البيانات لجلب القيمة، ثم يحاول تخزينها مرة أخرى في الطلب التالي ويفشل مجدداً. يدفع الموقع الآن تكلفة كل عمليات قاعدة البيانات الأصلية، بالإضافة إلى رحلة ذهاب وإياب إلى Redis لكل مفتاح. لا يخبرك أي شيء في لوحة إدارة WordPress بأن هذا يحدث. تظهر هذه السلسلة النصية في سجل أخطاء PHP، لذلك ابحث عن OOM command not allowed عندما يصبح الموقع أبطأ بعد إضافة ذاكرة مخبئية.
تُعد allkeys-lru القيمة الافتراضية الصحيحة هنا. يحذف Redis المفتاح الأقل استخداماً مؤخراً عندما تضيق الذاكرة، وهذا ما تحتاج إليه ذاكرة التخزين المؤقت للكائنات بالضبط، لأن كل قيمة فيها نسخة من بيانات لا تزال موجودة في MySQL. يؤدي فقدان مفتاح واحد إلى استعلام واحد. أما رفض عملية الكتابة فيؤدي إلى تنفيذ كل الاستعلامات، في كل طلب، إلى أن يلاحظ أحد ذلك.
تجنّب سياسات volatile-* لهذا الغرض. فهي تراعي المفاتيح التي تحمل وقت انتهاء فقط، ويوثّق Redis أنها تتصرف مثل noeviction عندما لا يكون لأي مفتاح وقت انتهاء. يخزّن WordPress معظم إدخالات ذاكرة التخزين المؤقت للكائنات من دون TTL، لذلك يمكن أن تمتلئ volatile-lru في ذاكرة التخزين المؤقت للكائنات وتبدأ برفض عمليات الكتابة. تُعد allkeys-lfu بديلاً مناسباً إذا كانت حركة المرور تصل إلى مجموعة صغيرة من المفاتيح بكثرة، لأنها تُخلي المفاتيح وفق معدل الاستخدام بدلاً من حداثة الاستخدام. اختر إحدى هذه السياسات عمداً، وسجّل سبب اختيارك.
الاستمرارية: عطّلها ما لم يكن لديك سبب لتفعيلها
تفعّل الحزمة redis.conf لقطات RDB باستخدام أسطر مثل save 900 1، وتترك ملف append-only معطّلاً. بالنسبة إلى cache مخصّص للكائنات فقط، لا تقدم اللقطات أي فائدة. فالبيانات قابلة لإعادة الإنشاء بحكم تعريفها، كما أن cache المستعاد من ملف عمره عشرون دقيقة سيكون مجموعة من القيم القديمة التي سيثق بها WordPress.
تستهلك اللقطات موارد أيضاً. إذ إن BGSAVE ينشئ نسخة فرعية من العملية، وتسمح آلية النسخ عند الكتابة بارتفاع استخدام الذاكرة بشكل حاد أثناء كتابة العملية الفرعية. يظهر ذلك على 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.لتعطيل اللقطات، اضبط جدول save فارغاً في /etc/redis/redis.conf، ثم أعد التشغيل وتحقق من أن القيمة عادت فارغة.
save ""sudo systemctl restart redis-server
redis-cli config get saveأبقِ الاستمرارية مفعّلة فقط إذا كان المثيل نفسه يحتفظ ببيانات لا يمكنك إعادة إنشائها، مثل قائمة مهام أو عدادات تحديد المعدل. في هذه الحالة، افصل بين الاستخدامين. يحتاج cache إلى حذف المفاتيح عند تجاوز السعة، بينما تحتاج البيانات الدائمة إلى الاحتفاظ بالمفاتيح. وينطبق maxmemory وسياسة الحذف عند تجاوز السعة على المثيل بأكمله، لا على فهرس قاعدة بيانات واحد. ويُعد تشغيل مثيلين على منفذين مختلفين الحل الأنظف.
ثبّت الإضافة وافهم ملف 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-content غير قابل للكتابة بواسطة المستخدم الذي يشغّل WP-CLI. وتعني 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، حدّد المخطط والمسار. عندئذٍ يتم تجاهل المضيف والمنفذ.
define( 'WP_REDIS_SCHEME', 'unix' );
define( 'WP_REDIS_PATH', '/run/redis/redis-server.sock' );
define( 'WP_REDIS_PREFIX', 'shop_prod:' );يفرض WP_REDIS_MAXTTL انتهاء صلاحية كل مفتاح، بالثواني. لا تحتاج إليه مع allkeys-lru، ويكون مفيداً إذا أردت حداً أقصى صارماً لمدة بقاء قيمة مخزّنة مؤقتاً قديمة.
Redis واحد، عدة مواقع: البادئات وقواعد البيانات
يوفّر Redis ست عشرة قاعدة بيانات مرقّمة افتراضياً، ومساحة مفاتيح مسطّحة واحدة داخل كل منها. إذا وُجّه تثبيتا WordPress إلى قاعدة البيانات 0 من دون بادئة، فسيكتبان أسماء المفاتيح نفسها في المساحة نفسها. لذلك قد يقرأ أحد الموقعين خيارات الموقع الآخر ويعرضها. امنح كل موقع بادئة خاصة به.
define( 'WP_REDIS_PREFIX', 'shopA_prod:' );
define( 'WP_REDIS_DATABASE', 1 );تفصل البادئة بين أسماء المفاتيح. ويفصل فهرس قاعدة البيانات بين مساحات المفاتيح، وهذا مهم عند تنفيذ flush: يؤدي إفراغ فهرس واحد إلى ترك الفهارس الأخرى دون تغيير. يوثّق المكوّن الإضافي أيضاً WP_REDIS_SELECTIVE_FLUSH، الذي يحذف المفاتيح المطابقة لبادئتك فقط بدلاً من حذف قاعدة البيانات بالكامل، لكنه يحتاج إلى البحث عن هذه المفاتيح.
ما لا تفصله البادئات والفهارس هو الذاكرة. ينطبق maxmemory وسياسة الإخلاء على المثيل بأكمله، لذلك قد يدفع موقع نشط مفاتيح موقع غير نشط إلى الإخلاء، من دون أن يبلّغ أيٌّ منهما عن ذلك. تحتاج المواقع التي يجب ألا يؤثر بعضها في بعض إلى مثيلات Redis منفصلة، ولكل مثيل socket خاص به وحدّ خاص به.
أبقِ بيئة الاختبار خارج ذاكرة التخزين المؤقت للإنتاج
يكون موقع الاختبار عادةً نسخة من ملفات الإنتاج وقاعدة بياناته، ما يعني أنه نسخة من wp-config.php تستخدم البادئة نفسها وفهرس قاعدة البيانات نفسه. إذا وجّهته إلى Redis نفسه، فسيكتب مفاتيح الإنتاج بقيم بيئة الاختبار. وقد يظهر سعر تجريبي أو خيار مُغيَّر على الموقع المباشر من دون نشر أو أثر في السجلات.
خصّص قيمة مختلفة لكل بيئة يدوياً. في ملف wp-config.php الخاص ببيئة الاختبار:
define( 'WP_REDIS_PREFIX', 'shop_staging:' );
define( 'WP_REDIS_DATABASE', 5 );والأفضل أن تمنح بيئة الاختبار نسخة Redis خاصة بها، أو ألا تستخدم ذاكرة تخزين مؤقت للكائنات إطلاقاً. يعطّل define( 'WP_REDIS_DISABLED', true ); ذاكرة التخزين المؤقت أثناء التشغيل ويُبقي ملف drop-in موجوداً، وهي أيضاً أسرع طريقة لإثبات ما إذا كان الخطأ ناتجاً عن ذاكرة التخزين المؤقت أم لا.
كانت البرامج التعليمية الأقدم تضبط WP_CACHE_KEY_SALT لهذا الغرض. يوضّح ملف readme الخاص بالإضافة أن هذا الثابت أصبح deprecated واستُبدل بـ WP_REDIS_PREFIX، لذلك استخدم الاسم الجديد.
تحقّق منه بدلاً من الوثوق به
ابدأ بأدوات التشخيص الخاصة بالـplugin.
wp redis statusالسطر الأهم هو Drop-in. يشير Drop-in: Valid إلى أن WordPress يحمّل ملف هذا الـplugin. يشير Drop-in: Not installed إلى أن عملية النسخ لم تحدث قط، وأن الموقع لا يملك cache دائمًا، مهما بدت شاشة الإدارة خضراء. يعرض Status الاتصال، ويسمّي Client الـextension المستخدم. هنا تؤكد استخدام PhpRedis بدلاً من Predis.
ثم اسأل WordPress core مباشرة، لأنه لا يهتم بما يعتقده الـplugin.
wp eval 'var_dump( wp_using_ext_object_cache() );'يعني bool(true) أن الـcore يتصل بـexternal object cache.
ثم أثبت وصول المفاتيح، باستخدام الـprefix الذي أعددته.
redis-cli -n 0 dbsize
redis-cli -n 0 --scan --pattern 'shop_prod:*' | headإن ارتفاع dbsize أثناء تنقلك في الموقع هو الدليل. يشير وجود صفر من المفاتيح مع drop-in صالح إلى أن الاتصال يفشل بصمت، أو أن الـprefix ليس الذي تظنه.
أخيراً، راجع ما يقيسه Redis نيابةً عنك.
redis-cli info stats | grep -E 'keyspace_hits|keyspace_misses|evicted_keys|expired_keys'نسبة الإصابات هي keyspace_hits / (keyspace_hits + keyspace_misses)، وتعرض وثائق Redis هذه الصيغة. اقرأها مع تنبيهين. تغطي العدادات الـinstance بالكامل منذ آخر إعادة تشغيل لها، ولذلك فهي تخلط بين كل موقع وكل تطبيق يشترك فيها. كما أن النسبة بعد flush أو إعادة تشغيل مباشرة لا تعني شيئاً، لأن الـcache لا يزال يمتلئ. اتركه يعمل خلال يوم عادي من network traffic.
لا تقارن رقمك بنسبة إصابات أو بعدد استعلامات تنشره شركة استضافة. فهذه الأرقام تصف مواقعها ومجموعة الـplugins لديها. الرقم المهم هو رقمك أنت، مقاساً قبل التغيير وبعده على صفحة لا يستطيع page cache تقديمها.
curl -o /dev/null -s -w '%{time_starttransfer}\n' -b cookies.txt https://example.com/my-account/نفّذ ذلك باستخدام cookie jar يتضمن جلسة تسجيل دخول، عدة مرات، مع إيقاف الـcache (WP_REDIS_DISABLED) ثم تشغيله. هذا الفرق هو نتيجتك.
عندما يجعل Redis موقع WordPress أبطأ
يُعد امتلاء المثيل مع استخدام سياسة خاطئة السبب الأكبر، وقد غُطي أعلاه: يظهر OOM command not allowed when used memory > 'maxmemory'. في السجل، ويدفع الموقع تكلفة كل من قاعدة البيانات وذاكرة التخزين المؤقت.
يأتي تشغيل Redis على مضيف آخر في المرتبة الثانية. يجري WordPress مئات الاستدعاءات لذاكرة التخزين المؤقت للكائنات ضمن الطلب الواحد. إذا أجرى الطلب 500 استدعاء، وكانت تكلفة كل رحلة ذهاباً وإياباً 1 ms، فهذا يعني نصف ثانية من الانتظار لا تحدث عند استخدام socket محلي. أبقِ Redis على الخادم نفسه، أو على شبكة خاصة ذات زمن انتقال أقل من 1 ms. أما مقدار الاستفادة من kernel عند استخدام الخادم نفسه فهو مسألة منفصلة: يحاول الجدولة المدركة لذاكرة التخزين المؤقت المضافة في Linux 7.2 إبقاء العمليات كثيرة التواصل، مثل PHP-FPM وRedis، على أنوية تشترك في ذاكرة تخزين مؤقت، ويستفيد الضيف على VPS من ذلك بدرجة أقل من الخادم الفعلي.
يأتي جدول الخيارات المحمّلة تلقائياً في المرتبة الثالثة، وهو شائع في المواقع القديمة. يخزّن WordPress جميع الخيارات المحمّلة تلقائياً في مفتاح واحد، لذلك يعبر حجمها البالغ ميجابايتاً واحداً الاتصال في كل طلب. قِس ذلك:
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 قيماً جديدة للتحميل التلقائي، لذلك فإن استعلاماً أقدم يطابق 'yes' فقط يعطي تقديراً أقل من الواقع عند استخدام تثبيت حديث. أي حجم يتجاوز ميجابايتاً واحداً يمثل مشكلة يجب إصلاحها في جدول الخيارات، لا في Redis.
يؤدي إعادة التشغيل إلى إفراغ كل شيء، لذلك تكون الدقائق التي تلي systemctl restart redis-server مليئة بحالات عدم العثور على العناصر وبكل عمليات قاعدة البيانات. أعد التشغيل عندما تكون حركة المرور منخفضة. كما أن ذاكرة التخزين المؤقت للكائنات لا تمنع تشغيل wp-cron.php عند تحميل صفحات الزوار، وهذا مصدر مستقل للطلبات البطيئة: انقل WP-Cron إلى مهمة cron فعلية للنظام أثناء إجراء هذه التغييرات.
الصيانة
نفِّذ تفريغاً بعد نشر يغيّر الخيارات أو شيفرة السمة باستخدام wp cache flush. شغّل wp redis update-dropin بعد تحديث إضافة إذا لم تُحدِّث الإضافة الجزئية نفسها، لأن وجود إضافة جزئية من إصدار أقدم من الإضافة مع إصدار أحدث منها يُعد مصدراً فعلياً للسلوك الغريب. راقب خادماً قيد التشغيل باستخدام redis-cli --stat، إذ يطبع سطراً واحداً كل ثانية. يطبع redis-cli monitor كل أمر، ويستهلك قدراً فعلياً من CPU على المثيل المشغول، لذلك استخدمه لبضع ثوانٍ أثناء إعادة إنتاج المشكلة، ثم أوقفه.
هناك رقم أخير يستحق معرفته: يعرض redis-cli info clients قيمة connected_clients. يحتفظ PHP-FPM باتصال واحد لكل عامل، لذلك ينبغي أن تتوافق هذه القيمة مع pm.max_children، لا أن تتجاوزها بمرتبة عشرية كاملة. إذا تجاوزتها، فهناك شيء يفتح اتصالات ولا يغلقها.
FAQ
هل ما زلت أحتاج إلى ذاكرة تخزين مؤقت للصفحات إذا كنت أشغّل ذاكرة تخزين مؤقت للكائنات باستخدام Redis؟
نعم، بالنسبة إلى الزيارات المجهولة. تعرض ذاكرة تخزين الصفحات HTML المخزّن من دون تشغيل PHP، وهذا أقل تكلفة دائماً من تشغيل WordPress مع ذاكرة تخزين مؤقت للكائنات مهيّأة مسبقاً. تتعامل ذاكرة تخزين الكائنات مع الطلبات التي يجب على ذاكرة تخزين الصفحات تجاوزها: المستخدمون الذين سجّلوا الدخول، وسلال التسوق، وإتمام الشراء، وwp-admin. في المتجر أو موقع العضويات، يستحق تشغيل كلتيهما. أما في الموقع الذي لا يسجّل زواره الدخول مطلقاً، فتنجز ذاكرة تخزين الصفحات معظم العمل.
ما مقدار الذاكرة التي ينبغي أن أخصصها لـRedis من أجل WordPress؟
احسبها استناداً إلى خادمك بدلاً من نسخ رقم جاهز. خذ إجمالي RAM، واطرح منه مخزن MySQL المؤقت والذاكرات المؤقتة لكل اتصال، ثم اطرح pm.max_children مضروباً في الحجم المقيم لعامل PHP-FPM واحد، واطرح بضع مئات من الميغابايتات للنواة وخادم الويب. خصص لـRedis جزءاً مما يتبقى، ثم افحص used_memory_human في redis-cli info memory بعد يوم من حركة المرور واضبط القيمة. يستقر موقع WordPress واحد عادةً عند عشرات الميغابايتات، لذلك يكون maxmemory بسعة 256 MB بداية سخية على خادم بسعة 4 GB.
لماذا أصبح موقعي أبطأ بعد تفعيل ذاكرة تخزين الكائنات باستخدام Redis؟
السبب المعتاد هو امتلاء المثيل الذي يستخدم سياسة noeviction. يرفض Redis عمليات الكتابة الجديدة ويعيد OOM command not allowed when used memory > 'maxmemory'.، لذلك يعود WordPress إلى قاعدة البيانات لكل قيمة، ويتحمل بالإضافة إلى ذلك زمناً ضائعاً في رحلة ذهاب وإياب إلى Redis. افحص redis-cli config get maxmemory-policy، واضبط allkeys-lru، وتأكد من أن maxmemory ليس صغيراً جداً. ومن الأسباب الشائعة الأخرى تشغيل خادم Redis على مضيف بعيد، إذ تتراكم مئات الرحلات ذهاباً وإياباً لكل طلب، ووجود قيمة خيارات محمّلة تلقائياً بحجم عدة ميغابايتات تعبر الاتصال مع كل طلب.
هل يمكن لعدة مواقع WordPress مشاركة خادم Redis واحد؟
نعم، مع توخي الحذر. امنح كل موقع WP_REDIS_PREFIX فريداً حتى لا تتعارض أسماء المفاتيح، واستخدم فهرس WP_REDIS_DATABASE منفصلاً حتى لا يؤدي تفريغ موقع واحد إلى إفراغ موقع آخر. لكن المواقع ستظل تشترك في الذاكرة: ينطبق maxmemory والإخلاء على المثيل بأكمله، لذلك يمكن لموقع نشط أن يطرد مفاتيح موقع قليل النشاط. تحتاج المواقع التي يجب ألا يؤثر بعضها في بعض إلى مثيلات Redis منفصلة بحدودها الخاصة.
هل حذف wp-content/object-cache.php آمن؟
نعم. فهذا ملف drop-in وليس جزءاً من نواة WordPress، وإزالته تعيد WordPress إلى ذاكرة التخزين المؤقت المضمّنة لكل طلب. سيستمر الموقع في العمل، لكنه سينفذ ببساطة استعلامات أكثر إلى قاعدة البيانات. يُفضّل استخدام wp redis disable، الذي يحذف الملف بطريقة صحيحة ويعرض Object cache disabled.. ويكون حذفه يدوياً هو الإجراء الطارئ المناسب إذا كان Redis متوقفاً أو يتصرف على نحو غير سليم، ولم تتمكن من الوصول إلى لوحة الإدارة.