Redis: репликация, часть 2 — Master-Slave репликация, и Redis Sentinel

Thank you for reading this post, don't forget to subscribe!

Для рабо­ты с сер­ви­са­ми исполь­зу­ем  три доме­на — redis-0.test.ru для масте­ра, redis-1.test.ru  и redis-2.test.ru  для двух слейвов.

Слейв в мини­маль­ном сета­пе может быть и один, но т.к. вто­рой сетап будет с Sentinel — то созда­дим сра­зу три инстанса.

Базовая Master-Slave репликация

В этом вари­ан­те слей­вы явля­ют­ся read-only репли­ка­ми масте­ра, под­дер­жи­вая у себя ту же инфор­ма­цию, кото­рая добав­ля­ет­ся на мастер.

Мастер шлёт на слей­вы все изме­не­ния, кото­рые выпол­ня­ют­ся в дан­ных — запи­си кли­ен­тов, обнов­ле­ния клю­чей и т.д.

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

В слу­чае, если частич­ная син­хро­ни­за­ция невоз­мож­на — слейв запра­ши­ва­ет у масте­ра пол­ную син­хро­ни­за­цию. Тогда мастер созда­ёт пол­ный снап­шот всех име­ю­щих­ся у него дан­ных, отправ­ля­ет их на слейв, а затем про­дол­жа­ет слать обнов­ле­ния в обыч­ном режиме.

Несколь­ко нюан­сов такой репликации:

  • один мастер может иметь несколь­ко слейвов
  • слей­вы могут при­ни­мать под­клю­че­ния от дру­гих слей­вов, созда­вая таким обра­зом «кас­кад» реп­ли­ци­ро­ван­ных нод — от масте­ра «ввер­ху», слей­вов «в сере­дине» и слей­вов «вни­зу»
  • кате­го­ри­че­ски реко­мен­ду­ет­ся исполь­зо­вать persistence на масте­ре и слей­вах во избе­жа­ние поте­ри дан­ных, см. Safety of replication when master has persistence turned off
  • слей­вы по умол­ча­нию рабо­та­ют в read-only режиме,

Настройка Redis Master

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

root@redis-0:/home/admin# yum -y install redis-server

 

Редак­ти­ру­ем /etc/redis/redis.conf, в bind зада­ём про­слу­ши­ва­ние всех интерфейсов:

bind 0.0.0.0

Мож­но ука­зать IP через про­бел, например:

bind 127.0.0.1 18.194.229.23

Дру­гие инте­рес­ные тут опции:

  • port 6379 — понятно
  • slave-read-only yes — слей­вы при­ни­ма­ют запро­сы толь­ко на read, на масте­ре роли не играет
  • requirepass foobared — мастер тре­бу­ет авто­ри­за­цию с паро­лем foobared
  • appendonly yes и appendfilename "appendonly.aof" — умень­ша­ем веро­ят­ность поте­ри послед­них дан­ных, см. Redis Persistence

Пере­за­пус­ка­ем сервис:

root@redis-0:/home/admin# systemctl restart redis

 

Про­ве­ря­ем, пере­да­вая с помо­щью опции -a пароль:

root@redis-0:/home/admin# redis-cli -a foobared ping
PONG

 

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

root@redis-0:/home/admin# redis-cli -a foobared info replication
Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

 

Добав­ля­ем данные:

root@redis-0:/home/admin# redis-cli -a foobared set test 'test'
OK

 

Полу­ча­ем их:

root@redis-0:/home/admin# redis-cli -a foobared get test
"test"

 

ОК — тут всё работает.

Настройка Redis Slave

На остав­ших­ся двух хостах выпол­ня­ем настрой­ку слейвов.

Тут всё оди­на­ко­во, про­сто повто­ря­ем на обоих.

Уста­нав­ли­ва­ем:

root@redis-1:/home/admin# yum  -y install redis-server

 

Редак­ти­ру­ем /etc/redis/redis.conf:

slaveof redis-0.test.ru  6379
masterauth foobared
requirepass foobared

Тут:

  • slaveof — ука­зы­ва­ем хост и порт мастера
  • masterauth — пароль для авто­ри­за­ции на мастере
  • requirepass — пароль для авто­ри­за­ции на слейве

