Nâng cấp Redis nghe như phải có cửa sổ bảo trì. Bài này đo một quy trình không cần cửa sổ nào — và đo cả cái giá của nó.
Ba bước, đo thật
1. Dựng bản mới làm bản sao của bản cũ
docker run -d --name rnew redis:7-alpine \
redis-server --replicaof rold 6379
đồng bộ xong sau 0,6 giây, đủ 200.000 khoá
Redis 7.4 đọc được luồng nhân bản của Redis 6.2 mà không cần cấu hình gì. Đây là điều cả quy trình dựa vào.
2. Đổi vai trò
redis-cli -h rnew replicaof no one
redis-cli -h rold replicaof rnew 6379
hai lệnh mất 0,12 giây
Bản mới thành máy chính; bản cũ thành bản sao của nó. Từ giây phút này, bản cũ chỉ còn để dự phòng.
3. Khách hàng trong suốt quá trình
ghi thành công 3.842 | thất bại 1 | gián đoạn 0,03 giây
Một lệnh ghi thất bại trên 3.843 lần thử.
Khách hàng của tôi chỉ làm hai việc: bắt lỗi, thử host kia. Không cần Sentinel, không cần proxy — với một lần chuyển đổi có kế hoạch, logic thử lại đơn giản là đủ.
Nhưng đường về thì không có
Tôi thử ngược lại: cho bản 6.2 làm bản sao của bản 7.4.
# Failed trying to load the MASTER synchronization DB from disk
* Reconnecting to MASTER rnew:6379 after failure
# Failed trying to load the MASTER synchronization DB from disk
master_link_status: down
dbsize: 0
Bản cũ không đọc nổi định dạng RDB của bản mới. Nó thử lại vô hạn, và cơ sở dữ liệu vẫn trống.
Nghĩa là quy trình này một chiều. Sau khi đổi vai trò, bạn không lùi lại được bằng cách đảo hai lệnh REPLICAOF — bản 6.2 đã không còn dữ liệu và không nhận được nữa.
Muốn lùi thì phải khôi phục từ bản sao lưu chụp trước khi nâng cấp, và chấp nhận mất mọi thay đổi kể từ đó.
Nên làm gì trước bước 2
Vì bước 2 không đảo ngược được, mọi việc kiểm tra phải xong trước nó.
Chụp RDB của bản cũ và mang ra khỏi máy. Đây là đường lùi duy nhất. Mất 0,1 giây như đo ở phần 18.
Kiểm ứng dụng chạy được với bản mới. Trong lúc bản mới còn là bản sao, nó đọc được. Trỏ một phần lưu lượng đọc sang đó và xem có gì hỏng không — đây là cửa sổ thử nghiệm miễn phí mà quy trình này cho không.
Đọc ghi chú phát hành. Giữa 6.2 và 7.0 có vài thay đổi thật: ziplist thành listpack (phần 5), cách tính maxmemory-clients, và một số lệnh đổi hành vi ở biên. Chúng ít khi làm hỏng, nhưng đọc mười phút rẻ hơn nhiều so với gỡ rối sau khi đã không lùi được.
Kiểm INFO server của cả hai. Chắc chắn bạn đang nâng đúng thứ mình nghĩ.
Nhảy cóc phiên bản
Redis không có ràng buộc "phải qua từng phiên bản" như Kubernetes. Nhân bản từ 6.2 sang 7.4 chạy thẳng, và đó là hai phiên bản chính cách nhau.
Nhưng càng xa thì càng nhiều thay đổi hành vi tích lại, và bạn không có đường lùi. Với khoảng cách lớn — 5.x lên 7.x chẳng hạn — cân nhắc đi hai chặng, mỗi chặng có bản sao lưu riêng.
Khi có Sentinel hoặc Cluster
Với Sentinel, đừng gõ REPLICAOF bằng tay — Sentinel sẽ thấy trạng thái không khớp và sửa lại. Dùng:
redis-cli -p 26379 sentinel failover mymaster
Quy trình: nâng cấp các bản sao trước (chúng không phục vụ ghi), rồi gọi SENTINEL FAILOVER để chuyển sang một bản sao đã nâng cấp, rồi nâng nốt máy chính cũ.
Thời gian chuyển đổi khi đó là con số đo ở phần 22: khoảng 4,5 giây cho Sentinel, 6,27 giây từ góc nhìn khách — chậm hơn 0,03 giây ở bài này, vì Sentinel phải phát hiện và bầu chọn thay vì được ra lệnh trực tiếp.
Với Cluster, nâng từng nút một, và nâng bản sao trước nút chính của nó. CLUSTER FAILOVER trên một bản sao đã nâng cấp làm việc chuyển đổi có kiểm soát, không mất dữ liệu.
Nâng cấp phiên bản vá
Với phiên bản vá cùng dòng — 7.4.1 lên 7.4.2 — quy trình vẫn như trên, nhưng bạn có đường lùi: hai bản cùng dòng đọc được RDB của nhau.
Đây là lý do nên nâng phiên bản vá thường xuyên thay vì để dồn: mỗi lần rẻ, có thể lùi, và bạn tránh được việc phải nhảy hai phiên bản chính một lúc.
Thử ba mươi giây
Kiểm xem bạn có sẵn sàng nâng cấp không:
redis-cli info server | grep -E 'redis_version|os|multiplexing_api'
redis-cli info replication | grep -E 'role|connected_slaves|master_link_status'
redis-cli info persistence | grep -E 'rdb_last_bgsave_status|rdb_changes_since_last_save'
Ba câu hỏi:
- Có bản sao nào không? Không có thì bạn cần dựng một cái trước, và đó là bước tốn thời gian nhất.
rdb_last_bgsave_statuscóokkhông? Nếu không, bạn đang không có đường lùi.- Ứng dụng có thử lại khi ghi thất bại không? Đây là điều kiện duy nhất để một lệnh thất bại trở thành vô hình thay vì thành lỗi cho người dùng.
Câu cuối là câu quan trọng nhất, và nó thuộc về mã ứng dụng chứ không thuộc về Redis.
Phần sau: Redis trong Docker cho môi trường thật — những cấu hình mặc định phải đổi.