W poprzednim poście (którego napisałam już baaardzo dawno temu) wprowadziłam nas do tematyki Redisa - post możecie go przeczytać
tutaj. Główny wątek polegał na zapoznanu się z możliwościami tego systemu, który stał się bardzo popularny ze względu na swoją szybkość działania.
Administratorów może jednak bardziej zastanawiać jak postawić taki system w replikacji. Zacznijmy od wymienienia kilku podstawowych faktów na ten temat:
- replikacja jest asynchroniczna
- master może mieć wiele slavów, które są tylko read-only
- nie istnieje replikacja master-master
- replikacja jest non-blocking po stronie mastera (gdy podpinany jest nowy slave), a także po stronie slava (dopóki synchronizacja jest inicjalizowana i wykorzystuje plik redis.conf, wykorzystywane są stare dane, który muszą zostać usunięte i zastąpone nowymi).
Przejdźmy do zadań praktycznych. Zacznijmy od uruchomienia 3 serwerów, na tej samej maszynie, które będą działały w replikacji slave-master-slave. Każdy z serwerów będzie miał własny plik konfiguracyjny z własnymi ścieżkami do katalogu danych czy zdefiniowanym numerem portu. Oto jeden z plików konfiguracyjnych:
pidfile /var/run/redis-6389.pid # ścieżka do PID fila
port 6389 # port
loglevel notice
logfile logfile.log
databases 16 # liczba baz danych zaczynając od liczby 0
save 60 10000 # zapis bazy na dysk: save
dbfilename dump-6389.rdb # nazwa pliku z dampem baz danych
dir /home/ela/work/redis_data/redis-6389 # ścieżka do katalogu z danymi
maxclients 100
# Replikacja
slaveof 127.0.0.1 6379 # jak polaczyc sie do mastera
slave-priority 100
Jeśli uruchomimy serwer:
./../redis-2.8.17/src/redis-server /home/ela/work/redis_data/redis-6379/redis-6379-small.conf
w logu zobaczymy następującą informację:
[4026] 28 Oct 19:19:06.832 # Server started, Redis version 2.8.17
[4026] 28 Oct 19:19:06.832 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
[4026] 28 Oct 19:19:06.832 * DB loaded from disk: 0.000 seconds
[4026] 28 Oct 19:19:06.832 * The server is now ready to accept connections on port 6379
[4026 | signal handler] (1414520349) Received SIGINT scheduling shutdown...
[4026] 28 Oct 19:19:09.334 # User requested shutdown...
[4026] 28 Oct 19:19:09.334 * Saving the final RDB snapshot before exiting.
[4026] 28 Oct 19:19:09.376 * DB saved on disk
[4026] 28 Oct 19:19:09.376 # Redis is now ready to exit, bye bye...
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 2.8.17 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in stand alone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 4029
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
[4029] 28 Oct 19:19:16.045 # Server started, Redis version 2.8.17
[4029] 28 Oct 19:19:16.045 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
[4029] 28 Oct 19:19:16.045 * DB loaded from disk: 0.000 seconds
[4029] 28 Oct 19:19:16.045 * The server is now ready to accept connections on port 6379
W logach slava zobaczymy dodatkowo informację o replikacji:
[4054] 28 Oct 19:22:23.536 * Connecting to MASTER 127.0.0.1:6379
[4054] 28 Oct 19:22:23.536 * MASTER <-> SLAVE sync started
[4054] 28 Oct 19:22:23.536 * Non blocking connect for SYNC fired the event.
[4054] 28 Oct 19:22:23.537 * Master replied to PING, replication can continue...
[4054] 28 Oct 19:22:23.537 * Partial resynchronization not possible (no cached master)
[4054] 28 Oct 19:22:23.541 * Full resync from master: 4430276f00317e4fc1b84bedbb1dbb288949b175:1
[4054] 28 Oct 19:22:23.642 * MASTER <-> SLAVE sync: receiving 35 bytes from master
[4054] 28 Oct 19:22:23.642 * MASTER <-> SLAVE sync: Flushing old data
[4054] 28 Oct 19:22:23.642 * MASTER <-> SLAVE sync: Loading DB in memory
[4054] 28 Oct 19:22:23.642 * MASTER <-> SLAVE sync: Finished with success
Testujemy slavy:
ela@skyler:~/work$ ./redis-2.8.17/src/redis-cli -p 6389
127.0.0.1:6389>
127.0.0.1:6389>
127.0.0.1:6389> keys *
1) "test"
2) "test2"
127.0.0.1:6389> set test3 hhhh
(error) READONLY You can't write against a read only slave.
Jeśli z jakiegoś powodu dojdzie do zatrzymania serwera primary (master) w logach slava będziemy mogli zobaczyć następujący komunikat:
[4054] 28 Oct 19:31:21.432 * Connecting to MASTER 127.0.0.1:6379
[4054] 28 Oct 19:31:21.432 * MASTER <-> SLAVE sync started
[4054] 28 Oct 19:31:21.432 # Error condition on socket for SYNC: Connection refused
Ale jak mamy promować nowy master w przypadku padnięcia starego?
Pomocne nam będzie Redis Sentinel. Jest to system stworzony aby pomóc w zarządzaniu instancjami Redisa (szczegółowe informacje znajdziecie na stronie dokumentacji
tutaj). Jest używane do:
- monitorowania
- notyfikacji
- automatyczny failover
- konfiguracji
Skonfigurujmy taki system monitoringu dla naszej replikacji:
ela@skyler:~/work/redis_data/redis-sentinel$ cat sentinel.conf
port 26379
dir /tmp
sentinel monitor mymaster 127.0.0.1 6379 1
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
Powyższy plik konfiguracyjny oznacza, że Redis Sentiel:
- będzie działać na porcie 26379,
- będzie monitorować master mymaster na hoście 127.0.0.1 i porcie standardowym (dla redisa jest to 6379) z liczbą Sentieli wymaganych do wykrycia padnięcia mastera (ten ostatni parametr nie jest wymagany ale bez niego nie dojdzie do automatycznego failovera),
- uzna, że jeśli po 30000 milisekundach proces nadal nie będzie odpowiadać (parametr down-after-milliseconds) to znaczy, że stary master już padł i musi rozpocząć procedurę promowania nowego mastera,
- w tym samym czasie tylko jeden slave może zostać przekonfigurowany aby promować nowego mastera (parametr parallel-syncs)
Przetestujmy nasze rozwiązanie. Po uruchomieniu replikacji, gdzie master pracuje na 127.0.0.1:6379 i mamy dwa działające slavy (127.0.0.1:6389 i 127.0.0.1:6399) uruchomiłam serwer Sentinel (uruchamiamy go przy pomocy specialnej programu
redis-sentinel lub tak jak zwykłą instancję redisa ale z opcją
--sentinel):
ela@skyler:~/work$ ./redis-2.8.17/src/redis-sentinel redis_data/redis-sentinel/sentinel-small.conf
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 2.8.17 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in sentinel mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 26379
| `-._ `._ / _.-' | PID: 3994
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
[3994] 12 Nov 13:40:35.613 # Sentinel runid is 24a06b8417caf25365713a87ad87f1b68239e89e
[3994] 12 Nov 13:40:35.613 # +monitor master mymaster 127.0.0.1 6379 quorum 1
[3994] 12 Nov 13:40:35.614 * +slave slave 127.0.0.1:6389 127.0.0.1 6389 @ mymaster 127.0.0.1 6379
[3994] 12 Nov 13:40:35.614 * +slave slave 127.0.0.1:6399 127.0.0.1 6399 @ mymaster 127.0.0.1 6379
Po ubiciu procesu mastera (127.0.0.1:6379) po chwili w logach Sentinel pojawił się komunikat padnięciu mastera i uruchomieniu procesu failover:
[3994] 12 Nov 13:42:27.956 # +sdown master mymaster 127.0.0.1 6379
[3994] 12 Nov 13:42:27.956 # +odown master mymaster 127.0.0.1 6379 #quorum 1/1
[3994] 12 Nov 13:42:27.956 # +new-epoch 1
[3994] 12 Nov 13:42:27.956 # +try-failover master mymaster 127.0.0.1 6379
[3994] 12 Nov 13:42:27.980 # +vote-for-leader 24a06b8417caf25365713a87ad87f1b68239e89e 1
[3994] 12 Nov 13:42:27.980 # +elected-leader master mymaster 127.0.0.1 6379
[3994] 12 Nov 13:42:27.980 # +failover-state-select-slave master mymaster 127.0.0.1 6379
[3994] 12 Nov 13:42:28.043 # +selected-slave slave 127.0.0.1:6399 127.0.0.1 6399 @ mymaster 127.0.0.1 6379
[3994] 12 Nov 13:42:28.043 * +failover-state-send-slaveof-noone slave 127.0.0.1:6399 127.0.0.1 6399 @ mymaster 127.0.0.1 6379
[3994] 12 Nov 13:42:28.109 * +failover-state-wait-promotion slave 127.0.0.1:6399 127.0.0.1 6399 @ mymaster 127.0.0.1 6379
[3994] 12 Nov 13:42:29.073 # +promoted-slave slave 127.0.0.1:6399 127.0.0.1 6399 @ mymaster 127.0.0.1 6379
[3994] 12 Nov 13:42:29.073 # +failover-state-reconf-slaves master mymaster 127.0.0.1 6379
[3994] 12 Nov 13:42:29.098 * +slave-reconf-sent slave 127.0.0.1:6389 127.0.0.1 6389 @ mymaster 127.0.0.1 6379
[3994] 12 Nov 13:42:30.140 * +slave-reconf-inprog slave 127.0.0.1:6389 127.0.0.1 6389 @ mymaster 127.0.0.1 6379
[3994] 12 Nov 13:42:30.140 * +slave-reconf-done slave 127.0.0.1:6389 127.0.0.1 6389 @ mymaster 127.0.0.1 6379
[3994] 12 Nov 13:42:30.206 # +failover-end master mymaster 127.0.0.1 6379
[3994] 12 Nov 13:42:30.206 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6399
[3994] 12 Nov 13:42:30.206 * +slave slave 127.0.0.1:6389 127.0.0.1 6389 @ mymaster 127.0.0.1 6399
[3994] 12 Nov 13:42:30.241 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6399
[3994] 12 Nov 13:43:00.298 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6399
Slave, który działał na porcie 6399 został promowany na nowego mastera. Redis Sentiel zaktualizował swój plik konfiguracyjny na:
ela@skyler:~/work/redis_data/redis-sentinel$ cat sentinel-small.conf
port 26379
dir "/tmp"
sentinel monitor mymaster 127.0.0.1 6399 1
sentinel config-epoch mymaster 1
sentinel leader-epoch mymaster 1
sentinel known-slave mymaster 127.0.0.1 6379
# Generated by CONFIG REWRITE
maxclients 4064
sentinel known-slave mymaster 127.0.0.1 6389
sentinel current-epoch 1
Sprawdźmy czy nasze instancje Redis naprawdę działają, tak jak to przedstawia proces Sentinel:
ela@skyler:~/work$ ./redis-2.8.17/src/redis-cli -p 6399
127.0.0.1:6399> keys *
1) "test2"
2) "test"
127.0.0.1:6399> set test3 hhhh
OK
127.0.0.1:6399> keys *
1) "test2"
2) "test3"
3) "test"
127.0.0.1:6399> quit
ela@skyler:~/work$
ela@skyler:~/work$
ela@skyler:~/work$
ela@skyler:~/work$ ./redis-2.8.17/src/redis-cli -p 6389
127.0.0.1:6389> keys *
1) "test3"
2) "test"
3) "test2"
127.0.0.1:6389> set test4 hhhh
(error) READONLY You can't write against a read only slave.
127.0.0.1:6389> quit
ela@skyler:~/work$
ela@skyler:~/work$
ela@skyler:~/work$
ela@skyler:~/work$ ./redis-2.8.17/src/redis-cli -p 6379
Could not connect to Redis at 127.0.0.1:6379: Connection refused
not connected>
not connected>
not connected>
not connected> quit
Gdy uruchomimy starego mastera (6379) do działania, zostanie on wykryty przez system monitoringu i podpięty do replikacji jako slave. Log z procesu Redis Sentinel:
[3994] 12 Nov 14:03:32.875 # -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6399
[3994] 12 Nov 14:03:42.831 * +convert-to-slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6399
Dodatkowo pliki konfiguracujne naszych instancji Redisa w replikacji zostały zmienione tak, aby miały jak naświeższą informację na temat, który z nich jest masterem, a który slavem (parametr
slaveof).
Oto plik konfiguracyjny starego mastera:
ela@skyler:~/work/redis_data/redis-6379$ cat redis-6379-small.conf
##############################################################################
### Master !!!
pidfile "/var/run/redis-6379.pid"
port 6379
loglevel notice
logfile "logfile.log"
databases 16
save 60 10000
dbfilename "dump-6379.rdb"
dir "/home/ela/work/redis_data/redis-6379"
maxclients 100
# Generated by CONFIG REWRITE
slaveof 127.0.0.1 6399
Jest to na tyle szeroki temat, że trzeba go rozbić na kilka postów aby móc poznać ten system dobrze. Więcej informacji znajdziecie, na stronie projektu dotyczącej
replikacji i
Redis Sentinel. Mam nadzieję, że ten post zachęcił Was do zapoznania się z tym tematem.