データの写しを持つ
レプリケーションとは、同じデータの写しを複数の機械に持たせることです。1台が壊れても、別の写しからデータを読めるので、サービスを続けられます。
映画館の座席予約を考えましょう。予約のデータが1台にしかなければ、その機械が壊れた瞬間に、誰も席を見られません。
このレッスンのゴール
メモ
データの写しがどう保たれ、故障が起きると何が起こるかを説明できます。
キーワード
| ことば | いみ |
|---|---|
| レプリケーション | 同じデータの写しを、複数の機械に持たせること |
| プライマリ | 書き込みを最初に受け取る機械 |
| レプリカ | プライマリの変更を追いかけて、写しを持つ機械 |
| 書き込みログ | 変更を起きた順に書き足した記録 |
| フェイルオーバー | 故障したプライマリを、レプリカに交代させること |
| 複製の遅れ | レプリカがまだ受け取っていない変更の数 |
学生が入力するセルは、このプレビューでは空白です。
プライマリが書き込み、レプリカが追いかける
最も多い作りは、プライマリとレプリカに分けるものです。書き込みは、まずプライマリが受け取ります。
プライマリは、変更を書き込みログに順に記録し、その記録をレプリカに送ります。レプリカは、同じ順に変更を当てはめます。読み取りは、プライマリでもレプリカでも受けられます。
小さなクライアント v を作る
v() ( printf '%s\r\n' "$*" | nc -w 1 valkey 6379 )ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
この機械の役割と、写しの数を尋ねる
v INFO replication | grep -E "role|connected_slaves"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
書き込みをファイルに記録しているか尋ねる
v CONFIG GET appendonlyここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
ラボの1台も、ログという写しを持つ
ラボのValkeyはプライマリで、レプリカは0台です。ただし、すべての書き込みを、ファイルに順に記録しています。これも書き込みログです。
機械を止めて起動し直しても、ログを読み直せば、同じ状態に戻れます。レプリカも、同じログを受け取って、同じ状態になります。
座席を1つ入れる
v SET ds:seat:a1 reservedここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
座席の状態を読む
v GET ds:seat:a1ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
例: どの写しがいちばん新しいか
| 写し | 受け取った書き込み | 遅れ |
|---|---|---|
| プライマリ(ログに5件) | 5件 | 0件 |
| レプリカ1 | 5件 | 0件 |
| レプリカ2 | 3件 | 2件 |
学生が入力するセルは、このプレビューでは空白です。
レプリカが追いかける様子
# プライマリの書き込みログを、レプリカが少し遅れて追いかけます。
log = ["SET a 1", "SET b 2", "SET c 3", "SET d 4"]
position = 2
print("受け取った書き込み:", log[:position])
print("まだ届いていない書き込み:", log[position:])
# position を 4 に変えると、遅れはなくなります。
プライマリが壊れたら、レプリカに交代する
プライマリが壊れたら、レプリカの1台を新しいプライマリにします。これがフェイルオーバーです。選ぶのは、いちばん多くの書き込みを受け取っている写しです。
ただし、壊れた瞬間にまだ届いていなかった書き込みは、どの写しにも残りません。
同期と非同期のちがい
| 方法 | 書き込みの応答 | 故障で失うもの | 速さ |
|---|---|---|---|
| 同期 | レプリカが受け取ってから返す | ほとんどない | 遅い |
| 非同期 | プライマリが受け取ったら返す | 届いていない分 | 速い |
学生が入力するセルは、このプレビューでは空白です。
どの写しを昇格させるか
# 書き込みログと、各レプリカがどこまで受け取ったかの記録です。
log = ["SET a 1", "SET b 2", "SET c 3", "SET d 4", "SET e 5"]
copies = {"replica1": 5, "replica2": 3}
best = "replica1"
for name in copies:
if copies[name] > copies[best]:
best = name
print("昇格させる写し:", best)
print("失われる書き込みの数:", len(log) - copies[best])
# replica1 の 5 を 2 に変えて、もう一度実行してみましょう。
よくある間違い
注意
レプリカがあれば、データは絶対に失われないと考えがちです。写しの更新は、少し遅れます。非同期のとき、故障の瞬間にまだ届いていない書き込みは、どの写しにも残りません。