Пере­за­пус­ка­ем:

root@redis-1:/home/admin# systemctl restart redis

Про­ве­ря­ем статус:

root@redis-1:/home/admin# redis-cli -a foobared info replication
Replication
role:slave
master_host:redis-0.test.ru
master_port:6379
master_link_status:up
master_last_io_seconds_ago:5
master_sync_in_progress:0

 

Про­ве­ря­ем лог:

root@redis-1:/home/admin# tail -f /var/log/redis/redis-server.log
16961:S 29 Mar 10:54:36.263 * Connecting to MASTER redis-0.test.ru :6379
16961:S 29 Mar 10:54:36.308 * MASTER <-> SLAVE sync started
16961:S 29 Mar 10:54:36.309 * Non blocking connect for SYNC fired the event.
16961:S 29 Mar 10:54:36.309 * Master replied to PING, replication can continue…
16961:S 29 Mar 10:54:36.310 * Partial resynchronization not possible (no cached master)
16961:S 29 Mar 10:54:36.311 * Full resync from master: 93585eeb7e32c0550c35f8d4935c9a18c4177ab9:1
16961:S 29 Mar 10:54:36.383 * MASTER <-> SLAVE sync: receiving 92 bytes from master
16961:S 29 Mar 10:54:36.383 * MASTER <-> SLAVE sync: Flushing old data
16961:S 29 Mar 10:54:36.383 * MASTER <-> SLAVE sync: Loading DB in memory
16961:S 29 Mar 10:54:36.383 * MASTER <-> SLAVE sync: Finished with success

 

Кон­нект к масте­ру есть, син­хро­ни­за­ция про­шла — окей, про­ве­ря­ем данные:

root@redis-1:/home/admin# redis-cli -a foobared get test
"test"

 

На слей­ве дан­ные тоже есть.

Переключение Slave => Master роли

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

Если сей­час на слей­ве попро­бо­вать запи­сать дан­ные — Redis вер­нёт ошиб­ку, т.к. по умол­ча­нию слей­вы нахо­дят­ся в read-only режиме:

slave-read-only yes

Про­бу­ем доба­вить дан­ные на слейве:

root@redis-1:/home/admin# redis-cli -a foobared set test2 'test2'
(error) READONLY You can't write against a read only slave.

 

Под­клю­ча­ем­ся к слейву:

root@redis-1:/home/admin# redis-cli

 

Авто­ри­зи­ру­ем­ся:

127.0.0.1:6379> auth foobared
OK

 

Отклю­ча­ем слейв-роль:

127.0.0.1:6379> slaveof no one
OK

 

Про­ве­ря­ем статус:

127.0.0.1:6379> info replication
Replication
role:master
connected_slaves:0
master_repl_offset:1989
repl_backlog_active:0
repl_backlog_size:1048576

 

Добав­ля­ем новый ключ ещё раз:

127.0.0.1:6379> set test2 'test2'
OK

 

Про­ве­ря­ем:

127.0.0.1:6379> get test2
"test2"

 

Учти­те, что т.к. в фай­ле настро­ек /etc/redis/redis.conf всё ещё уста­нов­лен пара­метр slaveof — то при рестар­те эта нода сно­ва ста­нет слейвом.

Redis Sentinel

Теперь допол­ним наш кла­стер, и доба­вим Redis в режи­ме Sentinel, кото­рый будет мони­то­рить ста­тус нод, и выпол­нять пере­клю­че­ние ролей автоматически.

Общая схе­ма рабо­ты будет выгя­деть так:

Тут:

  • M1 = Master
  • R1 = Replica 1 / Slave 1
  • R2 = Replica 2 / Slave 2
  • S1 = Sentinel 1
  • S2 = Sentinel 2
  • S3 = Sentinel 3

M1 и S1 — будут на redis-0, R1 и S2 — на redis-1, R2 и S3 — на redis-2.

Запуск Sentinel

Для запус­ка Sentinel исполь­зу­ем тот же Redis-сер­вер, но для него созда­дим отдель­ный кон­фиг /etc/redis/sentinel.conf.

