何が起きたか
アプリがRedisレプリカから読み取りを行っていました。レプリカがマスターへの接続を失い、すべての読み取りコマンドが次のエラーをスローするようになりました:
MASTERDOWN Link with MASTER is down and replica-serve-stale-data is set to 'no'
原因はレプリカの replica-serve-stale-data no 設定です。このフラグが無効になっていると、接続が切れたレプリカは INFO と REPLICAOF 以外のすべてのコマンド(読み取りを含む)を拒否します。これはクライアントに古いデータが届くのを防ぐ安全機能ですが、事前に対策をしていない場合、アプリは完全に停止してしまいます。
レプリカが接続を失った原因
すぐに修正に飛びつくのは禁物です。まず何が壊れたのかを特定してください。そうしないと1時間後に同じ問題に直面することになります。よくある原因:
- マスターのRedisプロセスがクラッシュまたは再起動した
- レプリカとマスターホスト間でネットワーク分断が発生した
- Sentinelフェイルオーバー中にマスターが昇格し、レプリカが古いIPを指したままになっている
- マスターが過負荷になり、
repl-timeout(デフォルト: 60秒)以内にPINGに応答できていない - ファイアウォールルールがレプリケーションポート(デフォルト: 6379)をブロックしている
まずレプリカのログを確認しましょう:
# レプリカホスト上で
tail -n 100 /var/log/redis/redis-server.log
# またはログファイルの場所に応じて
redis-cli -h replica-host INFO replication
Connection with master lost、Connecting to MASTER、または MASTER abort といった行を探してください。これらからリンクが切れた時刻がわかり、根本原因調査の出発点になります。
クイックフィックス: 読み取りをすぐに復旧させる
今すぐ読み取りを復旧させる必要がありますか? replica-serve-stale-data を実行時に yes に設定してください — 再起動は不要です:
redis-cli -h replica-host CONFIG SET replica-serve-stale-data yes
レプリカはメモリ内のデータが古くても即座に提供を開始します。それが許容できるかどうかは保存しているデータの種類によります。キャッシュであれば数分の遅延は通常問題ありません。金融状態や分散ロックの場合はおそらく許容できません。
Redis 3.x以前では、設定キーの名前が異なります:
# Redis 3.x以下
redis-cli CONFIG SET slave-serve-stale-data yes
接続問題そのものを修正する
1. マスターに到達できるか確認する
# レプリカホストから基本的な疎通を確認
redis-cli -h master-host -p 6379 PING
# 期待値: PONG
# ポートが開いているか確認
nc -zv master-host 6379
PONGが返ってこない場合はネットワークまたはファイアウォールの問題です。他の作業より先にそちらを解決してください。
2. レプリケーション状態を確認する
redis-cli -h replica-host INFO replication
以下のフィールドに注目してください:
role:slave
master_host:192.168.1.10
master_port:6379
master_link_status:down # これが問題
master_last_io_seconds_ago:X
master_sync_in_progress:0
master_link_status が down の場合、レプリカは master_host:master_port に到達できていません。master_last_io_seconds_ago を確認してリンクがいつ切れたかを把握し、デプロイログや監視アラートと照らし合わせましょう。
3. マスターのIPが変わった場合はレプリカの向き先を更新する
Sentinelフェイルオーバーではマスターが新しいホストに移動します。レプリカは古いアドレスを指したままになります。更新してください:
# Redis 4.0以上
redis-cli -h replica-host REPLICAOF new-master-host 6379
# Redis 3.x
redis-cli -h replica-host SLAVEOF new-master-host 6379
4. マスターが復旧したがリンクが回復しない場合は強制再接続する
マスターが復旧しても、レプリカが自力で再接続せずにスタックしたままになることがあります。以下の2ステップでリンクをリセットします:
redis-cli -h replica-host REPLICAOF NO ONE
redis-cli -h replica-host REPLICAOF master-host 6379
レプリカは一時的にスタンドアロンになり、その後レプリケーションを再確立します。レプリカのデータが大幅に遅れている場合は完全な再同期がトリガーされます。
恒久的な修正: replica-serve-stale-dataの適切な値を決める
適切な値は保存しているデータの種類と、古い読み取りが実際にどれほど問題になるかによって完全に異なります:
yesに設定する(デフォルト) — マスターに到達できないときレプリカが古いデータを提供します。数分の遅延が許容できるキャッシュに適しています。レプリケーションの断絶中もアプリが稼働し続けます。noに設定する — 切断時にレプリカがすべての読み取りを拒否します。古い読み取りが本当に危険な場合のみ使用してください: セッション検証、分散ロック、金融状態など。マスターのダウン中はエラーが発生することを想定してください。
再起動後も設定が維持されるよう /etc/redis/redis.conf に永続化します:
# レプリカのredis.conf内
replica-serve-stale-data yes # または選択に応じてno
# 再起動なしで適用
redis-cli -h replica-host CONFIG REWRITE
またはファイルを編集してRedisを再起動します:
sudo systemctl restart redis
接続が不安定な場合はrepl-timeoutも調整する
大量の書き込み負荷がかかっているマスターはPINGへの応答に10〜20秒かかることがあります。明確な原因なくレプリカがマスターリンクを繰り返し切断する場合は、タイムアウトを延長してください:
# redis.conf内
repl-timeout 120 # デフォルトは60秒
repl-ping-replica-period 10 # レプリカがマスターをpingする間隔
確認
解決済みとする前に、レプリカが実際に同期されており読み取りが正常に流れていることを確認してください:
# レプリケーションリンクを確認
redis-cli -h replica-host INFO replication | grep master_link_status
# 期待値: master_link_status:up
# 読み取りが機能することを確認
redis-cli -h replica-host GET some-key
# 設定値が保持されていることを確認
redis-cli -h replica-host CONFIG GET replica-serve-stale-data
Redis 3.xでは代わりに CONFIG GET slave-serve-stale-data を使用してください。
マスターにテストキーを書き込み、レプリカから読み返してレプリケーションがエンドツーエンドで実際に機能していることを確認します:
redis-cli -h master-host SET test-replication ok
redis-cli -h replica-host GET test-replication
# 期待値: "ok"
ElastiCacheまたはマネージドRedisを使用している場合
ElastiCacheではredis.confを直接編集できません。AWSコンソールを開き、クラスターにアタッチされているパラメータグループを見つけ、replica-serve-stale-data を設定して保存してください。Redis 6.x以上では再起動なしで変更が適用されます。古いバージョンではクラスターノードの再起動が必要で、再起動中は一時的な読み取りの中断が発生します。

