Реализация отказоустойчивого Redis в рамках горизонтального масштабирования DirectumRX

В случае применения горизонтального масштабирования сервисных служб DirectumRX необходимо использовать отказоустойчивую инсталляцию Redis для сервисных служб сервис хранилищ DirectumRX. В статье рассмотрим наиболее простой вариант реализации.




Введение в решаемую задачу




Redis – это система управления базами данных класса NoSQL (не реляционные СУБД), размещаемых целиком в оперативной памяти. Для доступа к данным используется модель «ключ» — «значение». Такая СУБД используется зачастую для хранения кэшей в масштабируемых сервисах, для хранения изображений и данных небольшого размера.




Широкое распространение СУБД Redis получила за счет:




  • высокой скорости работы, т.к. все данные хранятся в оперативной памяти,



  • кроссплатформенности,



  • распространению по BSD лицензии (относится к СПО).




Широту распространения и применимость Redis можно оценить по огромному количеству документации со всевозможными кейсами на официальном сайте проекта: https://redis.io/documentation.




В случае применения горизонтального масштабирования сервисных служб DirectumRX необходимо использовать отказоустойчивую инсталляцию Redis для корректной работы с сервисом хранилищ DirectumRX и сервисом веб-доступа DirectumRX.







В Redis будут храниться оперативные данные, кэши и прочая информация, которая необходима для работы служб, находящихся в режиме масштабирования, чтобы процесс взаимодействия пользователя с системой не зависел от инсталляции, с которой в текущий момент он работает.




В конфигурационных файлах служб необходимо указать необходимые параметры для подключения к Redis.




Для web-доступа:




<var name="ENABLE_SCALING" value="True"/>
<var name="REDIS_HOST" value="RedisHost"/>
<var name="REDIS_PORT" value="6379"/>




Для сервиса хранилищ:




<var name="STORAGE_SERVICE_ENABLED_SCALING" value="True" />
<var name="STORAGE_SERVICE_REDIS_HOST" value="RedisHost" />
<var name="STORAGE_SERVICE_REDIS_PORT" value="6379" />




ENABLE_SCALING и STORAGE_SERVICE_ENABLED_SCALING — признак включения горизонтального масштабирования.




REDIS_HOST и STORAGE_SERVICE_REDIS_HOST — путь до компьютера, на котором развернут экземпляр службы Redis. 




REDIS_PORT и STORAGE_SERVICE_REDIS_PORT — порт, по которому сервис взаимодействует со службой Redis. Значение по умолчанию 6379.




Разворачивание отказоустойчивого Redis 