Добав­ля­ем его сна­ча­ла на хосте с Redis Master:

sentinel monitor redis-test redis-0.test.ru  6379 2
sentinel down-after-milliseconds redis-test 6001
sentinel failover-timeout redis-test 60000
sentinel parallel-syncs redis-test 1
bind 0.0.0.0
sentinel auth-pass redis-test foobared

Тут:

  • monitor — адрес мастер-ноды, кото­рую будем мони­то­рить, 2 — кол-во инстан­сов Sentinel для при­ня­тия решений
  • down-after-milliseconds — вре­мя, после кото­ро­го мастер будет счи­тать­ся упавшим
  • failover-timeout — вре­мя ожи­да­ния после сме­ны ролей слей­ва на мастер в слу­чае, если мастер вышел из строя
  • parallel-syncs — вре­мя одно­вре­мен­ной сихро­ни­за­ции слей­вов после пере­на­зна­че­ния роли мастера

Запус­ка­ем:

root@redis-0:/home/admin# redis-server /etc/redis/sentinel.conf --sentinel

Про­ве­ря­ем ста­тус Sentinel — под­клю­ча­ем­ся на порт 26379:

root@redis-0:/home/admin# 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=redis-test,status=ok,address=35.158.154.25:6379,slaves=2,sentinels=1

 

Тут:

  • master0:name=redis-test,status=ok — мастер работает
  • slaves=2 — у него два слейва
  • sentinels=1 — пока запу­щен толь­ко один Sentinel

Мож­но полу­чить раз­лич­ные дан­ные о ста­ту­се репликации.

Напри­мер — адрес теку­ще­го мастера:

root@redis-0:/home/admin# redis-cli -p 26379 sentinel get-master-addr-by-name redis-test
1) "35.158.154.25"
2) "6379"

 

Повто­ря­ем запуск Sentinel на слей­вах, исполь­зуя такой же кон­фиг, как на масте­ре — в логе Sentinel на масте­ре долж­ны появит­ся сооб­ще­ния о новых Sentinel инстансах:

10447:X 29 Mar 14:18:40.437 * +sentinel sentinel fdc750c7d6388a6142d9e27b68172f5846e75d8c 172.31.36.239 26379 @ redis-test 35.158.154.25 6379
10447:X 29 Mar 14:18:42.725 * +sentinel sentinel ecddb26cd27c9a17c4251078c977761faa7a3250 172.31.35.218 26379 @ redis-test 35.158.154.25 6379

 

Про­ве­ря­ем ста­тус ещё раз:

root@redis-0:/home/admin# 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=redis-test,status=ok,address=18.194.229.23:6379,slaves=2,sentinels=3

 

sentinels=3 — окей.

Кро­ме все­го про­че­го — Sentinel авто­ма­ти­че­ски выпол­ня­ет настройку:

root@redis-1:/home/admin# cat /etc/redis/sentinel.conf
sentinel myid fdc750c7d6388a6142d9e27b68172f5846e75d8c
sentinel monitor redis-test 35.158.154.25 6379 2
sentinel down-after-milliseconds redis-test 6001
bind 0.0.0.0
sentinel failover-timeout redis-test 60000
Generated by CONFIG REWRITE
port 26379
dir "/home/admin"
sentinel auth-pass redis-test foobared
sentinel config-epoch redis-test 0
sentinel leader-epoch redis-test 0
sentinel known-slave redis-test 18.194.45.17 6379
sentinel known-slave redis-test 3.121.223.95 6379
sentinel known-sentinel redis-test 172.31.35.218 26379 ecddb26cd27c9a17c4251078c977761faa7a3250
sentinel known-sentinel redis-test 172.31.47.184 26379 e9fb72c8edb8ec2028e6ce820b9e72e56e07cf1e
sentinel current-epoch 0
  • Re-play
  • Copy to Clipboard
  • Pause
  • Full View

Тут доба­вил­ся sentinel myid fdc750c7d6388a6142d9e27b68172f5846e75d8c, и целый блок после Generated by CONFIG REWRITE.

Redis Sentinel Automatic Failover

Теперь про­ве­рим что будет, если умрёт мастер.

