Chuyện gì đã xảy ra
Ứng dụng của bạn đang đọc dữ liệu từ một Redis replica. Replica đó mất kết nối đến master, và bây giờ mọi lệnh đọc đều trả về lỗi:
MASTERDOWN Link with MASTER is down and replica-serve-stale-data is set to 'no'
Thủ phạm là cấu hình replica-serve-stale-data no trên replica. Khi tắt flag này, một replica bị mất kết nối sẽ từ chối toàn bộ lệnh ngoại trừ INFO và REPLICAOF — kể cả lệnh đọc. Đây là tính năng bảo vệ để ngăn dữ liệu cũ đến tay client, nhưng nếu bạn chưa có phương án dự phòng, nó sẽ làm ứng dụng của bạn sập hoàn toàn.
Tại sao replica mất kết nối
Đừng vội vàng xử lý ngay. Hãy tìm ra nguyên nhân trước, không thì một tiếng nữa bạn lại quay lại đây. Các nguyên nhân thường gặp:
- Tiến trình Redis master bị crash hoặc được khởi động lại
- Mạng bị phân tách giữa host của replica và master
- Master đã được thăng cấp trong quá trình Sentinel failover và replica vẫn đang trỏ vào IP cũ
- Master quá tải, không phản hồi PING trong thời gian
repl-timeout(mặc định: 60 giây) - Một quy tắc firewall đã chặn cổng replication (mặc định 6379)
Bắt đầu bằng cách kiểm tra log của replica:
# Trên host của replica
tail -n 100 /var/log/redis/redis-server.log
# Hoặc nơi lưu log của bạn
redis-cli -h replica-host INFO replication
Tìm các dòng như Connection with master lost, Connecting to MASTER, hoặc MASTER abort. Những dòng này cho bạn biết thời điểm kết nối bị ngắt và là điểm khởi đầu để tìm nguyên nhân gốc rễ.
Cách xử lý nhanh: khôi phục lệnh đọc ngay lập tức
Cần cho phép đọc dữ liệu ngay bây giờ? Đặt replica-serve-stale-data thành yes ở runtime — không cần khởi động lại:
redis-cli -h replica-host CONFIG SET replica-serve-stale-data yes
Replica sẽ lập tức phục vụ dữ liệu hiện có trong bộ nhớ, dù dữ liệu đó có thể đã cũ. Việc này có chấp nhận được hay không phụ thuộc vào dữ liệu bạn lưu trữ. Với cache, độ trễ vài phút thường không thành vấn đề. Với trạng thái tài chính hay distributed lock thì có thể không ổn.
Trên Redis 3.x và cũ hơn, tên config key có khác:
# Redis 3.x trở xuống
redis-cli CONFIG SET slave-serve-stale-data yes
Khắc phục vấn đề kết nối thực sự
1. Kiểm tra xem master có truy cập được không
# Từ host của replica, kiểm tra kết nối cơ bản
redis-cli -h master-host -p 6379 PING
# Kết quả mong đợi: PONG
# Kiểm tra cổng có mở không
nc -zv master-host 6379
Không có PONG? Đó là vấn đề mạng hoặc firewall. Hãy giải quyết điều đó trước tiên.
2. Kiểm tra trạng thái replication
redis-cli -h replica-host INFO replication
Chú ý các trường sau:
role:slave
master_host:192.168.1.10
master_port:6379
master_link_status:down # Đây là vấn đề
master_last_io_seconds_ago:X
master_sync_in_progress:0
Khi master_link_status là down, replica không thể kết nối đến master_host:master_port. Kiểm tra master_last_io_seconds_ago để biết kết nối bị ngắt bao lâu rồi — hữu ích để đối chiếu với log triển khai hoặc cảnh báo giám sát.
3. Trỏ lại replica nếu IP master đã thay đổi
Sentinel failover chuyển master sang host mới. Replica vẫn trỏ vào địa chỉ cũ. Hãy cập nhật lại:
# 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. Buộc kết nối lại nếu master đã phục hồi nhưng kết nối chưa tự khôi phục
Đôi khi master đã hoạt động trở lại nhưng replica vẫn ở trạng thái treo, không tự kết nối lại. Hai bước sau sẽ thiết lập lại kết nối:
redis-cli -h replica-host REPLICAOF NO ONE
redis-cli -h replica-host REPLICAOF master-host 6379
Replica sẽ tạm thời trở thành standalone, sau đó thiết lập lại replication. Nếu dữ liệu của replica lệch quá nhiều so với master, quá trình full resync sẽ được kích hoạt.
Cách xử lý dứt điểm: quyết định giá trị phù hợp cho replica-serve-stale-data
Giá trị phù hợp phụ thuộc hoàn toàn vào dữ liệu bạn lưu và mức độ ảnh hưởng khi đọc dữ liệu cũ:
- Đặt thành
yes(mặc định) — replica phục vụ dữ liệu cũ khi không kết nối được master. Phù hợp với cache khi độ trễ vài phút là chấp nhận được. Ứng dụng vẫn hoạt động trong thời gian replication bị gián đoạn. - Đặt thành
no— replica từ chối mọi lệnh đọc khi mất kết nối. Chỉ dùng khi dữ liệu cũ thực sự gây nguy hiểm: xác thực phiên, distributed lock, trạng thái tài chính. Hãy chuẩn bị cho việc ứng dụng trả lỗi mỗi khi master có downtime.
Lưu cấu hình vào /etc/redis/redis.conf để giữ nguyên sau khi khởi động lại:
# Trong redis.conf trên replica
replica-serve-stale-data yes # hoặc no, tùy lựa chọn của bạn
# Áp dụng mà không cần khởi động lại
redis-cli -h replica-host CONFIG REWRITE
Hoặc chỉnh sửa file rồi khởi động lại Redis:
sudo systemctl restart redis
Cũng nên điều chỉnh repl-timeout nếu kết nối hay bị gián đoạn
Một master đang chịu tải ghi nặng có thể mất 10–20 giây để phản hồi PING. Nếu replica của bạn liên tục mất kết nối master mà không rõ nguyên nhân, hãy tăng timeout lên:
# Trong redis.conf
repl-timeout 120 # mặc định là 60 giây
repl-ping-replica-period 10 # tần suất replica ping master
Kiểm tra lại
Trước khi đánh dấu đã xử lý xong, hãy xác nhận replica đã đồng bộ và lệnh đọc đang hoạt động bình thường:
# Kiểm tra kết nối replication
redis-cli -h replica-host INFO replication | grep master_link_status
# Kết quả mong đợi: master_link_status:up
# Xác nhận lệnh đọc hoạt động
redis-cli -h replica-host GET some-key
# Xác nhận giá trị config đã được lưu
redis-cli -h replica-host CONFIG GET replica-serve-stale-data
Trên Redis 3.x, dùng CONFIG GET slave-serve-stale-data thay thế.
Ghi một test key trên master và đọc lại từ replica để xác nhận replication thực sự đang hoạt động end-to-end:
redis-cli -h master-host SET test-replication ok
redis-cli -h replica-host GET test-replication
# Kết quả mong đợi: "ok"
Nếu bạn đang dùng ElastiCache hoặc Redis được quản lý
Bạn không thể chỉnh sửa redis.conf trên ElastiCache. Hãy mở AWS console, tìm parameter group gắn với cluster của bạn, đặt replica-serve-stale-data, rồi lưu lại. Trên Redis 6.x trở lên, thay đổi được áp dụng mà không cần reboot. Trên các phiên bản cũ hơn, cần reboot node trong cluster — hãy chuẩn bị cho việc gián đoạn đọc ngắn trong thời gian khởi động lại.

