Redisの「DENY COMMANDS ASKING WRITE. REPLICA can't execute write commands.」エラーの修正方法

intermediate🔴 Redis2026-03-21| Redis 2.6以降、Redis Cluster、Redis Sentinel、すべてのOS(Linux/macOS/Windows)

Error Message

(error) DENY COMMANDS ASKING WRITE. REPLICA can't execute write commands.
#redis#レプリケーション#レプリカ#書き込み

TL;DR

書き込みコマンド(SET、DEL、INCRなど)をRedisのレプリカノードに送信しました。レプリカはデフォルトで読み取り専用です——書き込みを受け付けません。代わりにマスターノードに接続してください。または、特別な理由がある場合は、CONFIG SET replica-read-only noでレプリカへの書き込みを一時的に許可できます。

このエラーが発生する理由

Redisのレプリケーションは一方向です:マスター → レプリカ。レプリカはマスターからデータを継続的に同期し、すべての書き込みコマンドを以下のエラーで拒否します:

(error) DENY COMMANDS ASKING WRITE. REPLICA can't execute write commands.

よくある原因はいくつかあります:

  • アプリの設定にレプリカのIP/ポートをハードコードしており、フェイルオーバー後に更新し忘れた。
  • Redis Sentinelが新しいマスターに昇格させたが、クライアントはまだ古いノード——今はレプリカ——を指している。
  • 間違ったポートに接続している。一般的な2ノード構成では6379がマスターで6380がレプリカだが、環境によって異なる。
  • コネクションプールがどのノードがマスターか把握せずにノード間でラウンドロビンしている。

接続中のノードを確認する

redis-cliROLEを実行すると、ノードの役割をすぐに確認できます:

redis-cli -h <host> -p <port> ROLE

レプリカの場合、次のように応答します:

1) "slave"
2) "192.168.1.10"
3) (integer) 6379
4) "connected"
5) (integer) 12345

マスターの場合、次のように応答します:

1) "master"
2) (integer) 12345
3) 1) 1) "192.168.1.11"
      2) "6379"
      3) "12345"

出力にslaveが表示されていますか?書き込みには間違ったノードに接続しています。

修正1:マスターノードに接続する(推奨)

各ノードでROLEを実行してマスターを見つけるか、INFO replicationを使用します:

redis-cli -h <host> -p <port> INFO replication

role:masterの行を探してください。そのホストとポートがすべての書き込みの送信先です。

Redis Sentinelの構成

IPのハードコードは完全に避けましょう。Sentinelに現在のマスターノードを問い合わせます:

redis-cli -h <sentinel-host> -p 26379 SENTINEL get-master-addr-by-name mymaster

フェイルオーバー後でも、現在のマスターのIPとポートが返されます。さらに良いのは、Sentinel対応クライアントを使用することで、アプリが手動で問い合わせる必要がなくなります:

# Python (redis-py)
from redis.sentinel import Sentinel

sentinel = Sentinel(
    [('sentinel-host', 26379)],
    socket_timeout=0.1
)
master = sentinel.master_for('mymaster', socket_timeout=0.1)
master.set('key', 'value')  # 常に現在のマスターにルーティングされる

Redis Clusterの構成

Cluster対応クライアントはスロットからマスターへのルーティングを自動的に処理します。手動でノードを選択する必要はありません:

# Python (redis-py cluster)
from redis.cluster import RedisCluster

rc = RedisCluster(host='node1', port=6379, decode_responses=True)
rc.set('key', 'value')  # このキーを担当するシャードマスターをクライアントが自動判断する

修正2:レプリカへの書き込みを許可する(テスト用のみ)

ローカルテストやワンタイムのマイグレーション作業など、レプリカへの書き込みが本当に必要な場合があります。実行時に読み取り専用モードを無効にします:

redis-cli -h <replica-host> -p <port> CONFIG SET replica-read-only no

Redis 5.0より古いバージョンでは、設定キーの名前が異なります:

redis-cli -h <replica-host> -p <port> CONFIG SET slave-read-only no

**警告:**レプリカに直接書き込んだデータは、次回マスターが同期するときに消去されます。これによりデータの乖離が発生します。明確な計画なしに本番環境では絶対に使用しないでください。

再起動後も変更を維持するには、レプリカのredis.confを編集します:

replica-read-only no

その後、Redisを再起動します:

sudo systemctl restart redis

修正3:フェイルオーバー後——アプリの設定を更新する

SentinelまたはClusterがフェイルオーバーをトリガーしました。アプリはまだ古いマスターのアドレス——現在はレプリカ——にハードコードされています。設定を更新します:

# フェイルオーバー前(古い設定——レプリカを指している)
REDIS_HOST=192.168.1.10
REDIS_PORT=6379

# フェイルオーバー後(正しい設定——新しいマスター)
REDIS_HOST=192.168.1.11
REDIS_PORT=6379

これで短期的には解決します。長期的には、SentinelまたはClusterクライアントに切り替えましょう。アプリが将来のフェイルオーバーを自動的に処理するため、設定の変更は不要になります。

修正を確認する

マスターを指しましたか?簡単な書き込み/読み取り/削除のサイクルを実行して確認します:

redis-cli -h <master-host> -p 6379 SET testkey "hello"
# 期待される結果: OK

redis-cli -h <master-host> -p 6379 GET testkey
# 期待される結果: "hello"

redis-cli -h <master-host> -p 6379 DEL testkey
# 期待される結果: (integer) 1

レプリケーション自体が正常かどうかも確認します:

redis-cli -h <master-host> -p 6379 INFO replication | grep -E 'role|connected_slaves|slave'

出力にrole:masterと少なくとも1つの接続済みスレーブが表示されていることを確認してください。

クイックリファレンス:どの構成を使用していますか?

  • スタンドアロンレプリカ:各ノードでROLEを実行してマスターを見つけ、直接接続する。
  • Redis SentinelSENTINEL get-master-addr-by-nameを使用するか、さらに良いのはSentinel対応クライアントライブラリを使用する。
  • Redis Cluster:Cluster対応クライアントを使用する。書き込みを正しいシャードマスターに自動的にルーティングする。

Related Error Notes