Translate

неділю, 14 серпня 2016 р.

Redis Replication: Master-Slave

Декілька тижнів тому, я писав базові можливості Redis та як з ним працювати. Також я обіцяв продовжити цикл статей про Редіс і розповісти про високу доступність, кластеризацію та реплікацію цього сервісу. Отже цього разу мова піде про вбудовану в Redis асинхронну реплікацію Master-Slave.

Redis має вбудовану Master-Slave реплікацію і особливості її наступні:
  • Асинхронність, що на практиці означає, що дані лише з часом потрапляють на слейв. З версії 2.8 слейв періодично надсилає майстру підтвердження щодо того, скільки даних було cкопійовано.
  • Майстер може мати декілька слейвів одночасно
  • Слейви можуть бути підключені каскадно один до одного. Тобто для кожного наступного слейву, попередній слейв виступатиме джерелом даних для реплікації.
  • Процес реплікації є неблокуючим для майстра. Це значить, що майстер продовжує відповідати на всі запити, навіть якщо слейв запитав початкову синхронізацію
  • Процес реплікації також не є блокуючим і для слейвів, у разі, якщо в конфігураційних файлах дозволено використання старого набору даних для відповіді на запити. Інакше, є можливість заборонити такі дії і слати помилки клієнтам, якщо процес реплікації зупинений. 
  • Реплікація може використовуватись для масштабування операцій читання: чим більше слейвів - тим швидше відбуваються операції читання, і тим більшу кількість запитів мають можливість обробити сервера. У разі падіння діючого майстра - слейв можна зробити новим майстром. Тобто слейви можуть використовуватись лише для читання, зі зрозумілих причин операції запису на них заблоковані.
Більш того, опціонально можна вимкнути механізм(и) збереження даних на диск на майстрі, задля підвищення швидкості його роботи. Так як слейви все реплікують - вони і будуть джерелом наповнення даних у разі падіння останнього. Але є одне але: у такому разі автозапуск Redis-процесу необхідно заборонити, адже інакше відсутні дані майстра (дивно звучить), після його можливого падіння, скопіюються і на слейви, що призведе до повного видалення баз. Але навіть так це достатньо ризиковано.

Зупинимось наразі трохи на деталях як відбувається реплікація. Після налаштування слейва, останній надсилає PSYNC команди на майстер. Якщо це регулярний запит і в беклогах майстра достатньо змін - то лише ці зміни будуть надіслані на слейв. У разі довгого простою слейва (виведення його з роботи і т.п.) буде запитана повна синхронізація даних з майстром.

Якщо було запитано повну синхронізацію, майстер запускає фоновий процес збереження задля створення RDB-файлу. В той же час він починає зберігати в буфер всі нові команди запису отримані від клієнтів, що користуються цим майстром. Коли створення RDB-файлу закінчено, майстер надсилає його слейву. Останній зберігає його на диск та завантажує його в пам’ять. І лише після цього майстер надсилає всі збережені в буфері команди на слейв.

Якщо майстер використовують одразу декілька слейвів і всі вони потребують повної синхронізації - Redis намагається відсилати RDB-файл та буфер збережених програм одним потоком одразу декільком слейвам.

Починаючи з версії 2.8, майстер і слейв в змозі продовжити реплікацію, без повної ресинхронізації у разі розірвання процесу реплікації (у разі відсутності мережі між серверами, тимчасового даунтайму слейву і т.п.). У процесі роботи реплікації, при надсиланні кожної порції нових даних, майстер та слейв слідкують за позицією виконання команд майстра на запис (replication offset) та id майстра (master run ID). Тому, наприклад, якщо зв’язок між серверами було розірвано, при його наступній появі, слейв зробить спробу продовжити реплікацію даних з останньої позиції replication offset та master run ID. На протязі часу відсутності реплікації, майстер створює буфер, куди записує дані, котрі не отримав слейв. Цей буфер має назву backlog, та його розміром можна управляти:

repl-backlog-size 1mb

Ці дані і будуть віддані слейву, одразу при його появі. Звісно, якщо реплікація була зупинена на протязі довгого проміжку часу, вказаної позиції може вже і не бути в беклозі майстра - і тому буде запитана повна ресинхронізація даних слейвом. Якщо після простою слейва master run ID змінився (наприклад, через переналаштування майстра) - знову ж це призведе до старту повної ресинхронізації даних.

Відповідно чим більший розмір беклога - тим довше слейв може бути відключеним від майстра і після цього запитати лаше часткову синхронізацію (partial resynchronization).

Часом існування беклогу також можна управляти.

repl-backlog-ttl 3600

Цей запис означає, що беклог існуватиме напротязі лише години і надалі буде витертий майстром.

Я вже згадував, що процес повної ресинхронізації відбувається зі збереження файлу RDB на диск майстра і подальшою підправкою його на слейви. У разі повільних дисків, цей процес може сповільнити роботу механізму збереження логу операцій AOF, що в свою чергу сповільнить роботу бази вцілому. З версією 2.8.18, Redis навчився формувати RDB файл і одразу надсилати його в мережевий сокет для відправки на слейви. Проте і досі ця опція є експериментальною і деактивована по-замовчуванню в файлі конфігурації:

repl-diskless-sync no

Знову ж, у разі декількох слейвів одного майстра, останній може дещо зачекати задля відправки даних одразу декільком слейвам:

repl-diskless-sync-delay 5