Сде­лать это мож­но про­сто убив его вруч­ную, напр­ми­ер через kill -9, либо с помо­щью redis-cli — отпра­вив ему коман­ду DEBUG и ука­зав либо вре­мя, на кото­рое его надо оста­но­вить, либо сиг­нал, от кото­ро­го ему умереть ?

root@redis-0:/home/admin# redis-cli -a foobared DEBUG sleep 30

 

В логе Sentinel на мастере:

10447:X 29 Mar 14:24:56.549 # +sdown master redis-test 35.158.154.25 6379
10447:X 29 Mar 14:24:56.614 # +new-epoch 1
10447:X 29 Mar 14:24:56.615 # +vote-for-leader ecddb26cd27c9a17c4251078c977761faa7a3250 1
10447:X 29 Mar 14:24:56.649 # +odown master redis-test 35.158.154.25 6379 #quorum 3/2
10447:X 29 Mar 14:24:56.649 # Next failover delay: I will not start a failover before Fri Mar 29 14:26:57 2019
10447:X 29 Mar 14:24:57.686 # +config-update-from sentinel ecddb26cd27c9a17c4251078c977761faa7a3250 172.31.35.218 26379 @ redis-test 35.158.154.25 6379
10447:X 29 Mar 14:24:57.686 # +switch-master redis-test 35.158.154.25 6379 3.121.223.95 6379
10447:X 29 Mar 14:24:57.686 * +slave slave 18.194.45.17:6379 18.194.45.17 6379 @ redis-test 3.121.223.95 6379
10447:X 29 Mar 14:24:57.686 * +slave slave 35.158.154.25:6379 35.158.154.25 6379 @ redis-test 3.121.223.95 6379
10447:X 29 Mar 14:25:03.724 # +sdown slave 35.158.154.25:6379 35.158.154.25 6379 @ redis-test 3.121.223.95 6379

 

Сей­час тут осо­бо инте­рес­ны вот эти две строки:

10384:X 29 Mar 14:24:57.686 # +config-update-from sentinel ecddb26cd27c9a17c4251078c977761faa7a3250 172.31.35.218 26379 @ redis-test 35.158.154.25 6379
10384:X 29 Mar 14:24:57.686 # +switch-master redis-test 35.158.154.25 6379 3.121.223.95 6379

 

Sentinel выпол­нил авто­ма­ти­че­скую пере­на­строй­ку слей­ва в мастер.

35.158.154.25 — ста­рый мастер, кото­рый умер, а 3.121.223.95 — новый мастер, кото­рый рань­ше был пер­вым слей­вом, с име­нем хоста redis-1.

Про­ве­ря­ем запись в него:

root@redis-1:/home/admin# redis-cli -a foobared set test3 'test3'
OK

 

Тогда как попыт­ка запи­сать дан­ные на ста­ром масте­ре, кото­рый теперь стал слей­вом, при­ве­дёт к ошибке:

root@redis-0:/home/admin# redis-cli -a foobared set test4 'test4'
(error) READONLY You can't write against a read only slave.

 

Либо уби­ва­ем его вооб­ще — и посмот­рим, что сде­ла­ет Sentinel:

root@redis-0:/home/admin# redis-cli -a foobared DEBUG SEGFAULT
Error: Server closed the connection

 

Лог:

10447:X 29 Mar 14:26:21.897 * +reboot slave 35.158.154.25:6379 35.158.154.25 6379 @ redis-test 3.121.223.95 6379

 

Мастер про­сто перезапущен.

Команды Sentinel

COMMAND DESCRIPTION
sentinel masters спи­сок всех масте­ров и их состояния
sentinel master состо­я­ние кон­крет­но­го мастера
sentinel slaves спи­сок всех слей­вов и их состояния
sentinel sentinels спи­сок всех Sentinel инстан­сов и их состояния
sentinel failover вруч­ную запу­стить про­цесс вос­ста­нов­ле­ние и заме­ны вышед­ше­го из строя мастера
sentinel flushconfig Force Sentinel to rewrite it’s configuration on disk
sentinel monitor доба­вить новый мастер
sentinel remove уда­лить мастер из-под наблюдения