آموزش راه اندازی Redis برای کش وردپرس روی VPS
با نصب Redis روی VPS، سرعت سایت وردپرسی خود را برای کاربران وارد شده افزایش دهید. این راهنما شامل تنظیمات maxmemory، سیاست eviction و تست اتصال برای بهینهسازی دیتابیس است.
کش اشیاء Redis برای وردپرس چه کاری انجام میدهد
کش اشیاء Redis برای وردپرس، نتایج پرسوجوهای پایگاه داده را در حافظه ذخیره میکند تا درخواست بعدی بهجای پرسش مجدد از MySQL، آنها را از Redis بخواند. وردپرس در هستهٔ خود یک کش اشیاء دارد، WP_Object_Cache، اما این کش در حافظهٔ PHP باقی میماند و با پایان یافتن درخواست، حذف میشود. یک فایل drop-in، آن را با فایلی جایگزین میکند که با Redis در ارتباط است، بنابراین کش از یک درخواست تا درخواست بعدی باقی میماند.
کش اشیاء با کش صفحه متفاوت است و همین تفاوت تعیین میکند که آیا این راهنما برای شما مفید است یا خیر. کش صفحه، HTML نهایی یک URL را ذخیره میکند و آن را بدون اجرای PHP ارائه میدهد. این روش از هر کاری که Redis انجام میدهد سریعتر است و برای بازدیدکنندگانی که وارد سیستم نشدهاند، کارایی دارد. به محض اینکه شخصی وارد سیستم شود، کالایی را به سبد خرید اضافه کند یا پنل مدیریت را باز کند، کش صفحه کنار میرود و وردپرس کل درخواست را اجرا میکند: bootstrap، افزونهها و پرسوجوها. کش اشیاء آن درخواست را کمهزینهتر میکند. این ابزار برای ترافیکی است که کش صفحه نمیتواند پوشش دهد: نشستهای کاربران واردشده، سبدهای خرید، تسویه حساب و wp-admin. در یک فروشگاه WooCommerce، این بخش بیشترین ترافیک سنگین را تشکیل میدهد.
این دو در کنار هم قرار میگیرند و در یک سایت پربازدید، هر دو ضروری هستند. مشخص کنید که در حال حل چه مشکلی هستید. یک سایت معرفی که خوانندگان ناشناس دارد، تقریباً تمام سرعت خود را از کش صفحه میگیرد و افزودن Redis به آن تغییر چندانی ایجاد نمیکند.
یک محدودیت صادقانه پیش از شروع: کش اشیاء، یک پرسوجوی کند را سریع نمیکند. بلکه تکرار پرسوجویی که قبلاً اجرا شده است را حذف میکند. اولین درخواست پس از یک miss، هزینهٔ کامل را پرداخت میکند، بنابراین افزونهای که یک پرسوجوی بدون ایندکس را اجرا میکند، همچنان آن را یک بار در طول عمر کش اجرا خواهد کرد.
پیشنیازها
- یک سرور مجازی لینوکس با دسترسی shell و
sudo. نیازی به کنترل پنل نیست. - وردپرس که توسط PHP-FPM سرویسدهی میشود، برای مثال روی یک LAMP stack روی Ubuntu 24.04.
- ابزار WP-CLI روی سرور. تمام مراحل این راهنما معادلهایی در پنل مدیریت وردپرس دارند، اما نسخه shell سریعتر است.
- Redis روی همان ماشینی که PHP اجرا میشود. هدف اصلی کاهش تأخیر (latency) است و هر پرش شبکه (network hop) این مزیت را از بین میبرد.
دستورات زیر برای Ubuntu 24.04 با PHP 8.3 و کاربر وب www-data نوشته شدهاند. نسخه PHP و نام کاربر را متناسب با تنظیمات سرور خود تغییر دهید. دستورات 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 pingredis-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 را restart نکنید، قابل مشاهده نخواهد بود.
sudo systemctl restart php8.3-fpm
php -m | grep redisدر بررسی آخر دقت کنید: php -m ماژولهای PHP خط فرمان (CLI) را فهرست میکند، در حالی که FPM ممکن است مجموعه متفاوتی را بارگذاری کند. بررسی معتبر، همان ابزار تشخیص (diagnostics) خودِ پلاگین است که در ادامه آمده است.
تا اوت 2026، توزیع Ubuntu 24.04 نسخه Redis 7.0.15 را ارائه میدهد که برای کش کردن اشیاء (object cache) مناسب است. اگر به نسخه جدیدتری نیاز دارید، 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 در مسیر قرار ندارد و دسترسی بهجای قوانین فایروال (که ممکن است بعداً تغییر کنند)، توسط مجوزهای فایل تعیین میشود.
unixsocket /run/redis/redis-server.sock
unixsocketperm 770مالکیت سوکت در اختیار کاربر و گروه 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 در حال اجرا، گروههایی را که هنگام شروع داشته است حفظ میکند؛ به همین دلیل ریاستارت در لیست قرار دارد. تا زمانی که از عملکرد سوکت مطمئن نشدهاید، TCP را فعال نگه دارید، در غیر این صورت یک اشتباه تایپی ممکن است هر دو مسیر دسترسی را همزمان مسدود کند.
میزان حافظه اختصاصیافته به Redis چقدر باید باشد؟
این مقدار را بر اساس سرور خود محاسبه کنید. Redis بدون maxmemory تا زمانی که حافظه هسته سیستمعامل تمام شود رشد میکند؛ در این حالت OOM killer وارد عمل شده و یک پردازش را متوقف میکند که معمولاً بزرگترین آنهاست؛ در یک سرور وردپرس، این پردازش اغلب MySQL است. journalctl -k | grep -i "out of memory" این توقف را پس از وقوع نشان میدهد و در آن لحظه سایت از دسترس خارج شده است.
از کل RAM شروع کرده و مقادیر مصرفی را کسر کنید. MySQL یا MariaDB به میزان innodb_buffer_pool_size به اضافه بافرهای مربوط به هر اتصال نیاز دارند. PHP-FPM هزینهای معادل pm.max_children ضربدر اندازه واقعی حافظه اشغالشده توسط یک worker دارد که معمولاً در سایتهای دارای افزونههای زیاد، بین 64 تا 128 مگابایت است. هسته سیستمعامل و وبسرور نیز به چند صد مگابایت حافظه نیاز دارند. آنچه باقی میماند سقف مجاز شماست و Redis بخشی از آن را دریافت میکند.
بودجهبندی نمونه برای یک VPS با 4 گیگابایت رم که یک فروشگاه را میزبانی میکند
اینها ارقام نمونه هستند، نه اندازهگیریهای سرور شما. هر کدام را با مقداری که سرور شما گزارش میدهد جایگزین کنید.
- MariaDB با یک buffer pool به حجم 1 گیگابایت: 1024 مگابایت
- PHP-FPM، ده worker با 96 مگابایت برای هر کدام: 960 مگابایت
- هسته، nginx یا Apache، sshd، لاگها: 512 مگابایت
- باقیمانده: تقریباً 1.5 گیگابایت
یک maxmemory معادل 256 مگابایت، شروع منطقی در این سناریو است. این مقدار فضای تنفس کافی باقی میگذارد و یک سایت وردپرس بهندرت به بیش از آن نیاز دارد.
حالا بهجای حدس زدن، اندازهگیری کنید. پس از یک روز ترافیک واقعی:
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-lruredis-cli config set maxmemory 256mb بلافاصله اعمال میشود اما با ریاستارت بعدی فراموش میگردد؛ این همان دامی است که در sysctl -w خام وجود دارد. فایل را ویرایش کنید، سپس sudo systemctl restart redis-server را اجرا کرده و مقدار را دوباره بخوانید. داشتن یک دیوار دوم ارزشمند است: یک محدودیت MemoryMax در unit سیستمدی مانع از آن میشود که یک Redis با پیکربندی اشتباه، کل سرور را از کار بیندازد. آن را بالاتر از maxmemory تنظیم کنید و هرگز با آن برابر قرار ندهید، زیرا محدودیت cgroup بهجای حذف کلید (evict)، پردازش را متوقف میکند. اگر Redis در یک کانتینر در کنار وردپرس اجرا میشود، همین عدد باید در محدودیتهای حافظه در فایل Compose قرار گیرد و همین استدلال، تعیینکننده اجرای دیتابیس در Docker یا روی host است.
سیاست تخلیه حافظه (eviction policy) را آگاهانه انتخاب کنید
یک Redis تازه نصبشده بهصورت پیشفرض از noeviction استفاده میکند. تنظیمات خود را بررسی کنید:
redis-cli config get maxmemory-policyدر حالت noeviction، یک نمونه (instance) کامل، پذیرش درخواستهای نوشتن را متوقف کرده و با این خطا پاسخ میدهد:
(error) OOM command not allowed when used memory > 'maxmemory'.این تکخط، بدترین حالت خرابی در این راهنماست، زیرا سایت از دسترس خارج نمیشود؛ بلکه سرعت آن بهشدت کاهش مییابد. هر عملیات نوشتن در کش با شکست مواجه میشود، بنابراین WordPress برای دریافت مقدار به دیتابیس مراجعه میکند، سپس در درخواست بعدی دوباره تلاش میکند آن را ذخیره کند و باز هم شکست میخورد. اکنون سایت علاوه بر تمام پردازشهای دیتابیس اصلی، هزینه یک رفتوبرگشت به Redis را برای هر کلید پرداخت میکند. هیچ بخشی در پنل مدیریت WordPress این وضعیت را گزارش نمیکند. این رشته در لاگ خطاهای PHP ظاهر میشود، بنابراین اگر پس از افزودن کش، سرعت سایت کاهش یافت، عبارت OOM command not allowed را در لاگها جستجو (grep) کنید.
allkeys-lru در اینجا گزینه پیشفرض مناسبی است. Redis در زمان کمبود حافظه، کلیدی که کمترین استفاده اخیر را داشته حذف میکند؛ این دقیقاً همان چیزی است که یک object cache به آن نیاز دارد، زیرا هر مقدار در آن، کپی دادهای است که همچنان در MySQL وجود دارد. از دست دادن یک کلید، هزینه یک کوئری را دارد، اما امتناع از نوشتن، هزینه تمام کوئریها را در هر درخواست تحمیل میکند تا زمانی که کسی متوجه مشکل شود.
از سیاستهای volatile-* برای این کار اجتناب کنید. این سیاستها فقط کلیدهایی را در نظر میگیرند که دارای زمان انقضا (expiry) هستند و مستندات Redis تأیید میکنند که اگر هیچ کلیدی زمان انقضا نداشته باشد، این سیاستها مانند noeviction عمل میکنند. WordPress بیشتر ورودیهای object cache را بدون TTL ذخیره میکند، بنابراین استفاده از volatile-lru برای object cache میتواند باعث پر شدن حافظه و امتناع از نوشتن شود. اگر ترافیک شما بهطور مکرر به مجموعه کوچکی از کلیدها برخورد میکند، allkeys-lfu جایگزین مناسبی است، زیرا حذف را بر اساس فراوانی (frequency) انجام میدهد نه تازگی (recency). یکی را آگاهانه انتخاب کنید و دلیل آن را یادداشت نمایید.
ماندگاری (Persistence): تا زمانی که دلیلی ندارید، آن را غیرفعال نگه دارید
بسته redis.conf قابلیت RDB snapshots را با خطوطی مانند save 900 1 فعال میکند و فایل append-only را غیرفعال میگذارد. برای یک کش شیء (object cache) خالص، اسنپشاتها هیچ سودی ندارند. دادهها طبق تعریف قابل بازسازی هستند و کشی که از یک فایل 20 دقیقهای بازیابی شود، مجموعهای از مقادیر قدیمی است که WordPress به آنها اعتماد خواهد کرد.
اسنپشاتها هزینه هم دارند. BGSAVE فرآیند را fork میکند و مکانیزم copy-on-write باعث میشود هنگام نوشتن توسط فرزند، مصرف حافظه بهشدت افزایش یابد. در یک VPS کوچک، این موضوع در لاگ Redis به این صورت دیده میشود:
Can't save in background: fork: Cannot allocate memoryو اغلب این هشدار در هنگام شروع به کار ظاهر میشود که به شما میگوید احتمالاً fork در آینده با شکست مواجه خواهد شد:
WARNING overcommit_memory is set to 0! Background save may fail under low memory condition.برای غیرفعال کردن اسنپشاتها، یک زمانبندی ذخیرهسازی خالی در /etc/redis/redis.conf تنظیم کنید، سرویس را restart کنید و تأیید کنید که مقدار بازگشتی خالی است.
save ""sudo systemctl restart redis-server
redis-cli config get saveماندگاری را فقط در صورتی حفظ کنید که همان instance دادهای را نگه میدارد که نمیتوانید دوباره بسازید، مانند صفهای کاری (job queue) یا شمارندههای محدودیت نرخ (rate-limit counters). در این صورت، این دو را از هم جدا کنید. کش نیاز به حذف کلیدها (eviction) دارد و دادههای ماندگار نیاز به حفظ کلیدها دارند، و maxmemory به همراه eviction روی کل instance اعمال میشود، نه روی یک ایندکس دیتابیس خاص. داشتن دو instance روی دو socket، راهکار تمیز و اصولی است.
نصب افزونه و درک نحوه عملکرد drop-in
wp plugin install redis-cache --activate
wp redis enable
wp redis statuswp redis enable در صورت موفقیت، Object cache enabled. را چاپ میکند. کاری که این دستور در واقع انجام میدهد، کپی کردن wp-content/plugins/redis-cache/includes/object-cache.php به wp-content/object-cache.php است. آن کپی همان drop-in است و بخش اصلی عملیات توسط همین drop-in انجام میشود. وردپرس فایل 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 بازگردید.
اگر کپی به دلیل مجوزهای دسترسی (permissions) شکست خورد، آن را بهصورت دستی در مسیر مربوطه قرار دهید و مالکیت آن را به کاربر وب واگذار کنید.
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) و مسیر (path) را تنظیم کنید. در این حالت، host و port نادیده گرفته میشوند.
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 بهصورت پیشفرض شانزده پایگاه داده شمارهگذاریشده و یک فضای کلید (keyspace) تخت در هر کدام ارائه میدهد. دو نصب WordPress که به پایگاه داده 0 اشاره میکنند و هیچ پیشوندی ندارند، نام کلیدهای یکسانی را در فضای مشابه مینویسند؛ بنابراین یک سایت میتواند تنظیمات سایت دیگر را بخواند و آنها را ارائه دهد. برای هر سایت یک پیشوند اختصاصی تعیین کنید.
define( 'WP_REDIS_PREFIX', 'shopA_prod:' );
define( 'WP_REDIS_DATABASE', 1 );پیشوند، نام کلیدها را از هم جدا میکند. ایندکس پایگاه داده، فضاهای کلید را جدا میکند که هنگام پاکسازی (flush) اهمیت دارد: خالی کردن یک ایندکس، سایر ایندکسها را دستنخورده باقی میگذارد. افزونه همچنین WP_REDIS_SELECTIVE_FLUSH را مستند کرده است که بهجای کل پایگاه داده، فقط کلیدهای منطبق با پیشوند شما را حذف میکند، هرچند این کار مستلزم اسکن کردن کلیدها است.
آنچه پیشوندها و ایندکسها جدا نمیکنند، حافظه است. maxmemory و سیاست تخلیه (eviction policy) برای کل نمونه (instance) اعمال میشوند؛ بنابراین یک سایت پرمصرف میتواند کلیدهای یک سایت کممصرف را از حافظه خارج کند و هیچکدام از آنها این موضوع را گزارش نمیکنند. سایتهایی که نباید بر یکدیگر تأثیر بگذارند، به نمونههای Redis مجزا نیاز دارند که هر کدام سوکت و محدودیت حافظه خاص خود را داشته باشند.
جلوگیری از تداخل محیط staging با کش محیط production
سایت staging معمولاً نسخهای از فایلها و دیتابیس production است؛ این یعنی کپی از wp-config.php که همان پیشوند (prefix) و همان ایندکس دیتابیس را دارد. اگر آن را به همان Redis متصل کنید، کلیدهای production را با مقادیر staging بازنویسی میکند. در نتیجه، یک قیمت تستی یا یک گزینه تغییریافته بدون هیچ عملیات deploy و بدون ردپایی، در سایت زنده ظاهر میشود.
برای هر محیط بهصورت دستی یک salt تعریف کنید. در فایل wp-config.php محیط staging:
define( 'WP_REDIS_PREFIX', 'shop_staging:' );
define( 'WP_REDIS_DATABASE', 5 );بهتر از آن، برای staging یک instance مجزای Redis در نظر بگیرید یا کلاً object cache را غیرفعال کنید. استفاده از define( 'WP_REDIS_DISABLED', true ); کش را در زمان اجرا (runtime) خاموش میکند و drop-in را در جای خود باقی میگذارد؛ این سریعترین راه برای اثبات این است که آیا یک باگ مربوط به کش هست یا خیر.
آموزشهای قدیمی برای این کار WP_CACHE_KEY_SALT را تنظیم میکردند. در فایل readme این افزونه، آن ثابت (constant) منسوخ شده و با WP_REDIS_PREFIX جایگزین شده است، بنابراین از نام جدید استفاده کنید.
به جای اعتماد کردن، آن را تایید کنید
با ابزارهای تشخیص خودِ افزونه شروع کنید.
wp redis statusخطی که بیشترین اهمیت را دارد Drop-in است. Drop-in: Valid یعنی وردپرس در حال بارگذاری فایل این افزونه است. Drop-in: Not installed یعنی کپیسازی هرگز انجام نشده و سایت هیچ کش پایداری ندارد، هرچقدر هم که صفحه مدیریت سبز و سالم به نظر برسد. Status وضعیت اتصال را گزارش میدهد و Client نام افزونه (extension) در حال استفاده را ذکر میکند؛ این همان جایی است که باید تایید کنید از PhpRedis استفاده میشود نه Predis.
سپس مستقیماً از هسته وردپرس پرسوجو کنید، زیرا برای هسته اهمیتی ندارد که افزونه چه چیزی را گزارش میدهد.
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 معتبر، به این معنی است که اتصال در سکوت شکست میخورد یا پیشوند همان چیزی نیست که شما تصور میکنید.
در نهایت، نگاهی به آنچه Redis برای شما اندازهگیری میکند بیندازید.
redis-cli info stats | grep -E 'keyspace_hits|keyspace_misses|evicted_keys|expired_keys'نرخ اصابت (hit ratio) برابر با keyspace_hits / (keyspace_hits + keyspace_misses) است و مستندات Redis آن فرمول را ارائه میدهد. آن را با دو هشدار بخوانید. شمارندهها کل instance را از زمان آخرین راهاندازی مجدد پوشش میدهند، بنابراین همه سایتها و برنامههایی که از آن استفاده میکنند را با هم ترکیب میکنند. همچنین، نرخ بلافاصله پس از یک flush یا راهاندازی مجدد معنایی ندارد، زیرا کش هنوز در حال پر شدن است. اجازه دهید یک روز کاری عادی با ترافیک معمولی سپری شود.
عدد خود را با نرخ اصابت یا تعداد کوئریهای منتشر شده توسط یک شرکت میزبانی مقایسه نکنید. آن ارقام توصیفکننده سایتها و مجموعه افزونههای خودشان است. رقمی که اهمیت دارد، رقم خود شماست که قبل و بعد از فعالسازی، در صفحهای که کش صفحه (page cache) قادر به سرویسدهی آن نیست، اندازهگیری شده باشد.
curl -o /dev/null -s -w '%{time_starttransfer}\n' -b cookies.txt https://example.com/my-account/آن را با یک کوکی لاگین، چندین بار، با کش خاموش (WP_REDIS_DISABLED) و سپس روشن اجرا کنید. تفاوت حاصل، نتیجه واقعی شماست.
زمانی که Redis باعث کندی WordPress میشود
یک نمونه کامل با سیاست اشتباه، عامل اصلی است که در بالا به آن پرداخته شد: OOM command not allowed when used memory > 'maxmemory'. در لاگ، و سایتی که هم برای دیتابیس و هم برای کش هزینه میکند.
Redis روی یک میزبان دیگر، عامل دوم است. WordPress در هر درخواست، صدها فراخوانی object cache انجام میدهد. اگر یک درخواست 500 فراخوانی داشته باشد و هر رفتوبرگشت 1 میلیثانیه زمان ببرد، این یعنی نیم ثانیه انتظار که در صورت استفاده از سوکت محلی وجود نداشت. Redis را روی همان سرور نگه دارید یا از یک شبکه خصوصی با تأخیر زیر یک میلیثانیه استفاده کنید.
یک جدول options با حجم autoload بالا، عامل سوم است که در سایتهای قدیمی رایج است. WordPress تمام گزینههای autoload را به عنوان یک کلید واحد کش میکند، بنابراین در هر درخواست، یک مگابایت داده از شبکه عبور میکند. آن را اندازهگیری کنید:
wp db query "SELECT ROUND(SUM(LENGTH(option_value))/1024) AS kb FROM wp_options WHERE autoload IN ('yes','on','auto','auto-on');"نسخه 6.6 از WordPress مقادیر autoload جدیدی اضافه کرده است، بنابراین یک کوئری قدیمی که فقط 'yes' را مطابقت میدهد، در نصبهای مدرن گزارش ناقصی ارائه میدهد. هر چیزی بیش از یک مگابایت، مشکلی است که باید در جدول options حل شود، نه در Redis.
راهاندازی مجدد (restart)، همه چیز را خالی میکند، بنابراین دقایق پس از systemctl restart redis-server تماماً شامل miss و فعالیت دیتابیس است. زمانی که ترافیک کم است، سرویس را restart کنید. همچنین یک object cache مانع از اجرای wp-cron.php در هنگام بارگذاری صفحات توسط بازدیدکنندگان نمیشود، که خود منبعی برای درخواستهای کند است: انتقال WP-Cron به یک job سیستمی cron در حالی که در اینجا مشغول هستید.
نگهداری سیستم
پس از هر استقرار (deploy) که گزینهها یا کدهای پوسته (theme) را تغییر میدهد، با استفاده از wp cache flush حافظه موقت را پاکسازی کنید. اگر پس از بهروزرسانی یک افزونه، فایل drop-in بهطور خودکار بهروز نشد، حتماً wp redis update-dropin را اجرا کنید؛ چرا که استفاده از یک drop-in متعلق به نسخه قدیمی افزونه در کنار نسخه جدید، منبع اصلی رفتارهای غیرعادی است. برای نظارت بر سرور در لحظه، از redis-cli --stat استفاده کنید که در هر ثانیه یک خط خروجی چاپ میکند. دستور redis-cli monitor تمام دستورات را چاپ میکند و در نمونههای (instance) پرمشغله، بار پردازشی (CPU) قابلتوجهی ایجاد میکند؛ بنابراین فقط برای چند ثانیه جهت بازتولید یک مشکل از آن استفاده کرده و سپس متوقفش کنید.
یک عدد دیگر که دانستن آن مفید است: redis-cli info clients وضعیت connected_clients را گزارش میدهد. PHP-FPM به ازای هر worker یک اتصال نگه میدارد، بنابراین این عدد باید با pm.max_children شما همخوانی داشته باشد و نباید از آن به میزان یک مرتبه بزرگی (order of magnitude) بیشتر شود. اگر چنین شد، یعنی فرآیندی در حال باز کردن اتصالات است و آنها را نمیبندد.
FAQ
آیا با وجود Redis object cache همچنان به page cache نیاز دارم؟
بله، برای ترافیک ناشناس. یک page cache فایلهای HTML ذخیرهشده را بدون اجرای PHP ارائه میدهد که همیشه از اجرای وردپرس با یک object cache گرم، کمهزینهتر است. object cache به درخواستهایی رسیدگی میکند که page cache باید از آنها صرفنظر کند: کاربران واردشده، سبد خرید، تسویه حساب و wp-admin. در یک فروشگاه یا سایت عضویتمحور، استفاده از هر دو توصیه میشود. در سایتی که بازدیدکنندگان هرگز وارد نمیشوند، page cache تقریباً تمام کار را انجام میدهد.
برای وردپرس چه مقدار حافظه به Redis اختصاص دهم؟
این مقدار را بر اساس سرور خود تعیین کنید، نه با کپی کردن یک عدد ثابت. کل RAM را در نظر بگیرید، MySQL buffer pool و بافرهای هر اتصال را از آن کم کنید، pm.max_children ضربدر اندازه مقیم (resident size) یک worker از PHP-FPM را کسر کنید، و چند صد مگابایت برای هسته سیستمعامل و وبسرور کنار بگذارید. بخشی از باقیمانده را به Redis اختصاص دهید، سپس پس از یک روز ترافیک، used_memory_human را در redis-cli info memory بررسی کرده و تنظیمات را اصلاح کنید. یک سایت وردپرسی معمولاً به دهها مگابایت حافظه نیاز دارد، بنابراین یک maxmemory با حجم 256 MB برای شروع در یک سرور 4 GB مقدار سخاوتمندانهای است.
چرا پس از فعالسازی Redis object cache، سایت من کندتر شد؟
دلیل معمول، پر شدن instance و اجرای سیاست noeviction است. Redis نوشتنهای جدید را رد کرده و OOM command not allowed when used memory > 'maxmemory'. برمیگرداند، بنابراین وردپرس برای هر مقدار به دیتابیس بازمیگردد و علاوه بر آن، یک رفتوبرگشت بیهوده به Redis نیز متحمل میشود. redis-cli config get maxmemory-policy را بررسی کنید، allkeys-lru را تنظیم نمایید و مطمئن شوید که maxmemory مقدار بسیار کمی نباشد. دلایل رایج دیگر، قرار داشتن سرور Redis روی یک میزبان راه دور است که در آن صدها رفتوبرگشت در هر درخواست جمع میشوند، و همچنین وجود یک مقدار autoloaded options چند مگابایتی که در هر درخواست از طریق شبکه منتقل میشود.
آیا چندین سایت وردپرسی میتوانند از یک سرور Redis مشترک استفاده کنند؟
بله، با رعایت احتیاط. به هر سایت یک WP_REDIS_PREFIX منحصربهفرد اختصاص دهید تا نام کلیدها با هم تداخل نداشته باشد، و یک ایندکس WP_REDIS_DATABASE جداگانه تعیین کنید تا پاکسازی (flush) یک سایت، دادههای سایت دیگر را حذف نکند. آنچه همچنان مشترک باقی میماند حافظه است: maxmemory و سیاستهای حذف (eviction) برای کل instance اعمال میشوند، بنابراین یک سایت پربازدید میتواند کلیدهای یک سایت کمترافیک را حذف کند. سایتهایی که نباید بر یکدیگر تأثیر بگذارند، به instanceهای جداگانه Redis با محدودیتهای خاص خود نیاز دارند.
آیا حذف فایل wp-content/object-cache.php ایمن است؟
بله. این یک فایل drop-in است و بخشی از هسته وردپرس نیست؛ حذف آن باعث میشود وردپرس به کش داخلی و مبتنی بر هر درخواست (per-request) خود بازگردد. سایت به کار خود ادامه میدهد و صرفاً کوئریهای دیتابیس بیشتری انجام میدهد. استفاده از wp redis disable را ترجیح دهید، زیرا فایل را بهتمیزی حذف کرده و Object cache disabled. را گزارش میدهد. اگر Redis از دسترس خارج شده یا دچار اختلال است و به پنل مدیریت دسترسی ندارید، حذف دستی این فایل اقدام اضطراری درستی است.