В прошлом уроке мы окинули взглядом специальные структуры Redis. Прежде чем разбирать их по одной, поднимем голову от команд. До сих пор у нас был один сервер на ноутбуке. Магазин уже держит в Redis кэш книг, корзины, сессии и очередь писем. Что будет, если этот сервер выключится, если данным станет тесно в памяти или если к нему подключится кто-то чужой? Этот урок обзорный: он показывает карту, а подробные уроки про каждую часть ждут в конце раздела.
Магазин с одним продавцом
Представь книжный магазин, где работает один продавец. Пока он на месте, всё хорошо. Заболел, и магазин закрыт. Это первая беда: одна точка отказа.
Хозяин нанимает помощника, который стоит рядом и запоминает каждую продажу. Если продавец заболел, помощник встаёт за кассу. Но кто решит, что продавец действительно заболел, а не вышел на минуту? Нужен управляющий, который следит за обоими и, если надо, назначает нового продавца.
Магазин растёт, и одному продавцу уже не справиться с очередью, а книги не помещаются на полки. Тогда открывают несколько отделов: художественная литература в одном, учебники в другом, и у каждого свой продавец.
У Redis те же три шага: реплика как помощник, Sentinel как управляющий и Cluster как отделы.
Реплика: копия на случай беды
Основной сервер называют master, копию replica. Реплику запускают с указанием, с кого копировать. Вот два контейнера на одной сети Docker, второй следит за первым:
docker network create shop
docker run -d --name redis-main --network shop redis:7
docker run -d --name redis-replica --network shop redis:7 redis-server --replicaof redis-main 6379
Первые секунды после старта реплика скачивает у основного сервера все данные, потом получает изменения по мере записи. Пишем в основной, читаем с реплики:
$ docker exec -it redis-main redis-cli SET book:1:title "Master and Margarita"
OK
$ docker exec -it redis-replica redis-cli GET book:1:title
"Master and Margarita"
$ docker exec -it redis-replica redis-cli SET book:1:title x
(error) READONLY You can't write against a read only replica.
Реплика получила ключ почти сразу, а писать в неё нельзя. Все записи идут в основной сервер, а читать можно с любого. Команда ROLE подскажет, кто есть кто:
127.0.0.1:6379> ROLE
1) "slave"
2) "redis-main"
3) (integer) 6379
4) "connected"
5) (integer) 178
Это ответ реплики: «я копия, мой основной сервер redis-main на порту 6379, связь есть». Последнее число показывает, сколько байт изменений реплика уже получила. Слово slave осталось в ответах Redis с давних времён, в документации теперь пишут replica.
Важная деталь: репликация в Redis асинхронная. Основной сервер отвечает OK, не дожидаясь реплик. Если он упал через миллисекунду после записи, реплика могла её не получить. Для кэша это не страшно, а для денег Redis главным хранилищем не делают, мы говорили об этом в первом уроке.
Реплика также не заменяет бэкап. Команда FLUSHALL, случайно выполненная на основном сервере, тут же очистит и реплику. Сохранение на диск разобрано в уроке про RDB и AOF.
Sentinel: кто назначит нового главного
Реплика есть, но если основной сервер упал, сама она главной не станет. Кто-то должен заметить падение и переключить приложение на реплику. Это и делает Sentinel: три или больше процессов-наблюдателей, которые раз в секунду проверяют серверы. Когда большинство наблюдателей согласны, что основной сервер не отвечает, они выбирают реплику и делают её основной. Это называется переключением при отказе.
Приложение при этом спрашивает адрес основного сервера не у себя в конфиге, а у Sentinel. Клиенты вроде node-redis умеют это сами. Наблюдателей должно быть нечётное число от трёх: так они не разделятся пополам в споре, жив сервер или нет.
урок из курса
Урок из курса «Redis с нуля». Курс покупается один раз и остаётся навсегда: 500 ₽.
Оплата пока не подключена: премиум и курсы открываются промокодом.