Hai phần trước đo RDB và AOF riêng lẻ. Bài này đặt chúng cạnh nhau trên cùng 2 triệu khoá và đo thứ quan trọng nhất: thời gian sống lại sau sự cố.
Kích thước tệp chênh 5,8 lần
RDB 46.888.988 byte
AOF có tiền tố RDB 46.893.128 byte gần như y hệt
AOF văn bản thuần 270.893.097 byte lớn hơn 5,8 lần
Hai dòng đầu gần bằng nhau, và đó không phải trùng hợp. Từ Redis 7, aof-use-rdb-preamble mặc định yes, và tệp cơ sở của AOF thật sự là một tệp RDB:
appendonly.aof.4.base.rdb
appendonly.aof.4.incr.aof
appendonly.aof.manifest
Sau mỗi lần viết lại, Redis chụp trạng thái hiện tại dưới dạng RDB rồi nối các lệnh mới vào tệp .incr.aof. Nghĩa là AOF hiện đại không phải một tệp văn bản khổng lồ; nó là RDB cộng thêm phần đuôi.
Dòng thứ ba là AOF kiểu cũ, khi tôi tắt tiền tố RDB: 270 MB cho cùng dữ liệu.
Nhưng thời gian nạp lại thì bằng nhau
Đây là chỗ tôi trông đợi thấy khác biệt lớn và không thấy.
| Thời gian nạp | |
|---|---|
| RDB (46,9 MB) | 1,416 / 1,331 / 1,343 giây |
| AOF văn bản (270,9 MB) | 1,399 / 1,321 / 1,296 / 1,392 giây |
| AOF + tiền tố RDB | 1,509 giây |
Tệp lớn gấp 5,8 lần mà nạp nhanh bằng.
Lý do: thời gian nạp bị chi phối bởi việc dựng 2 triệu mục trong bảng băm, không bởi việc đọc byte. Cấp phát bộ nhớ, băm khoá, chèn vào bảng, thỉnh thoảng mở rộng bảng — đó mới là công việc. Phân tích 270 MB văn bản so với 47 MB nhị phân chỉ là phần nhỏ.
Con số đọc được từ nhật ký của chính Redis (DB loaded from disk: X seconds), không phải đo từ ngoài, nên không lẫn thời gian khởi động container.
Lời khuyên quen thuộc "AOF nạp chậm hơn RDB nhiều" không đúng ở quy mô này. Nó có thể đúng với một tệp AOF chưa từng được viết lại — một tệp chứa hàng chục triệu lệnh chồng lên nhau trên cùng vài khoá, vì lúc đó Redis phải chạy lại tất cả. Nhưng đó là vấn đề của việc không viết lại, không phải của định dạng.
Khác biệt thật nằm ở lượng mất
Tốc độ khôi phục gần như nhau, nên lựa chọn không nằm ở đó.
| Mất tối đa | |
|---|---|
RDB mặc định (save 3600 1) |
một giờ thay đổi |
RDB (save 60 10000) |
60 giây, nếu đủ 10.000 thay đổi |
AOF everysec |
1 giây khi mất điện |
AOF everysec hoặc no |
0 khi tiến trình bị SIGKILL (đo ở phần 19) |
Đây mới là bảng quyết định. RDB một mình là "mất một khoảng gần đây, khoảng đó có thể rất dài".
Bật cả hai
Redis cho phép, và đó là cấu hình đúng cho phần lớn trường hợp:
appendonly yes
appendfsync everysec
save 3600 1 300 100 60 10000
Khi khởi động, nếu appendonly yes thì Redis luôn nạp từ AOF và bỏ qua RDB — AOF mới hơn.
Vậy giữ RDB làm gì? Vì nó là một tệp duy nhất, gọn, chép đi được:
dump.rdbmang sang máy khác, đưa vào kho sao lưu, nén lại.- AOF là một thư mục nhiều tệp kèm tệp kê khai; sao chép nửa vời là hỏng.
Nên: AOF để khôi phục tại chỗ, RDB để mang đi.
Chi phí của việc bật cả hai là hai nguồn fork — và như đo ở phần 18, fork mang chi phí copy-on-write thật. Trên hệ thống ghi rất nhiều, cân nhắc tắt RDB tự động và chỉ gọi BGSAVE theo lịch vào lúc rảnh.
Ba tình huống, ba cấu hình
Bộ đệm thuần, mất hết cũng được: tắt cả hai.
save ""
appendonly no
Không fork, không ghi đĩa, không copy-on-write. Đây là cấu hình nhanh nhất và nhiều người quên rằng nó tồn tại.
Dữ liệu quan trọng: AOF everysec + RDB theo lịch. Cấu hình ở trên.
Cần khởi động lại thật nhanh: chỉ RDB, và chấp nhận mất. Nạp RDB không nhanh hơn AOF ở phép đo này, nhưng nó tránh được chi phí ghi AOF liên tục lúc chạy bình thường.
Điều cả hai đều không làm
Cả RDB lẫn AOF đều không bảo vệ bạn khỏi:
- Lệnh
FLUSHALLgõ nhầm — nó được ghi vào AOF và nhân bản sang bản sao ngay lập tức. - Đĩa hỏng — cả hai tệp nằm trên cùng ổ đó.
- Máy chủ mất.
Cho ba thứ đó cần sao lưu ra ngoài máy: chép dump.rdb sang nơi khác theo lịch. Đây là chỗ RDB thắng rõ, vì nó là một tệp.
Và mẹo nhỏ với FLUSHALL: đổi tên nó đi.
rename-command FLUSHALL ""
rename-command FLUSHDB ""
Thử ba mươi giây
Xem bạn đang mất bao nhiêu nếu Redis chết ngay bây giờ:
redis-cli info persistence | grep -E \
'aof_enabled|rdb_changes_since_last_save|rdb_last_save_time|aof_last_write_status'
date +%s
Lấy date +%s trừ rdb_last_save_time ra số giây kể từ lần lưu RDB gần nhất. Nếu aof_enabled:0 thì đó chính là lượng thời gian bạn sẽ mất.
Và kiểm thời gian khôi phục bằng chính nhật ký của Redis:
docker logs <container> 2>&1 | grep -i "DB loaded from disk"
Dòng đó có sẵn sau mỗi lần khởi động. Nó là con số thật cho cụm của bạn, chính xác hơn mọi ước lượng — và nếu bạn chưa từng nhìn nó, bây giờ là lúc tốt hơn nhiều so với lúc đang có sự cố.
Phần sau: nhân bản — đo độ trễ giữa bản chính và bản sao.