Redis майстер буде чекати 5 секунд перед стартом передачі даних всім бажаючим слейвам. Інакше, для всіх інших слейвів, що не підключились за цей проміжок часу, необхідно буде розпочинати увесь цей процес спочатку.

Redis майстер може блокувати запити на запис, якщо до нього не підключениий певний мінімум слейвів:

min-slaves-to-write <number of slaves>

Чи відставання репліки від майстра вище за вказану кількість секунд:

min-slaves-max-lag <number of seconds>

Ці опції можуть бути корисними для підтримки актуальності данних на всій группі серверів. Скажімо, можуть бути ситуації, коли майстер вийде із ладу, а останніх актуальних даних може і не бути через велике відставання слейвів від майстру. Якщо такий слейв вручну призначити майстром - то при появі старого майстра, актуальні дані можуть бути втрачені повністю. По замовчуванню ці опції деактивовані в redis.conf.

Перейдемо до практичної частини. Для подальших налаштування використаємо останню Ubuntu 16.04, в репозиторіях якої знаходиться достатньо свіжа версія Redis - 3.0.6. У якості IP-адрес оберемо наступні:

192.168.1.39 master
192.168.1.42 slave

Для демонстрації роботи реплікації Master-Slave двох серверів буде цілком достатньо. Перший буде майстром, другим - слейвом. Слейвів може бути декілька.


Установимо сервіс на кожен із вузлів:

# apt install redis-server -y

Відредагуємо конфігураційний файл Redis на майстрі:

# vim /etc/redis/redis.conf

Відкриваємо порт Redis для роботи на всіх інтерфейсах:

bind 0.0.0.0

Пароль для доступу до сервера:

requirepass your_redis_master_password

У якості пароля бажано обирати щось складне та довге, адже по своїй природі Redis дуже швидкий і перебір паролів по словнику відбувається аналогічно швидко.

Увімкнемо механізму забезпечення цілісності Append Only File (AOF) та вкажемо назву файлу для нього. Про AOF я писав у попередній статті про Redis:

appendonly yes
appendfilename "appendonly.aof"

Перевантажимо сервіс:

# service redis-server restart

Налаштуємо Redis Slave. Для цього відредагуємо аналогічний конфігураційний файл:

# vim /etc/redis/redis.conf

І також дозволимо роботу сервісу на всіх інтерфейсах:

bind 0.0.0.0

Укажемо пароль для слейв-сервера:

requirepass your_redis_slave_password

Аналогічно активуємо AOF:

appendonly yes
appendfilename "appendonly.aof"

Якщо слейв не буде переналаштовуватись для ролі майстра у випадку, якщо останній буде не в робочому стані, дані опції можна вимкнути.

Ну і останнє, найважливіше: вкажемо слейву за якою адресою розміщений майстер, та пароль доступу до нього, котрий ми створили раніше:

slaveof 192.168.1.39 6379
masterauth your_redis_master_password

Перевантажимо Redis на слейві:

# service redis-server restart

Якщо ви налаштовуєте майбутні бойові сервери - то варто також підняти ліміт максимальної кількості відкритих файлів redis-процесом:

# vim /etc/default/redis-server
#
ULIMIT=65536

Це стосується як майстра, так і слейва.

Прийшов час перевірити результати. Спершу перевіримо вивід сервісних команд. Виконаємо на майстрі:

# redis-cli -h 192.168.1.39 -p 6379
192.168.1.39:6379> AUTH your_redis_master_password
192.168.1.39:6379> INFO
...
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.1.42,port=6379,state=online,offset=407,lag=1
master_repl_offset:407
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:406
...

Як бачимо, в секції Replication вказано, що є лише 1 слейв (connected_slaves:1) для цього майстра і адреса його - 192.168.1.39. Перевірити конфігурацію серверів також можна зі слейва:

# redis-cli -h 192.168.1.42 -p 6379
192.168.1.42:6379> AUTH your_redis_slave_password
192.168.1.42:6379> INFO
...
# Replication
role:slave
master_host:192.168.1.39
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:1401
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

З виводу стає зрозуміло, що цей сервер Redis працює у ролі слейва, комунікує з майстром, що знаходиться за адресою 192.168.1.39, може використовуватись лише для читання (slave_read_only:1). Останній раз слейв комунікував з майстром 3 секунди тому (master_last_io_seconds_ago:3). Більше інформації про вивід команди INFO знаходиться ось тут http://redis.io/commands/INFO

У разі, якщо з діючим майстром щось сталось, вручну можна делегувати роль майстра слейву. Це робиться наступним чином (192.168.1.42 - адреса слейва):

# redis-cli -h 192.168.1.42 -p 6379
192.168.1.42:6379> AUTH your_redis_slave_password
192.168.1.42:6379> SLAVEOF NO ONE

Перевіряємо результат зміни ролі сервера:

192.168.1.42:6379> INFO
...
# Replication
role:master
connected_slaves:0
master_repl_offset:1737
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
...

Інші слейви (якщо такі були) варто переконфігурувати на новий майстер. Для цього виконаємо в консолі кожного слейва Redis:

> SLAVEOF new_master_hostname port

Після появи старого майстра, його роль можна повернути, переконфігурувавши слейви таким чином:

> SLAVEOF your_old_redis_master_ip port

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

Посилання:
https://www.digitalocean.com/community/tutorials/how-to-configure-a-redis-cluster-on-ubuntu-14-04
http://redis.io/topics/replication
http://download.redis.io/redis-stable/redis.conf
http://antirez.com/news/81

Немає коментарів:

Дописати коментар