Lỗi Gặp Phải
Bạn kích hoạt snapshot thủ công và Redis trả về:
127.0.0.1:6379> BGSAVE
(error) ERR Background save already in progress
Một tiến trình fork BGSAVE đang chạy — Redis không cho phép chạy hai tiến trình cùng lúc. Thường thì điều này vô hại. Nhưng lúc 2 giờ sáng với deployment đang chờ, bạn cần biết chuyện gì đang xảy ra và khi nào nó sẽ xong.
Nguyên Nhân
Redis xử lý RDB snapshot bằng cách fork một tiến trình con. Chỉ một tiến trình fork chạy tại một thời điểm. Lỗi xảy ra khi:
- Một lệnh
BGSAVEtrước đó — thủ công hoặc được kích hoạt bởi cấu hìnhsave— chưa hoàn thành - Một lệnh
BGREWRITEAOFđang chạy — trên các phiên bản Redis cũ, việc ghi lại AOF cũng chặnBGSAVE - Một replica vừa kết nối và Redis đã fork để gửi RDB cho nó (lưu ngầm do replication)
Không có gì bị hỏng. Redis đang bảo vệ bạn khỏi việc fork hai lần. Việc của bạn là chờ lần lưu hiện tại hoàn thành, hoặc tìm hiểu tại sao việc lưu lại mất quá nhiều thời gian.
Bước 1 — Kiểm Tra Tiến Trình Đang Chạy
Bắt đầu từ đây — xem trạng thái persistence hiện tại:
redis-cli INFO persistence
Các trường quan trọng:
rdb_bgsave_in_progress:1 # 1 = đang có lần lưu chạy
rdb_current_bgsave_time_sec:42 # số giây đã trôi qua kể từ khi bắt đầu lưu
rdb_last_bgsave_status:ok # trạng thái của lần lưu hoàn thành gần nhất
aof_rewrite_in_progress:0 # 1 = AOF rewrite đã được fork
rdb_bgsave_in_progress:1 nghĩa là đang có lần lưu đang hoạt động. Hãy chờ. Redis sẽ đặt lại về 0 khi xong.
Bước 2 — Chờ Đúng Cách
Theo dõi cho đến khi lần lưu hoàn thành:
watch -n 2 'redis-cli INFO persistence | grep -E "bgsave_in_progress|bgsave_time_sec|last_bgsave"'
Với dataset dưới vài GB và I/O đĩa bình thường, BGSAVE sẽ hoàn thành trong vài giây đến vài phút. Nếu quá 5–10 phút, có gì đó không ổn — hãy chuyển sang phần xử lý sự cố bên dưới.
Khi rdb_bgsave_in_progress về 0, chạy lại lệnh BGSAVE của bạn:
127.0.0.1:6379> BGSAVE
Background saving started
Bước 3 — Tìm Nguyên Nhân Kích Hoạt Lần Lưu Ban Đầu
Log của Redis cho bạn biết chính xác điều gì đã kích hoạt nó:
tail -n 100 /var/log/redis/redis-server.log | grep -i "bgsave\|save\|fork"
Các dòng log thường gặp:
# BGSAVE thủ công
* Background saving started by pid 12345
# Kích hoạt bởi cấu hình save (ví dụ: save 300 10)
* 10000 changes in 300 seconds. Saving...
# Kích hoạt bởi replication
* Starting BGSAVE for SYNC with target: disk
Lần lưu do replication kích hoạt? Kiểm tra các kết nối replica:
redis-cli INFO replication | grep -E "connected_slaves|slave"
Bước 4 — Nếu BGSAVE Mất Quá Nhiều Thời Gian
Lưu chậm thường do ba nguyên nhân. Hãy xử lý theo thứ tự sau.
Dataset lớn với đĩa chậm
Tiến trình con ghi toàn bộ dataset xuống đĩa — từng byte một. Với dataset 10 GB và đĩa cơ học chạy 100 MB/s, ít nhất mất 100 giây chưa kể overhead. Kiểm tra kích thước dataset và throughput đĩa:
redis-cli INFO memory | grep used_memory_human
iostat -x 1 5 # kiểm tra mức sử dụng đĩa
I/O đĩa đã đạt tối đa nghĩa là lần lưu sẽ rất chậm. Di chuyển file RDB sang ổ đĩa nhanh hơn:
# redis.conf
dir /mnt/fast-ssd/redis
Áp lực copy-on-write do tải ghi cao
Sau khi fork, mỗi lần ghi vào Redis khiến OS phải sao chép các trang bộ nhớ bị ảnh hưởng (copy-on-write). Throughput ghi cao trong khi lưu làm phồng working set của tiến trình con. Càng nhiều trang được sao chép, lần lưu càng kéo dài. Kiểm tra lượng thay đổi kể từ lần lưu cuối:
redis-cli INFO stats | grep rdb_changes_since_last_save
Con số lớn ở đây có nghĩa là khoảng thời gian lưu của bạn quá rộng. Hãy thu hẹp lại hoặc lên lịch lưu vào giờ thấp điểm.
Transparent Huge Pages gây độ trễ khi fork
THP là thủ phạm nổi tiếng làm giảm hiệu năng Redis — nó làm tăng đáng kể overhead của copy-on-write. Kiểm tra và tắt nó:
cat /sys/kernel/mm/transparent_hugepage/enabled
# Nếu hiển thị [always], hãy tắt đi:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
Bước 5 — Điều Chỉnh Tần Suất Lưu Để Tránh Xung Đột
Tự động lưu quá thường xuyên là thủ phạm phổ biến trên các server bận. Các cấu hình mặc định kích hoạt rất tích cực — trên dataset lớn, các lần lưu có thể chồng chéo nhau. Hãy điều chỉnh lại trong redis.conf:
# Mặc định (thường quá tích cực với dataset lớn)
save 900 1
save 300 10
save 60 10000
# Thận trọng hơn — chỉ lưu khi có thay đổi đáng kể
save 900 1
save 300 1000
Áp dụng mà không cần khởi động lại:
redis-cli CONFIG SET save "900 1 300 1000"
Để xác nhận cấu hình đang chạy đã có hiệu lực:
redis-cli CONFIG GET save
Kiểm Tra Kết Quả
Xác nhận lần lưu đã hoàn thành thành công:
redis-cli INFO persistence | grep -E "rdb_bgsave_in_progress|rdb_last_bgsave_status|rdb_last_save_time"
Kết quả bình thường trông như thế này:
rdb_bgsave_in_progress:0
rdb_last_bgsave_status:ok
rdb_last_save_time:1714900000
Sau đó kiểm tra file RDB đã được cập nhật:
ls -lh $(redis-cli CONFIG GET dir | tail -1)/$(redis-cli CONFIG GET dbfilename | tail -1)
Thời gian của file phải khớp với lần lưu gần đây của bạn.
Tóm Tắt Nhanh
- Có thể bỏ qua nếu đang có lần lưu chạy — chỉ cần chờ nó hoàn thành
- Kiểm tra trạng thái:
redis-cli INFO persistence | grep bgsave - Đừng bao giờ kill tiến trình con BGSAVE thủ công trừ khi nó chạy nhiều giờ — kill giữa chừng sẽ làm hỏng file RDB
- LASTSAVE trả về Unix timestamp của lần lưu thành công gần nhất:
redis-cli LASTSAVE - Để dừng toàn bộ việc lưu:
redis-cli CONFIG SET save ""— chỉ làm điều này khi bạn hiểu mình đang từ bỏ tính năng persistence nào