На официальном сайте Redis выделяется 2 способа обеспечения отказоустойчивости:




  1. Использование Redis Sentiel (https://redis.io/topics/sentinel).



  2. Использование Redis Cluster (https://redis.io/topics/cluster-spec).




Redis Sentiel




Вариант с использованием Redis Sentiel (Следящий узел Redis) был реализован в версии Redis 2.4 и состоит в том, что для мониторинга доступности мастера используется дополнительный сервис Redis Sentiel. Он же выполняет настройку узлов реплик, в случае выхода из строя мастера. Определяет какой из SLAVE узлов станет MASTER и выполнит перенастройку на ходу.




Реализует классическую схему:







SLAVE-узлов может быть множество (до 1000 по данным с официального сайта), для продуктивной работы рекомендуется использовать не менее двух SLAVE-узлов.




Обычно схема настраивается таким образом, что на MASTER- и на SLAVE-узлах настраивается сервис Redis Sentiel и при выходе из строя MASTER-узла, оставшиеся следящие узлы принимают решение о введении в работу нового MASTER.




Redis Cluster




Вариант кластеризации Redis Cluster реализован для версии redis 3.0 и выше, является решением для создания и управления кластером с сегментацией и репликацией данных. Выполняет задачи управления узлами, репликации, синхронизации данных на узлах и обеспечения доступа клиентского приложения к MASTER-узлу в случае выхода из строя одного из нескольких MASTER-узлов.







Redis Cluster наиболее надежный вариант. Работает в режиме мультимастера, у каждого MASTER-узла может быть один или более SLAVE-узлов (до 1000).




Представленная схема требует, как минимум 3-6 узлов. Запросы перенаправляются от клиентов на нужный MASTER или SLAVE — но это требует поддержки режима кластера Redis самим клиентским приложением.




В данной статье будем рассматривать наиболее простой вариант – Redis Sentiel.




Создание отказоустойчивой инсталляций по схеме Redis Sentiel




Актуальная версия Redis доступна для скачивания с официального сайта разработчика продукта https://redis.io/download. Однако на сайте доступен дистрибутив только для ОС Linux. В своё время развивался проект Microsoft по портированию Redis на ОС Windows (https://github.com/MicrosoftArchive/Redis), однако в настоящее время проект остановил развитие на версии 3.2.100, поэтому в данной статье будем рассматривать наиболее актуальный вариант разворачивания – на ОС Linux.




В качестве тестовых узлов будем использовать два виртуальных хоста redis1 и redis2 с установленным дистрибутивом Linux Debian 10.




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




1. Создадим файл /etc/apt/sources.list.d/dotdeb.list и пропишем адреса репозитория:




deb http://packages.dotdeb.org stable all
deb-src http://packages.dotdeb.org stable all




2. Получим GPG-ключ для работы с репозиторием:




wget https://www.dotdeb.org/dotdeb.gpg
apt-key add dotdeb.gpg 




При необходимости, устанавливаем дополнительные компоненты:




apt install gnupg




3. Устанавливаем Redis:




apt install redis-server




Проверим версию:




root@redis1:/home/user# redis-server -v
Redis server v=5.0.3 sha=00000000:0 malloc=jemalloc-5.1.0 bits=64 build=afa0decbb6de285f




Пусть redis1 будет выступать в качестве MASTER-узла, а redis2 – в качестве SLAVE-узла.




Для этого в конфигурационных файлах Redis пропишем необходимые параметры, которые позволят создать реплику (пока не отказоустойчивую).




Для redis1 в конфигурационном файле /etc/redis/redis.conf указываем:




#указываем пароль, по которому MASTER будет разрешать работать с ним.
requirepass TestPass 




Для redis2  в конфигурационном файле /etc/redis/redis.conf указываем:




# Указываем адрес MASTER и порт.
slaveof redis1 6379 
# Указываем пароль для работы с мастером.
masterauth TestPass 
# Также указываем пароль, чтобы с узлом можно было работать только по паролю.
requirepass TestPass 




Выполним перезапуск сервисов redis-server на обоих узлах:




root@redis1:/etc/redis# /etc/init.d/redis-server stop
[ ok ] Stopping redis-server (via systemctl): redis-server.service.
root@redis1:/etc/redis# /etc/init.d/redis-server start
[ ok ] Starting redis-server (via systemctl): redis-server.service.

root@redis2:/etc/redis# /etc/init.d/redis-server stop
[ ok ] Stopping redis-server (via systemctl): redis-server.service.
root@redis2:/etc/redis# /etc/init.d/redis-server start
[ ok ] Starting redis-server (via systemctl): redis-server.service.




Проверяем на стороне MASTER, что узлы стали репликами и получили необходимые роли:




root@redis1:/etc/redis# redis-cli -a TestPass info replication
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.9.96,port=6379,state=online,offset=28,lag=0
master_replid:56b0a702d5823d107b0ca1ca2c80f8ef650a4b28
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:28
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:28




На стороне SLAVE видим такую же ситуацию:




root@redis2:/etc/redis# redis-cli -a TestPass info replication
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Replication
role:slave
master_host:redis1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:4
master_sync_in_progress:0
slave_repl_offset:14
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:56b0a702d5823d107b0ca1ca2c80f8ef650a4b28
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:14
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:14




Теперь необходимо настроить реплику таким образом, чтобы она автоматически восстанавливалась в случае выхода из строя одного из узлов. Для этого нам понадобиться следящий сервис Redis Sentinel.




Исходя из документации https://redis.io/topics/sentinel, следящий сервис Redis Sentinel умеет выполнять следующие операции:




  1. Мониторинг: следящий узел проверяет доступность MASTER и SLAVE узлов и способен оправлять оповещения о недоступности узлов.



  2. Обеспечение отказоустойчивости: если MASTER-узел вышел из строя, следящий узел может перевести SAVE-узел в режим MASTER, а также перенастраивает остальные SLAVE-узлы, и они начинают работать с новым MASTER.



  3. Управление конфигурациями. Конфигурирует узлы MASTER и SLAVE.




Разместим для чистоты эксперимента следящий сервис на отдельную ВМ redis3. 




Подключаем аналогичным способом репозиторий Redis и устанавливаем пакет redis-sentinel:




apt install redis-sentinel 




После установки необходимо внести настройки в конфигурационный файл следящего узла /etc/redis/sentinel.conf:




# Настраиваем мониторинг узла redis1 по порту 6379. 
# Последняя цифра 1 - означает количество следящих узлов в кворуме, 
# мнение которых учитывается в случае необходимости изменить MASTER-узел.
# То есть можно поднять несколько следящих узлов, 
# которые будут выполнять мониторинг MASTER-узла.
sentinel monitor master01 redis1 6379 1

# Ждем 3 секунды, прежде чем принимать решение о сбое узла.
sentinel down-after-milliseconds master01 3000

# Зададим таймаут восстановления MASTER-узла
sentinel failover-timeout master01 6000

# Указываем сколько SLAVE-узлов необходимо перенастраивать одновременно. 
# Необходимо указывать минимальное количество, чтобы не получилось так, 
# что все реплики станут недоступны одновременно.
sentinel parallel-syncs master01 1

# Обязательно прописываем прослушиваемые порты.
bind 192.168.9.97 127.0.0.1 ::1

# И прописываем пароль MASTER-узла.
sentinel auth-pass master01 TestPass




Перезапустим сервис после внесения настроек:




root@redis3:/etc/redis# /etc/init.d/redis-sentinel restart
[ ok ] Restarting redis-sentinel (via systemctl): redis-sentinel.service.




Проверим, что следящий сервис увидел MASTER и SLAVE:




root@redis3:/etc/redis# redis-cli -p 26379 info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=master01,status=ok,address=192.168.9.95:6379,slaves=1,sentinels=1




Начинаем эксперименты.




Сымитируем сбой, остановим сервис redis-server на узле redis1 и получим ткущую информацию следящего узла:




root@redis3:/etc/redis# redis-cli -p 26379 info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=master01,status=ok,address=192.168.9.96:6379,slaves=1,sentinels=1




Видим, MASTER поменялся.




Восстановим работу узла redis1 и проверим его состояние: 




root@redis3:/var/log/redis# redis-cli -h redis1 -p 6379 -a TestPass info replication
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Replication
role:slave
master_host:192.168.9.96
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:15977
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:6c0c7d0eedccede56f211f2db74a98c4d0ff6d56
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:15977
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:15977




Видим, что узел получил роль SLAVE, а узел redis2 является MASTER-узлом.




Сымитируем сбой узла redis2 и проверим состояние следящего узла:




root@redis3:/var/log/redis# redis-cli -p 26379 info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=master01,status=ok,address=192.168.9.95:6379,slaves=1,sentinels=1




И состояние узла redis1:




root@redis3:/var/log/redis# redis-cli -h redis1 -p 6379 -a TestPass info replication
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Replication
role:master
connected_slaves:0
master_replid:6e9d67d6460815b925319c2bafb58bf2c435cffb
master_replid2:6c0c7d0eedccede56f211f2db74a98c4d0ff6d56
master_repl_offset:33610
second_repl_offset:26483
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:33610




Отлично, механизм работает. Но теперь возникла проблема, как мы будем подключать наши сервисы DirectumRX, ведь для них нужен адрес единственного узла. Решим вопрос с помощью сервисной службы HAProxy.




Проксирование обращения к узлам Redis




В качестве reverse-прокси для узлов Redis может выступать любой проксирующий tcp-сервис. В данной статье рассмотрим использование HAProxy поскольку это специализированный инструмент предназначенный для обеспечения высокой доступности и балансировки нагрузки и используется повсеместно известными онлайн сервисами. Подробнее о HAProxy можно почитать на странице разработчика http://www.haproxy.org/#desc




Установим HAProxy на узел redis3:




root@redis3:/var/log/redis# apt search haproxy




В конфигурационный файл HAProxy /etc/haproxy/haproxy.cfg, добавим настройки для проксирования запросов к узлам Redis:




…
frontend ft_redis
        bind *:6379 name redis
        mode tcp
        default_backend bk_redis

backend bk_redis
        mode tcp
        option tcp-check
        tcp-check connect
        # Не забываем, что все узлы принимают запросы только при наличии пароля.
        tcp-check send AUTH TestPassrn
        tcp-check expect string +OK
        tcp-check send PINGrn
        tcp-check expect string +PONG
        tcp-check send info replicationrn
        # Работаем только с MASTER, т.к. SLAVE по умолчанию работает только на чтение.
        tcp-check expect string role:master
        tcp-check send QUITrn
        tcp-check expect string +OK
        server Redis1 redis1:6379 check inter 3s
        server Redis2 redis2:6379 check inter 3s




В данной конфигурации указано, что проксировать будем любые запросы, приходящие на все интерфейсы текущей виртуальной машины по адресу на порт 6379. Запросы будем передавать на узел, который ответит, что он имеет роль MASTER.




Перезапустим сервис haproxy:




root@redis3:/etc/haproxy# /etc/init.d/haproxy restart




Попробуем подключиться с помощью клиента redis-cli и создадим тестовый ключ:




root@redis3:/etc/haproxy# redis-cli -p 6379 -a TestPass
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> SET TestKey "Some test string"
OK
127.0.0.1:6379> GET TestKey
"Some test string"
127.0.0.1:6379> info keyspace
# Keyspace
db0:keys=1,expires=0,avg_ttl=0




Остановим узел redis1 и запросим снова список ключей:




127.0.0.1:6379> info keyspace
Error: Server closed the connection
(3.01s)
127.0.0.1:6379> info keyspace
# Keyspace
db0:keys=1,expires=0,avg_ttl=0
(2.01s)




Видим, что на некоторое время соединение оборвалось, но затем подключение снова восстановилось и все данные остались на месте.




Теперь достаточно прописать в конфигурационных файлах сервисов DirectumRX адрес reverse-прокси для подключения к Redis.




Вместо заключения




При настройке на реальной инсталляции, необходимо, чтобы следящих сервисов было несколько (по правилам на каждом узле реплики) и HAProxy работал в режиме кластера. В данной статье кластеризация HAProxy рассматриваться не будет, мы рассмотрели только основные принципы настройки отказоустойчивого Redis для сервисов DirectumRX.




Если статья наберет больше 30 лайков, продолжим данную тему и рассмотрим настройку Redis Cluster, а также в продолжении рассмотрим настройки балансировщиков на базе HAProxy и Ngnix применимо для DirectumRX.




Дисклеймер 




Рекомендации представленные в статье не являются официальной документацией какой бы то ни было компании. Рекомендации предоставляются на основании личного опыта автора по настройке системы DirectumRX и серверных компонентов. Автор статьи не несет ответственности и не предоставляет гарантий в связи с публикацией фактов, сведений и другой информации, а также не предоставляет никаких заверений или гарантий относительно содержащихся здесь сведений. 




Источник: https://club.directum.ru/post/222438




Redis + Sentinel behind HAProxy




Просто краткое замечание, недавно я выяснил, как установить один IP-адрес для вашего набора Redis.




Возьмем следующий сценарий, в котором у вас есть три экземпляра Redis, один ведущий и два ведомых. У вас также есть три Redis стражей которые управляют состоянием master / slave этого набора.




Я не хотел, чтобы моим клиентам приходилось поддерживать соединения с экземплярами Redis sentinel, подписываясь на событие master change и затем обновляя свою конфигурацию. Я также не хотел открывать правила брандмауэра, чтобы разрешить клиентам подключаться к каждому из трех экземпляров Redis.




Я предпочитаю, чтобы все было просто, мои клиенты просто занимаются чтением и записью в Redis, и что-то еще отвечает за управление доступностью кластера. Что я на самом деле обнаружил, так это то, что я могу использовать проверки работоспособности TCP Layer7 в HAProxy чтобы проверить состояние «master», впоследствии я только «балансирую нагрузку» своего трафика на главный узел, а «slave» считаются отключенными.




Предварительные условия




Это не статья о том, как настроить HAProxy, поэтому, боюсь, вам придется обратиться за этим в другое место, и я не объясняю конфигурации Redis master / slave / sentinel. Итак, в принципе, продолжайте и настройте свою настройку Redis как обычно, а затем установите другой хост с HAProxy .




Конфигурация




Конфигурация HAProxy вокруг redis сама по себе довольно проста, довольно проста:




listen redis-postprocess-TCP-6379 0.0.0.0:6379
    mode tcp
    option tcplog
    option tcp-check
    #uncomment these lines if you have basic auth
    #tcp-check send AUTH yourpasswordrn
    #tcp-check expect +OK
    tcp-check send PINGrn
    tcp-check expect string +PONG
    tcp-check send info replicationrn
    tcp-check expect string role:master
    tcp-check send QUITrn
    tcp-check expect string +OK
    server redis-1 192.168.0.2:6379 maxconn 1024 check inter 1s
    server redis-2 192.168.0.3:6379 maxconn 1024 check inter 1s
    server redis-3 192.168.0.4:6379 maxconn 1024 check inter 1s




То, что мы в основном просим HAProxy делать здесь, — это каждые 1 секунду, ping сервер и ожидать pong, затем запрашивать info и ожидать строку role:master.




В результате вы получаете ситуацию, когда весь ваш трафик отправляется только на «master», как вы можете видеть на экране состояния HAProxy:







Вуаля, на самом деле все, просто укажите своим клиентам ваш IP-адрес HAProxy и оставьте заботу о высокой доступности Sentinels + HAProxy, работающим в унисон.




Источник: https://karlstoney.com/redis-sentinel-behind-haproxy/









2023-10-09T15:43:24
Software