Redis-кластер с балансировкой на nginx

Эта статья больше является обзорной, а по факту - перевод официальной документации :-)

Redis - очень быстрая база данных типа ключ-значение. А также она является message broker, а именно Publish/Subscription и очереди сообщений.

Если вдруг понадобилось организовать кластер из Redis, то необходимо знать как его создать, как им управлять и как повысить его доступность. Здесь я буду приводить все примеры с использованием Docker.

Запуск Redis нод

Для организации всего в Docker используется последняя стабильная на данный момент версия Redis ветки 3.2. Для упрощения настройки кластера на одной машине все контейнеры будут запускаться с настройки сети хоста.

Предварительно желательно уже иметь образ redis. Для этого запускаем docker pull redis. Подготавливаем скрипт, который запустит необходимое количество нод redis'а и запускаем его.

В скрипте указано запустить 10 контейнеров и начинать привязывать порт каждого начиная с 7000. Каждому контейнеру устанавливается somaxconn в 65535, что позволит создать для каждого контейнера 65535 соединений (по умолчанию docker выставляет для контейнеров 128 подключений) и указывается, что используется сеть хост-системы.

Так же указан ряд параметров для самого redis-server:

  • cluster-enabled включает режим кластера
  • cluster-config-file указывает где хранить настройки кластера
  • cluster-node-timeout выставленный в 2000 указывает, что нода будет помечена failed в случае отсутствия ответа в течении 2000 мс
  • maxclients указывает максимальное количество клиентских подключений и выставлен на 65535, чтобы изменить умолчание в 10000
  • appendonly выключен, чтобы в принципе исключить работу с жестким диском (в условиях моего использования необходимо именно такое поведение)
  • deamonize тоже выключен, чтобы процесс висел активным и контейнер продолжал работать пока выполняется процесс

В результате выполнения этого скрипта получим примерно такой выхлоп:

В конце видим строку с набором <ip>:<port>, она нам нужна для объединения всех redis-контейнеров в кластер.

Объединение redis-нод в кластер

Для объединения всех нод в кластер будем использовать утилиту, которая находится в исходных кодах redis-сервера - redis-trib.rb. Для её запуска необходим интерпретатор Ruby и gem redis. Для установки gem'а выполним эту команду sudo gem install redis.

Теперь необходимо запустить эту утилиту с указанием строки <ip>:<port> из выхлопа прошлого скрипта:

Кластер готов. Для просмотра его состояния можно выполнить команду watch -n1 redis-cli -p 7009 cluster nodes.

Изменение количества нод в кластере

Добавление нод

Для добавления ноды в кластер необходимо запустить новую ноду в режиме кластера и воспользоваться ранее указанным скриптом redis-trib.rb, указав адрес новой ноды и адрес одной из нод кластера:

С помощью этой команды была добавлена нода в режиме master. Желательно ноде иметь как минимум одину реплику.

Добавим реплику к этой ноде указав id мастера(новую добавленую ноду, подсмотреть можно с помощью cluster nodes при подключении к кластеру):

После перенесем некоторую часть слотов с одной ноды на новую:

Удаление нод

Удаление ноды из кластера выполняется простой командой:

Где 192.168.51.69:7001 адрес для доступа к кластеру (любой из существующих), а 78a54e33af901a153f62497f653e53179c12c49a идентификатор удаляемой ноды (можно подсмотреть подключившись к кластеру и выполнив команду cluster nodes).

Удаление произойдет сразу в случае если на ноде отсутствуют слоты. Выше удалялась нода, которая является репликой для ноды 355c2b091daa3e327798db415d639e02820cf339.

Теперь попробуем удалить ее:

Необходимо перенести обрабатываемые слоты на другие ноды. Я буду переносить сразу все с лоты с одной ноды на другую, чтобы не заморачиваться равномерным распределением слотов по каждому из мастеров:

После подробного указания каждой перенесенной ноды процесс заканчивается и мы можем удалить освобожденную ноду из кластера:

После проверим, что кластер работает нормально:

Балансировка между нодами кластера

Для балансировки tcp-соединений я буду использовать nginx (опять же в docker контейнере). Своеобразная замена redis-sentinel.

Первоначально необходимо написать конфигурацию nginx:

И теперь можно запустить контейнер с nginx: docker run -itd --name tcp-balancer --network=host -v ${PWD}/nginx.conf:/etc/nginx/nginx.conf:ro nginx

nginx с такой конфигурацией можно поднять на каждой физической машине, которая обслуживает redis-ноду.

comments powered by Disqus