W części poprzedniej przyjrzeliśmy się podstawom partycjonowania danych w klastrze Redis.
W tym artykule zajmiemy się podstawowym scenariuszem replikacji.
Oczywiście należy mieć na uwadze wiele niuansów, które tutaj zostaną pominięte. Wśród nich są jednak istotne kwestie bezpieczeństwa i integralności danych opisane w dokumentacji, a m.in.:
- asynchroniczna natura replikacji (strumieniowanie, opóźnienia)
- persystencja danych
- autentykacja
- replikacja TTL (wygasanie kluczy)
Zdecydowanie zachęcam do zapoznania się z dokumentacją.
Tutaj zajmiemy się jedynie replikacją w zakresie podstawowym - bez klastra oraz Sentinel, które zapewniają wysoką dostępność (high availablity), czy automatyczny failover.
Konfiguracja master oraz replik
Zrealizujemy scenariusz z jedną instancją master oraz dwiema replikami. W takim scenariuszu instancje replik Redis są domyślnie w trybie read-only. Zapisy wykonujemy na instancji master, a odczytów możemy dokonywać na wszystkich instancjach. Należy jednak mieć na uwadze ewentualne opóźnienie.
$ tree configs/
configs/
├── master.conf
├── replica-1.conf
└── replica-2.conf
0 directories, 3 files
Plik configs/master.conf
:
daemonize yes
bind 0.0.0.0
port 16001
pidfile ./run/master-A.pid
Plik configs/replica-1.conf
:
daemonize yes
bind 0.0.0.0
port 17001
pidfile ./run/replica-1.pid
replicaof 127.0.0.1 16001
Plik configs/replica-2.conf
:
daemonize yes
bind 0.0.0.0
port 17002
pidfile ./run/replica-2.pid
replicaof 127.0.0.1 16001
Uruchamiamy instancje
Start:
$ redis-server configs/master.conf
$ redis-server configs/replica-1.conf
$ redis-server configs/replica-2.conf
Wyświetlamy stan replikacji dla instancji master:
$ redis-cli -p 16001 info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=17001,state=online,offset=210,lag=0
slave1:ip=127.0.0.1,port=17002,state=online,offset=210,lag=0
master_replid:dc6e272c994fbebae0d7019f8f655131eecb0975
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:210
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:210
Możemy również sprawdzić stan instancji w roli 'slave':
$ redis-cli -p 17001 info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:16001
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:252
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:dc6e272c994fbebae0d7019f8f655131eecb0975
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:252
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:252
Sprawdzamy zapis i odczyt
$ redis-cli -p 16001 set x 987
OK
$ redis-cli -p 17001 get x
"987"
$ redis-cli -p 17002 get x
"987"
REPLICAOF
Komendą REPLICAOF
możemy zarówno wyłączyć replikację, jak i włączyć replikację z danej instancji.
Przykładowo: wyłączamy replikację na instancji replica-2
(port 17002).
$ redis-cli -p 17002
127.0.0.1:17002> REPLICAOF no one
OK
W tym momencie nasza instancja master posiada tylko jedną replikę:
$ redis-cli -p 16001 info replication | head -n 3
# Replication
role:master
connected_slaves:1
Jeśli sprawdzimy stan replikacji dla replica-2
- zauważymy, że serwer działa w trybie master i nie ma żadnych replik.
$ redis-cli -p 17002 info replication | head -n 3
# Replication
role:master
connected_slaves:0
Dane zapisywane na master nie będą replikowane na replica-2
:
$ redis-cli -p 16001 set foo bar
OK
$ redis-cli -p 17001 get foo
"bar"
$ redis-cli -p 17002 get foo
(nil)
Replikacja kaskadowa
Replikacja może odbywać się z dowolnej instancji, uzyskamy wtedy replikację kaskadową (master -> replica -> replica):
$ redis-cli -p 17002
127.0.0.1:17002> REPLICAOF 127.0.0.1 17001
OK
Zapis i odczyt:
$ redis-cli -p 16001 set hello world
OK
$ redis-cli -p 17001 get hello
"world"
$ redis-cli -p 17002 get hello
"world"
Jeśli powrócimy do replikacji instancji master, na replice pojawią się również dane zapisane wcześniej pod kluczem 'foo', które nie były replikowane.
127.0.0.1:17002> REPLICAOF 127.0.0.1 16001
OK
127.0.0.1:17002>
$ redis-cli -p 17002 get foo
"bar"
Replikacja w Redis zapamiętuje offset
("punkt w historii danych"). Serwer replikujący synchronizuje się do punktu w czasie odpowiadającego instancji master.
Promocja instancji do roli master
W przypadku kiedy nie używamy trybu klastra, ani Redis Sentinel
, promocję instancji do roli master możemy wykonać ręcznie przy użyciu komendy REPLICAOF.
W tym scenariuszu wyłączymy instancję master, przełączymy replica-2
do roli master, a instancję replica-1
przekonfigurujemy na replikę nowego mastera.
$ cat run/master-A.pid | xargs kill
$ redis-cli -p 17002 -c replicaof no one
OK
$ redis-cli -p 17001 -c replicaof 127.0.0.1 17002
OK
Po tym zabiegu instancja na porcie 17002 działa w roli master, a serwer na porcie 17001 replikuje z niej dane.
(instancja 17002, nowy master):
$ redis-cli -p 17002 info replication | head -5
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=17001,state=online,offset=2526,lag=0
master_replid:2c93f3fe047448399e470dc08153ca50ea3dfd3c
Replika z nowego mastera:
$ redis-cli -p 17001 info replication | head -5
# Replication
role:slave
master_host:127.0.0.1
master_port:17002
master_link_status:up
Podsumowanie
Przybliżyliśmy tutaj jedynie podstawy replikacji w Redis, które umożliwiają wstępne zapoznanie się z samym mechanizmem i komendami. W przyszłych częściach tej serii przyjrzymy się bardziej zaawansowanym scenariuszom oraz rozwiązaniom zapewniającym pewien stopień automatyzacji promocji repliki do instancji master.