У цій статті піде мова про Sentinel - один із способів забезпечення високої доступності Redis. Забігаючи наперед, скажу, що Redis Sentinel не надає можливостей шардингу (sharding), тобто для збільшення простору збереження даних необхідно збільшувати кількість оперативної пам’яті сервера.
Дуже раджу попередньо ознайомитись з простою реплікацією Redis, про яку я писав дещо раніше. У двох словах, Redis Sentinel - це звичайна реплікація Redis, але з можливістю автоматичного міграції майстра на інший працюючий вузол, що був у реплікації. Після такої міграції майстра, попередній майстер, завдяки додатковому демону Sentinel, автоматично переконфігуровується в слейв, який може використовуватись лише для читання.
Для налаштування Redis Sentinel використаємо такі адреси:
192.168.1.39
192.168.1.42
192.168.1.43
Установимо пакети redis-server та redis-sentinel на кожен із серверів. У якості дистрибутиву я обрав останню LTS Ubuntu - 16.04. Зі стандартного репозиторію встановимо Redis та Sentinel:
# apt install redis-server
# apt install redis-sentinel
Зрештою, сервер Redis займе звичний порт 6379, а sentinel - 26379. Ясна річ, що ці порти мають бути відкритими в фаєрволі, якщо такий є.
Перезавантажимо Redis та перевіримо його роботу:
# redis-cli ping
PONG
Конфігурація кластера Sentinel не має викликати особливих труднощів. Перше, що необхідно перевірити - це те чи відкритий порт Redis для віддаленої роботи:
# vim /etc/redis/redis.conf
...
bind 0.0.0.0
...
Порт 6379 має працювати на нелокальному інтерфейсі для взаємодії Redis-процесу з іншими вузлами. Ця опція має приймати аналогічне значення і для Sentinel сервісу в /etc/redis/sentinel.conf.
Налаштовуємо Sentinel-процес:
# vim /etc/redis/sentinel.conf
...
sentinel monitor mymaster 192.168.1.39 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
...
На всіх нодах конфігураційний файл має абсолютно однаковий вигляд.
Отже, Sentinel-процес буде слідкувати за роботою майстра (monitor), котрому було дано образне ім’я mymaster. Кворум для роботи фейловера Sentinel (останній аргумент першого рядка) - 2 ноди, це розумне значення для нашого прикладу з 3 нодами кластеру (про те, чому кількість нод кластера має має бути непарною я писав у статті про Mesos).
Майстер буде вважатись непрацюючим у разі, якщо він не відповідатиме на пінг-команди інших хостів більше 30 секунд, після чого розпочнеться процес обирання нового майстра в кластері (failover). failover-timeout опція означає, що, у разі появи старого майстра, він же зможе бути обраний майстером знову не раніше ніж через 180 секунд (для нашого прикладу).
Опція parallel-syncs у нашому випадку вказує на те, що лише один слейв може бути недоступним під час failover процесу. Тобто падіння тільки одного сервера (наприклад, минулого майстра) задовольняє цій вимозі.
Виходячи з наведеного вище конфігураційного файлу, при старті кластера, 192.168.1.39 буде вважатись майстром. Операції запису будуть дозволені лише на майстрі, а читання - всюди. Тобто це така собі master-slave redis-реплікація з різницею в тому, що Sentinel-процес сам відслідковує стан redis-вузлів і, у випадку форс-мажорів, запускає процес переналаштування реплікації з іншим майстром на чолі. Тобто, по-факту Sentinel власноруч змінює конфігураційні файли /etc/redis/redis.conf кожної ноди кластеру і являється таким собі хабом конфігурацій для Redis.
Після успішного старту Sentinel дещо змінює і свої конфігураційні файли: наприклад, додає директиви known-slave, known-sentinel і т.п.
Sentinel-процеси можуть слідкувати за декількома Redis кластерами одночасно, для цього необхідно лише описати додаткову групу на кшталт наступної:
...
sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5
...
Група resque може без проблем співіснувати з попередньою групою mymaster.
Sentinel, по аналогії з Redis, може бути переналаштований прямо в процесі роботи, без перезавантаження. Для цього необхідно скористатись його консоллю, що знову ж відбувається схожим з Redis чином. За наступним посиланням можна знайти про це більше інформації http://redis.io/topics/sentinel#reconfiguring-sentinel-at-runtime
Після зміни конфігураційних файлів як процес redis-server, так і процес redis-sentinel необхідно перевантажувати.
Підключимось до адреси 192.168.1.39 та порту 26379 (стандартний порт Sentinel) і перевіримо конфігурацію кластера:
# redis-cli -h 192.168.1.39 -p 26379
192.168.1.39:26379> SENTINEL master mymaster
1) "name"
2) "mymaster"
3) "ip"
4) "192.168.1.39"
5) "port"
6) "6379"
7) "runid"
8) "36c0e7a6e4ee29cd1bcefa40e59a71c5fa50a230"
9) "flags"
10) "master"
11) "pending-commands"
12) "0"
13) "last-ping-sent"
14) "0"
15) "last-ok-ping-reply"
16) "332"
17) "last-ping-reply"
18) "332"
19) "down-after-milliseconds"
20) "30000"
21) "info-refresh"
22) "3514"
23) "role-reported"
24) "master"
25) "role-reported-time"
26) "3568"
27) "config-epoch"
28) "1"
29) "num-slaves"
30) "2"
31) "num-other-sentinels"
32) "2"
33) "quorum"
34) "2"
35) "failover-timeout"
36) "180000"
37) "parallel-syncs"
38) "1"
Все аналогічно, як ми і описували sentinel.conf. Дізнатись про адресу діючого майстру можна також наступним чином:
# redis-cli -h 192.168.1.42 -p 26379
192.168.1.42:26379> SENTINEL get-master-addr-by-name mymaster
1) "192.168.1.39"
2) "6379"
Якщо проілюструвати зроблене, то вийде щось схоже на це
Спроба запису на слейв-сервер очікувано призведе до помилки:
192.168.1.39:6379> set users:leto "{name: leto, planet: dune, likes: [spice]}"
(error) READONLY You can't write against a read only slave.
Для тестових цілей зупинимо діючий майстер та зачекаємо більше 30 секунд до старту failover-процесу:
# redis-cli -h 192.168.1.39 -p 6379 DEBUG sleep 40
Перевіримо хто ж наразі став новим майстром Sentinel-кластеру:
# redis-cli -h 192.168.1.41 -p 26379
192.168.1.41:26379> SENTINEL master mymaster
1) "name"
2) "mymaster"
3) "ip"
4) "192.168.1.42"
5) "port"
6) "6379"
7) "runid"
8) "36c0e7a6e4ee29cd1bcefa40e59a71c5fa50a230"
9) "flags"
10) "master"
11) "pending-commands"
12) "0"
13) "last-ping-sent"
14) "0"
15) "last-ok-ping-reply"
16) "332"
17) "last-ping-reply"
18) "332"
19) "down-after-milliseconds"
20) "60000"
21) "info-refresh"
22) "3514"
23) "role-reported"
24) "master"
25) "role-reported-time"
26) "3568"
27) "config-epoch"
28) "1"
29) "num-slaves"
30) "2"
31) "num-other-sentinels"
32) "2"
33) "quorum"
34) "2"
35) "failover-timeout"
36) "180000"
37) "parallel-syncs"
38) "1"
192.168.1.41:26379>
Отже, Sentinel переналаштував кластер і в якості майстра було обрано 192.168.1.42:
Sentinel приймає рішення про переналаштування кластеру в декілька етапів:
Сам Redis-сервер також відображає статус роботи Sentinel-кластеру, адже з його сторони це сприймається як звичайна майстер-слейв реплікація :
# redis-cli -h 192.168.1.39 -p 6379
192.168.1.39:6379> INFO Replication
# Replication
role:slave
master_host:192.168.1.42
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:34618
slave_priority:100
slave_read_only:1
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
192.168.1.39:6379>
Що ще раз підтверджує, що минулий майстер став слейвом, а новим було обрано 192.168.1.42.
Redis має можливість установки пріоритету серверам, що входять в кластер:
slave-priority 100
Sentinel буде надавати перевагу в обранні майстром сервера з нижчим пріоритетом. А значення "slave-priority 0" означатиме, що сервер ніколи не буде майстром. Проте це не єдиний фактор, що впливає на те, хто буде обраний наступним майстром.
Як же програма розуміє, хто наразі майстер, в який можна записувати, і хто слейв, з якого можна читати вже записані дані? Один із варіантів - це підключення додатків через драйвер Redis Sentinel. Для мови програмування Python 3 з цим може допомогти одноіменна бібліотека:
# pip install redis
# python3
Python 3.5.1+ (default, Mar 30 2016, 22:46:26)
[GCC 5.3.1 20160330] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import redis
>>> from redis.sentinel import Sentinel
>>> sentinel = Sentinel([('192.168.1.39', 26379), ('192.168.1.42', 26379), ('192.168.1.43', 26379)], socket_timeout=0.1)
>>> sentinel.discover_master('mymaster')
('192.168.1.42', 6379)
>>> sentinel.discover_slaves('mymaster')
[('192.168.1.43', 6379), ('192.168.1.39', 6379)]
Не виходячи з консолі Python, перевіримо роботу реплікації:
>>> master = sentinel.master_for('mymaster', socket_timeout=0.1)
>>> master.set('foo', 'bar')
True
>>> slave = sentinel.slave_for('mymaster', socket_timeout=0.1)
>>> slave.get('foo')
b'bar'
Реалізація подібних бібліотек є і для багатьох інших мов програмування.
Інший, альтернативний варіант, - це установка перед Redis Sentinel балансувальника HAProxy, котрий, роблячи keepalive-запити до Sentinel, і дізнається хто наразі майстер.
Посилання:
http://redis.io/topics/sentinel
http://blog.commando.io/redis-is-easy-trivial-hard/
https://seanmcgary.com/posts/how-to-build-a-fault-tolerant-redis-cluster-with-sentinel
http://engineering.bloomreach.com/the-evolution-of-fault-tolerant-redis-cluster/
http://stackoverflow.com/questions/31143072/redis-sentinel-vs-clustering
Дуже раджу попередньо ознайомитись з простою реплікацією Redis, про яку я писав дещо раніше. У двох словах, Redis Sentinel - це звичайна реплікація Redis, але з можливістю автоматичного міграції майстра на інший працюючий вузол, що був у реплікації. Після такої міграції майстра, попередній майстер, завдяки додатковому демону Sentinel, автоматично переконфігуровується в слейв, який може використовуватись лише для читання.
Для налаштування Redis Sentinel використаємо такі адреси:
192.168.1.39
192.168.1.42
192.168.1.43
Установимо пакети redis-server та redis-sentinel на кожен із серверів. У якості дистрибутиву я обрав останню LTS Ubuntu - 16.04. Зі стандартного репозиторію встановимо Redis та Sentinel:
# apt install redis-server
# apt install redis-sentinel
Зрештою, сервер Redis займе звичний порт 6379, а sentinel - 26379. Ясна річ, що ці порти мають бути відкритими в фаєрволі, якщо такий є.
Перезавантажимо Redis та перевіримо його роботу:
# redis-cli ping
PONG
Конфігурація кластера Sentinel не має викликати особливих труднощів. Перше, що необхідно перевірити - це те чи відкритий порт Redis для віддаленої роботи:
# vim /etc/redis/redis.conf
...
bind 0.0.0.0
...
Порт 6379 має працювати на нелокальному інтерфейсі для взаємодії Redis-процесу з іншими вузлами. Ця опція має приймати аналогічне значення і для Sentinel сервісу в /etc/redis/sentinel.conf.
Налаштовуємо Sentinel-процес:
# vim /etc/redis/sentinel.conf
...
sentinel monitor mymaster 192.168.1.39 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
...
На всіх нодах конфігураційний файл має абсолютно однаковий вигляд.
Отже, Sentinel-процес буде слідкувати за роботою майстра (monitor), котрому було дано образне ім’я mymaster. Кворум для роботи фейловера Sentinel (останній аргумент першого рядка) - 2 ноди, це розумне значення для нашого прикладу з 3 нодами кластеру (про те, чому кількість нод кластера має має бути непарною я писав у статті про Mesos).
Майстер буде вважатись непрацюючим у разі, якщо він не відповідатиме на пінг-команди інших хостів більше 30 секунд, після чого розпочнеться процес обирання нового майстра в кластері (failover). failover-timeout опція означає, що, у разі появи старого майстра, він же зможе бути обраний майстером знову не раніше ніж через 180 секунд (для нашого прикладу).
Опція parallel-syncs у нашому випадку вказує на те, що лише один слейв може бути недоступним під час failover процесу. Тобто падіння тільки одного сервера (наприклад, минулого майстра) задовольняє цій вимозі.
Виходячи з наведеного вище конфігураційного файлу, при старті кластера, 192.168.1.39 буде вважатись майстром. Операції запису будуть дозволені лише на майстрі, а читання - всюди. Тобто це така собі master-slave redis-реплікація з різницею в тому, що Sentinel-процес сам відслідковує стан redis-вузлів і, у випадку форс-мажорів, запускає процес переналаштування реплікації з іншим майстром на чолі. Тобто, по-факту Sentinel власноруч змінює конфігураційні файли /etc/redis/redis.conf кожної ноди кластеру і являється таким собі хабом конфігурацій для Redis.
Після успішного старту Sentinel дещо змінює і свої конфігураційні файли: наприклад, додає директиви known-slave, known-sentinel і т.п.
Sentinel-процеси можуть слідкувати за декількома Redis кластерами одночасно, для цього необхідно лише описати додаткову групу на кшталт наступної:
...
sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5
...
Група resque може без проблем співіснувати з попередньою групою mymaster.
Sentinel, по аналогії з Redis, може бути переналаштований прямо в процесі роботи, без перезавантаження. Для цього необхідно скористатись його консоллю, що знову ж відбувається схожим з Redis чином. За наступним посиланням можна знайти про це більше інформації http://redis.io/topics/sentinel#reconfiguring-sentinel-at-runtime
Після зміни конфігураційних файлів як процес redis-server, так і процес redis-sentinel необхідно перевантажувати.
Підключимось до адреси 192.168.1.39 та порту 26379 (стандартний порт Sentinel) і перевіримо конфігурацію кластера:
# redis-cli -h 192.168.1.39 -p 26379
192.168.1.39:26379> SENTINEL master mymaster
1) "name"
2) "mymaster"
3) "ip"
4) "192.168.1.39"
5) "port"
6) "6379"
7) "runid"
8) "36c0e7a6e4ee29cd1bcefa40e59a71c5fa50a230"
9) "flags"
10) "master"
11) "pending-commands"
12) "0"
13) "last-ping-sent"
14) "0"
15) "last-ok-ping-reply"
16) "332"
17) "last-ping-reply"
18) "332"
19) "down-after-milliseconds"
20) "30000"
21) "info-refresh"
22) "3514"
23) "role-reported"
24) "master"
25) "role-reported-time"
26) "3568"
27) "config-epoch"
28) "1"
29) "num-slaves"
30) "2"
31) "num-other-sentinels"
32) "2"
33) "quorum"
34) "2"
35) "failover-timeout"
36) "180000"
37) "parallel-syncs"
38) "1"
Все аналогічно, як ми і описували sentinel.conf. Дізнатись про адресу діючого майстру можна також наступним чином:
# redis-cli -h 192.168.1.42 -p 26379
192.168.1.42:26379> SENTINEL get-master-addr-by-name mymaster
1) "192.168.1.39"
2) "6379"
Якщо проілюструвати зроблене, то вийде щось схоже на це
192.168.1.39:6379> set users:leto "{name: leto, planet: dune, likes: [spice]}"
(error) READONLY You can't write against a read only slave.
Для тестових цілей зупинимо діючий майстер та зачекаємо більше 30 секунд до старту failover-процесу:
# redis-cli -h 192.168.1.39 -p 6379 DEBUG sleep 40
Перевіримо хто ж наразі став новим майстром Sentinel-кластеру:
# redis-cli -h 192.168.1.41 -p 26379
192.168.1.41:26379> SENTINEL master mymaster
1) "name"
2) "mymaster"
3) "ip"
4) "192.168.1.42"
5) "port"
6) "6379"
7) "runid"
8) "36c0e7a6e4ee29cd1bcefa40e59a71c5fa50a230"
9) "flags"
10) "master"
11) "pending-commands"
12) "0"
13) "last-ping-sent"
14) "0"
15) "last-ok-ping-reply"
16) "332"
17) "last-ping-reply"
18) "332"
19) "down-after-milliseconds"
20) "60000"
21) "info-refresh"
22) "3514"
23) "role-reported"
24) "master"
25) "role-reported-time"
26) "3568"
27) "config-epoch"
28) "1"
29) "num-slaves"
30) "2"
31) "num-other-sentinels"
32) "2"
33) "quorum"
34) "2"
35) "failover-timeout"
36) "180000"
37) "parallel-syncs"
38) "1"
192.168.1.41:26379>
Отже, Sentinel переналаштував кластер і в якості майстра було обрано 192.168.1.42:
Sentinel приймає рішення про переналаштування кластеру в декілька етапів:
- Спочатку кожен sentinel-процес виявляє непрацюючий майстер і ставить йому статус SDOWN (subjectіvely down). Цей статус призначається серверу у разі, якщо останній не відповідає чи відповідає некоректно на PING запити від сусідів.
- У разі, якщо більшість sentinel-процесів мають аналогічну думку, впавшому майстру призначається статус ODOWN (objectіvely down). Обмін цією інформацією Sentinel-процеси проводять у окремому каналі +odown.
- sentinel-процеси, у разі якщо вони мають кворум, голосують за те хто буде проводити переналаштування кластеру. І лише один обраний sentinel-процес буде цим займатись.
- Відбувається failover-процес
Сам Redis-сервер також відображає статус роботи Sentinel-кластеру, адже з його сторони це сприймається як звичайна майстер-слейв реплікація :
# redis-cli -h 192.168.1.39 -p 6379
192.168.1.39:6379> INFO Replication
# Replication
role:slave
master_host:192.168.1.42
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:34618
slave_priority:100
slave_read_only:1
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
192.168.1.39:6379>
Що ще раз підтверджує, що минулий майстер став слейвом, а новим було обрано 192.168.1.42.
Redis має можливість установки пріоритету серверам, що входять в кластер:
slave-priority 100
Sentinel буде надавати перевагу в обранні майстром сервера з нижчим пріоритетом. А значення "slave-priority 0" означатиме, що сервер ніколи не буде майстром. Проте це не єдиний фактор, що впливає на те, хто буде обраний наступним майстром.
Як же програма розуміє, хто наразі майстер, в який можна записувати, і хто слейв, з якого можна читати вже записані дані? Один із варіантів - це підключення додатків через драйвер Redis Sentinel. Для мови програмування Python 3 з цим може допомогти одноіменна бібліотека:
# pip install redis
# python3
Python 3.5.1+ (default, Mar 30 2016, 22:46:26)
[GCC 5.3.1 20160330] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import redis
>>> from redis.sentinel import Sentinel
>>> sentinel = Sentinel([('192.168.1.39', 26379), ('192.168.1.42', 26379), ('192.168.1.43', 26379)], socket_timeout=0.1)
>>> sentinel.discover_master('mymaster')
('192.168.1.42', 6379)
>>> sentinel.discover_slaves('mymaster')
[('192.168.1.43', 6379), ('192.168.1.39', 6379)]
Не виходячи з консолі Python, перевіримо роботу реплікації:
>>> master = sentinel.master_for('mymaster', socket_timeout=0.1)
>>> master.set('foo', 'bar')
True
>>> slave = sentinel.slave_for('mymaster', socket_timeout=0.1)
>>> slave.get('foo')
b'bar'
Реалізація подібних бібліотек є і для багатьох інших мов програмування.
Інший, альтернативний варіант, - це установка перед Redis Sentinel балансувальника HAProxy, котрий, роблячи keepalive-запити до Sentinel, і дізнається хто наразі майстер.
Посилання:
http://redis.io/topics/sentinel
http://blog.commando.io/redis-is-easy-trivial-hard/
https://seanmcgary.com/posts/how-to-build-a-fault-tolerant-redis-cluster-with-sentinel
http://engineering.bloomreach.com/the-evolution-of-fault-tolerant-redis-cluster/
http://stackoverflow.com/questions/31143072/redis-sentinel-vs-clustering
Немає коментарів:
Дописати коментар