TL;DR
Bạn đã gửi lệnh ghi (SET, DEL, INCR, v.v.) đến node replica của Redis. Replica mặc định chỉ đọc — không chấp nhận lệnh ghi. Hãy kết nối đến node master thay thế. Hoặc nếu có lý do cụ thể, tạm thời cho phép ghi trên replica bằng CONFIG SET replica-read-only no.
Tại Sao Lỗi Này Xảy Ra
Luồng replication của Redis chỉ đi một chiều: master → replica(s). Replica liên tục đồng bộ dữ liệu từ master và từ chối mọi lệnh ghi với thông báo:
(error) DENY COMMANDS ASKING WRITE. REPLICA can't execute write commands.
Một số tình huống thường gặp:
- Bạn hardcode IP/port của replica trong config ứng dụng và quên cập nhật sau khi failover.
- Redis Sentinel đã promote master mới, nhưng client vẫn đang trỏ vào node cũ — hiện đã thành replica.
- Bạn kết nối nhầm port. Trong cấu hình hai node thông thường,
6379là master và6380là replica, nhưng điều này có thể khác nhau. - Connection pool của bạn round-robin qua các node mà không biết node nào là master.
Kiểm Tra Bạn Đang Ở Node Nào
Chạy lệnh ROLE qua redis-cli để xem role của node ngay lập tức:
redis-cli -h <host> -p <port> ROLE
Một replica trả về kết quả như sau:
1) "slave"
2) "192.168.1.10"
3) (integer) 6379
4) "connected"
5) (integer) 12345
Một master trả về kết quả như sau:
1) "master"
2) (integer) 12345
3) 1) 1) "192.168.1.11"
2) "6379"
3) "12345"
Thấy slave trong kết quả? Bạn đang ở sai node để thực hiện lệnh ghi.
Cách Sửa 1: Kết Nối Đến Node Master (Khuyến Nghị)
Chạy ROLE trên từng node để tìm master, hoặc dùng INFO replication:
redis-cli -h <host> -p <port> INFO replication
Tìm dòng role:master. Host và port đó là nơi tất cả lệnh ghi cần được gửi đến.
Cấu Hình Redis Sentinel
Bỏ hoàn toàn việc hardcode IP. Hỏi Sentinel xem node nào đang là master:
redis-cli -h <sentinel-host> -p 26379 SENTINEL get-master-addr-by-name mymaster
Lệnh này trả về IP và port của master hiện tại — kể cả sau khi failover. Tốt hơn nữa, hãy dùng client hỗ trợ Sentinel để ứng dụng không bao giờ cần hỏi thủ công:
# 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') # Luôn route đến master hiện tại
Cấu Hình Redis Cluster
Client hỗ trợ cluster xử lý việc route slot đến master tự động. Không cần chọn node thủ công:
# Python (redis-py cluster)
from redis.cluster import RedisCluster
rc = RedisCluster(host='node1', port=6379, decode_responses=True)
rc.set('key', 'value') # Client tự xác định shard master nào sở hữu key này
Cách Sửa 2: Cho Phép Ghi Trên Replica (Chỉ Dùng Để Test)
Đôi khi bạn thực sự cần ghi vào replica — chẳng hạn khi test ở local hoặc thực hiện một bước migration đơn lẻ. Tắt chế độ read-only ngay tại runtime:
redis-cli -h <replica-host> -p <port> CONFIG SET replica-read-only no
Với Redis cũ hơn phiên bản 5.0, tên config key có khác:
redis-cli -h <replica-host> -p <port> CONFIG SET slave-read-only no
Cảnh báo: Bất kỳ dữ liệu nào bạn ghi trực tiếp vào replica sẽ bị xóa vào lần đồng bộ tiếp theo từ master. Điều này gây ra tình trạng phân kỳ dữ liệu. Tuyệt đối không dùng cách này trên môi trường production nếu không có kế hoạch rõ ràng.
Để thay đổi này tồn tại sau khi khởi động lại, hãy chỉnh sửa redis.conf trên replica:
replica-read-only no
Sau đó khởi động lại Redis:
sudo systemctl restart redis
Cách Sửa 3: Sau Failover — Cập Nhật Config Ứng Dụng
Sentinel hoặc Cluster đã kích hoạt failover. Ứng dụng của bạn vẫn đang hardcode địa chỉ master cũ — hiện đã thành replica. Hãy cập nhật config:
# Trước failover (cũ — đang trỏ vào replica)
REDIS_HOST=192.168.1.10
REDIS_PORT=6379
# Sau failover (đúng — master mới)
REDIS_HOST=192.168.1.11
REDIS_PORT=6379
Cách này giải quyết vấn đề trước mắt. Về lâu dài, hãy chuyển sang dùng client Sentinel hoặc Cluster. Ứng dụng của bạn sẽ tự xử lý các lần failover trong tương lai mà không cần chỉnh sửa config.
Xác Nhận Đã Sửa Xong
Đã trỏ vào master? Chạy thử một vòng ghi/đọc/xóa để xác nhận:
redis-cli -h <master-host> -p 6379 SET testkey "hello"
# Kết quả mong đợi: OK
redis-cli -h <master-host> -p 6379 GET testkey
# Kết quả mong đợi: "hello"
redis-cli -h <master-host> -p 6379 DEL testkey
# Kết quả mong đợi: (integer) 1
Cũng kiểm tra xem quá trình replication có đang hoạt động bình thường không:
redis-cli -h <master-host> -p 6379 INFO replication | grep -E 'role|connected_slaves|slave'
Kết quả cần có role:master và ít nhất một slave đang kết nối.
Tóm Tắt Nhanh: Bạn Đang Dùng Cấu Hình Nào?
- Replica độc lập: Chạy
ROLEtrên từng node để tìm master, rồi kết nối trực tiếp vào đó. - Redis Sentinel: Dùng
SENTINEL get-master-addr-by-name, hoặc tốt hơn — dùng thư viện client hỗ trợ Sentinel. - Redis Cluster: Dùng client hỗ trợ cluster. Nó tự động route lệnh ghi đến shard master phù hợp.

