Redis persistence: restart hoặc kill -9 thì mất bao nhiêu dữ liệu? Trung cấp
Thời gian đọc ước tính: 8 phút
Vấn đề
Phần tiêu đề “Vấn đề”Một Redis 7.4 giữ cache sản phẩm (nạp lại được từ PostgreSQL), session đăng nhập và bộ đếm rate limit theo IP. Tất cả nằm trong RAM; persistence là cách Redis ghi dataset xuống đĩa để nạp lại khi khởi động.
Khi container bị kill -9 hoặc máy mất điện: mất cache chỉ tăng tải database, mất session thì người dùng bị đăng xuất, mất bộ đếm thì một IP được thêm một cửa sổ request.
Câu hỏi: với cấu hình hiện tại, sau crash Redis còn lại gì và mất tối đa bao nhiêu?
Chọn gì? (tóm tắt trước)
Phần tiêu đề “Chọn gì? (tóm tắt trước)”| Tình huống | Chọn | Điều kiện |
|---|---|---|
| Cache thuần | Tắt persistence (save "", appendonly no) hoặc RDB thưa |
Database chịu được cold start; có replica thì master không được tự restart |
| Session, bộ đếm rate limit | AOF everysec + giữ RDB |
Chấp nhận mất khoảng 1 s ghi khi máy sập |
| Dữ liệu không được mất | Không để Redis là nguồn sự thật duy nhất; nếu bắt buộc: AOF always + replication + WAIT |
Throughput giảm mạnh; failover vẫn có thể mất ghi đã xác nhận |
Docs Redis khuyên bật cả hai khi cần độ an toàn gần PostgreSQL; RDB vẫn hữu ích cho backup và restart nhanh.
Khái niệm cốt lõi
Phần tiêu đề “Khái niệm cốt lõi”| RDB | AOF | |
|---|---|---|
| Ghi gì | Snapshot toàn dataset (dump.rdb) |
Log mọi lệnh ghi, replay khi khởi động |
| Khi nào | Rule save <giây> <số thay đổi> hoặc BGSAVE |
Mỗi lệnh ghi; fsync theo appendfsync |
| Mất khi crash | Mọi ghi sau snapshot cuối | Tuỳ appendfsync (bảng dưới) |
| Default 7.4 | Bật: save 3600 1 300 100 60 10000 |
Tắt: appendonly no |
Rule save mặc định: snapshot sau 3600 s nếu ≥ 1 thay đổi, sau 300 s nếu ≥ 100, sau 60 s nếu ≥ 10000. Kiểm tra bằng CONFIG GET save.
fsync buộc kernel đẩy dữ liệu từ page cache xuống đĩa. Đã write() mà chưa fsync thì dữ liệu sống sót khi process chết, nhưng mất khi máy sập.
appendfsync |
Hành vi (theo docs) | Mất khi máy sập |
|---|---|---|
always |
fsync trước khi trả lời client, gộp nhiều lệnh vào một fsync | Gần như không; rất chậm |
everysec (default) |
fsync mỗi giây ở thread nền | Khoảng 1 s; tới 2 s nếu fsync chậm khiến Redis hoãn write() |
no |
Kernel tự flush (Linux thường khoảng 30 s) | Tuỳ kernel |
Cách hoạt động
Phần tiêu đề “Cách hoạt động”Session B và một lệnh INCR đi qua RAM, dump.rdb, thư mục AOF, rồi Redis chết:
Snapshot gần nhất chứa session A. Từ đây RDB đứng yên tới lần save sau.
| Mốc | Memory | dump.rdb |
AOF trên đĩa |
|---|---|---|---|
| Snapshot | A | A | A |
SET B, fsync |
A, B | A | A, B |
INCR |
A, B, rl=1 | A | INCR chưa fsync |
| Restart | Chỉ RDB: còn A | A, B; INCR còn nếu chỉ process chết |
RDB: fork và copy-on-write
Phần tiêu đề “RDB: fork và copy-on-write”BGSAVE gọi fork(). Process con ghi snapshot ra file tạm rồi rename đè file cũ, nên dump.rdb không bao giờ ghi dở; process cha tiếp tục phục vụ client.
Copy-on-write: sau fork, cha và con dùng chung trang nhớ; trang nào cha sửa thì kernel mới chép riêng. Ghi càng nhiều trong lúc save, RAM càng tăng. Hai thứ cần đo:
- Latency fork:
fork()chép page table trên main thread. Xemlatest_fork_usec(INFO stats); docs ghi khoảng 9–13 ms/GB trên phần cứng hiện đại. - Bộ nhớ CoW: log
Fork CoW for RDB: ...vàrdb_last_cow_sizetrongINFO persistence. Docs yêu cầu tắt transparent huge pages vì THP làm gần như toàn bộ memory bị chép.
AOF: rewrite và multi-part từ Redis 7
Phần tiêu đề “AOF: rewrite và multi-part từ Redis 7”INCR 100 lần sinh 100 entry cho một key. Rewrite tạo lại tập lệnh tối thiểu: chạy bằng BGREWRITEAOF hoặc tự động khi AOF gấp đôi kích thước sau lần rewrite trước và ≥ 64 MB (auto-aof-rewrite-percentage 100, auto-aof-rewrite-min-size 64mb).
Từ 7.0, AOF là thư mục appenddirname (mặc định appendonlydir):
- base: snapshot lúc rewrite; dạng RDB (
.base.rdb) vìaof-use-rdb-preamble yeslà default. - incr: lệnh ghi sau base (
.incr.aof). - manifest: danh sách file và thứ tự nạp.
Khi rewrite, cha ghi tiếp vào incr mới, con viết base mới, rồi Redis thay manifest nguyên tử; rewrite lỗi thì file cũ vẫn đủ dữ liệu.
Khởi động lại nạp file nào
Phần tiêu đề “Khởi động lại nạp file nào”Đang tải diagram…
Docs: cả hai cùng bật thì nạp AOF vì đầy đủ nhất. Nhánh “AOF rỗng” đã tái hiện trong demo.
Chi tiết vận hành
Phần tiêu đề “Chi tiết vận hành”- Shutdown sạch (
SIGTERM): có rulesavethì Redis ghi RDB trước khi thoát (demo:docker stopcòn đủ 5000/5000 key).docker stopchỉ chờ 10 s rồiSIGKILL. stop-writes-on-bgsave-error yes(default):BGSAVElỗi, ví dụ đầy đĩa, thì Redis từ chối ghi.aof-load-truncated yes(default): AOF cụt ở cuối vẫn nạp; hỏng ở giữa thì cầnredis-check-aof.
Replication không thay persistence
Phần tiêu đề “Replication không thay persistence”Docs replication mô tả: master tắt persistence, crash, được tự restart với dataset rỗng; replica đồng bộ lại và xoá luôn bản sao. Với Sentinel, master có thể restart nhanh tới mức không bị phát hiện.
Khuyến nghị: bật persistence trên master và replica; nếu không thể thì tắt auto-restart cho master. Replication bất đồng bộ, WAIT chỉ giảm xác suất mất ghi.
Ví dụ thực tế
Phần tiêu đề “Ví dụ thực tế”Demo: Redis 7.4.9 riêng (port 6391), ghi lô 50 SET liên tục 3 giây, docker kill ngay sau lô được xác nhận cuối, restart, đếm DBSIZE:
npx --prefix examples ts-node examples/src/redis-persistence/crash-demo.ts rdb # cả everysec, always, none| Cấu hình | Client nhận OK | Còn sau restart | Mất |
|---|---|---|---|
| Không persistence | 589.800 | 0 | 589.800 |
RDB save 60 1000, snapshot ở giây 60 |
1.058.300 | 411.550 | 646.750 |
AOF everysec |
630.950 | 630.950 | 0 |
AOF always |
183.850 | 183.850 | 0 |
Đọc kết quả:
docker killchỉ giết process; dữ liệu đãwrite()còn trong page cache nêneverysecmất 0. Mất điện mới lộ phần chưa fsync; demo không mô phỏng được.alwaysnhận ít OK hơneveryseckhoảng 3,4 lần (Docker Desktop trên macOS, chỉ so tương đối; số đổi mỗi lần chạy).
Output thật: thư mục AOF, bật AOF sai cách, fork và CoW
[everysec] sau restart: 630950 key còn, mất 0 key-rw------- 1 redis redis 22183987 appendonly.aof.2.base.rdb-rw------- 1 redis redis 33363023 appendonly.aof.2.incr.aof-rw------- 1 redis redis 88 appendonly.aof.manifestfile appendonly.aof.2.base.rdb seq 2 type bfile appendonly.aof.2.incr.aof seq 2 type iRestart với --appendonly yes trên volume có dump.rdb 5000 key:
* Creating AOF base file appendonly.aof.1.base.rdb on server startDBSIZE → 0Dataset 383 MB, BGSAVE trong khi redis-benchmark ghi SET ngẫu nhiên:
latest_fork_usec:2475Fork CoW for RDB: current 108 MB, peak 108 MB, average 72 MBTrade-offs
Phần tiêu đề “Trade-offs”Persistence đem lại gì
- RDB: file gọn, restart nhanh, chép backup an toàn khi Redis đang chạy
- AOF
everysec: process chết gần như không mất ghi; máy sập mất khoảng 1 s - Multi-part AOF: rewrite không đệm ghi trong RAM, base dạng RDB nạp nhanh
Cái giá phải trả
- Fork chặn main thread; CoW cần RAM dự phòng
- AOF
alwaysgiảm throughput nhiều lần - fsync chậm có thể gây spike latency
Checklist production
Phần tiêu đề “Checklist production”- Tách instance cache thuần khỏi instance giữ session.
- Session, bộ đếm:
appendonly yes,appendfsync everysec, giữ rulesave; kiểm tra bằngCONFIG GETsau deploy. - Dự phòng RAM cho CoW, tắt transparent huge pages, cảnh báo theo
latest_fork_usecvàrdb_last_cow_size. - Cảnh báo khi
rdb_last_bgsave_status,aof_last_bgrewrite_status,aof_last_write_statuskhácok. - Đổi RDB sang AOF bằng
CONFIG SET appendonly yes, chờ rewrite xong,CONFIG REWRITE, rồi mới restart. - Có replica: bật persistence trên master hoặc tắt auto-restart cho master.
- Timeout dừng (
docker stop -t,terminationGracePeriodSeconds) đủ cho lần save cuối. - Chép RDB hoặc thư mục AOF ra ngoài máy định kỳ và thử restore.
Sai lầm thường gặp
Phần tiêu đề “Sai lầm thường gặp”Bẫy thứ hai nằm ở chỗ ghép replication với master không persistence:
| Cách hiểu sai | Hệ quả | Cần làm |
|---|---|---|
| Bật cả hai thì Redis nạp file mới hơn | Khôi phục nhầm | Có AOF thì Redis luôn nạp AOF |
always nghĩa là không bao giờ mất |
Vẫn mất khi failover sang replica chưa nhận ghi | Nguồn sự thật ở database có transaction |
Tự kiểm tra
Phần tiêu đề “Tự kiểm tra”- Chỉ RDB, rule default, ghi 50 thay đổi lúc 10:00,
kill -9lúc 10:04. Restart còn gì? - Vì sao
docker killvớieverysecmất 0 key, còn mất điện có thể mất khoảng 1 giây? - Dataset 20 GB ghi dày lúc
BGSAVE: đo RAM dự phòng bằng metric nào? - Vì sao replica bật AOF vẫn có thể mất dữ liệu?
Tóm tắt
Phần tiêu đề “Tóm tắt”Tham khảo
Phần tiêu đề “Tham khảo”- Redis persistence — Redis Docs:
appendfsync, multi-part AOF, chuyển RDB sang AOF. - Redis replication — Redis Docs: master không persistence xoá dữ liệu replica.
- Diagnosing latency issues — Redis Docs: latency fork, THP, fsync.
- redis.conf Redis 7.4: các default persistence.