Перейти до вмісту
EuroVPSEuroVPS

Як під’єднати PHP до Valkey Sentinel і довести, що failover працює

Реплікований кеш допомагає лише тоді, коли PHP іде за promotion. Як налаштувати Sentinel, під’єднати WordPress і Laravel, обрати політику витіснення.

Автор EuroVPS Engineering

5 хв читання
Wiring PHP to Valkey Sentinel, and proving the failover works

Чимало сайтів використовують реплікований кеш Redis або Valkey і все одно падають, коли гине primary, бо застосунок спрямований на одну фіксовану адресу. Репліки на місці, Sentinel підвищує одну з них, а PHP продовжує стукати у двері мертвого сервера. Ось як побудувати кеш так, щоб failover справді доходив до застосунку, і як довести це до того, як він вам знадобиться.

Чому кеш є частиною вашої доступності

Object cache зберігає обчислені результати: опції, меню, сесії, результати запитів, відрендерені фрагменти. На завантаженому сайті на WordPress, Magento або Laravel він поглинає більшу частину читального навантаження бази даних. Втратьте його, і кожен запит одразу повертається до бази даних. Базу даних ніколи не розраховували на це, тому сайт за лічені хвилини сповільнюється до повзання. Тож один інстанс кешу є єдиною точкою відмови, хоча й не містить нічого, чого не можна відбудувати.

Форма: один primary, дві репліки, три Sentinel

Запустіть три вузли кешу на трьох окремих хостах: один primary і дві репліки. Поруч із кожним запустіть процес Sentinel. Sentinel спостерігають за primary, домовляються між собою, коли його немає, підвищують репліку і відповідають на запитання, яке потрібне кожному клієнту: де зараз primary?

На кожній репліці:

replicaof <primary-address> 6379
masterauth <secret>
requirepass <secret>

І на кожному з трьох Sentinel:

sentinel monitor cache <primary-address> 6379 2
sentinel auth-pass cache <secret>
sentinel down-after-milliseconds cache 5000
sentinel failover-timeout cache 30000
sentinel parallel-syncs cache 1

2 у рядку monitor є кворумом: два з трьох Sentinel мають погодитися, що primary впав, перш ніж почнеться failover. Саме тому їх три, на трьох різних хостах.

down-after-milliseconds є компромісом між швидкістю та обережністю. Ми тримаємо його коротким. Непотрібний failover коштує кількох секунд промахів кешу; довге очікування з мертвим primary коштує бази даних, що повзе.

Крок, який пропускають: клієнти, що питають Sentinel

Клієнт, налаштований на адресу primary, ніколи не дізнається про promotion. Застосунок має з’єднуватися через Sentinel, за ім’ям сервісу, і питати про поточний primary.

З phpredis напряму:

$sentinel = new RedisSentinel(['host' => '<sentinel-1>', 'port' => 26379]);
[$host, $port] = $sentinel->getMasterAddrByName('cache');
$redis = new Redis();
$redis->connect($host, (int) $port);
$redis->auth('<secret>');

Робочий код має пробувати кожен Sentinel по черзі, бо будь-який з них може бути на хості, який щойно відмовив.

Для WordPress широко вживаний drop-in Redis Object Cache підтримує Sentinel нативно у wp-config.php:

define('WP_REDIS_CLIENT', 'phpredis');
define('WP_REDIS_SENTINEL', 'cache');
define('WP_REDIS_SERVERS', [
    'tcp://<sentinel-1>:26379',
    'tcp://<sentinel-2>:26379',
    'tcp://<sentinel-3>:26379',
]);
define('WP_REDIS_PASSWORD', '<secret>');

Laravel, через Predis, приймає список Sentinel і дві опції у config/database.php:

'redis' => [
    'client' => 'predis',
    'default' => [
        'tcp://<sentinel-1>:26379',
        'tcp://<sentinel-2>:26379',
        'tcp://<sentinel-3>:26379',
        'options' => ['replication' => 'sentinel', 'service' => 'cache'],
    ],
],

Коли це на місці, promotion не потребує ні зміни конфігурації, ні перезапуску PHP.

Пам’ять: обмежте її і виберіть, кого витісняти

Кеш, який росте, доки не втрутиться OOM killer ядра, відмовив у найгірший можливий спосіб. Установіть maxmemory у фіксовану частку RAM вузла, залишивши місце для буферів реплікації та fork, який використовується для persistence, і свідомо оберіть політику витіснення:

  • allkeys-lru для чистого кешу. Коли пам’ять заповнена, іде найдавніше використаний ключ, яким би він не був. Це правильно для object cache.
  • volatile-lru, якщо інстанс також тримає ключі без терміну дії, які ніколи не можна витісняти, як-от сесії. Кандидатами є лише ключі з TTL.

Ще краще тримати сесії та object cache окремо. Деплой, який скидає object cache, ніколи не повинен розлогінювати кожного клієнта. У спільному кластері дайте кожному сайту щонайменше власну логічну базу даних; великим або критичним сайтам дайте власний інстанс, щоб скидання одного сайту або некероване зростання його ключів не могло спустошити кеші сусідів.

Доведіть: убийте primary навмисно

Failover, за яким ви не спостерігали, є надією. Перед передачею ми запускаємо це з під’єднаним застосунком і живим трафіком:

# 1. Who is primary right now?
valkey-cli -p 26379 SENTINEL get-master-addr-by-name cache

# 2. Watch the site from outside, timestamped
while true; do
  printf '%s ' "$(date +%T.%N)"
  curl -s -o /dev/null -w '%{http_code} %{time_total}\n' https://www.example.com/
  sleep 0.5
done | tee cache-failover.log

# 3. On the primary's host, stop the cache service
systemctl stop valkey

# 4. Watch the Sentinel log for +switch-master, then ask again
valkey-cli -p 26379 SENTINEL get-master-addr-by-name cache

(З Redis команди ті самі під redis-cli.)

Запишіть три речі: скільки часу минуло до появи +switch-master, скільки до повернення таймінгів сторінок до норми і чи хоч один запит зазнав невдачі, а не просто сповільнився. Здорова збірка підвищує репліку за кілька секунд, і PHP іде за цим без чийогось втручання. Потім знову запустіть старий primary і підтвердьте, що він приєднується як репліка нового, а не як другий primary.

Для м’якшої репетиції, яка не зупиняє сервіс, SENTINEL FAILOVER cache примусово виконує promotion на вимогу. Корисно для тестування клієнтського боку; менш корисно для тестування виявлення, яке є тим, що має значення поганої ночі.

Ваш чекліст

  • Три вузли кешу і три Sentinel на трьох окремих хостах, кворум два.
  • Автентифікація ввімкнена, і кеш досяжний лише з вебрівня, який його використовує.
  • Кожен застосунок з’єднується через Sentinel за ім’ям сервісу, а не з фіксованою адресою.
  • maxmemory встановлено і політику витіснення обрано під те, що тримає інстанс.
  • Сесії відокремлені від object cache; великі сайти ізольовані від малих.
  • Записаний тест failover з під’єднаним застосунком, включно з поверненням старого primary.

Якщо ви хочете, щоб ми налаштували або протестували ваш рівень кешу, ми радо це зробимо.

Поговоріть з інженером

Related (rows[1])

Пов’язане: Object caching з автоматичним failover · Вебрівні високої доступності, N+1 на кожному рівні · Побудова платформ високої доступності

Опубліковано 18 серпня 2026 р..

Усі нотатки з практики