Bối cảnh: Cuộc gọi lúc nửa đêm – 'CLUSTERDOWN Hash slot not served'
Đã 2 giờ sáng, và máy nhắn tin của bạn kêu inh ỏi. Một ứng dụng quan trọng đang gặp sự cố, và các log đang hiển thị tràn ngập lỗi CLUSTERDOWN Hash slot not served từ Redis. Đây không chỉ là một cảnh báo; nó có nghĩa là Redis Cluster của bạn đang ở trạng thái lỗi, và một số hoặc tất cả các thao tác dữ liệu đã bị dừng đối với các khóa (key) ánh xạ tới các hash slot chưa được phục vụ. Cluster không thể đảm bảo tính khả dụng hoặc tính nhất quán của dữ liệu cho các hash slot đó, vì vậy nó ngừng phục vụ các yêu cầu hoàn toàn.
Lỗi này thường xuất hiện khi một hoặc nhiều trong số 16384 hash slot tạo nên một Redis Cluster không được gán cho bất kỳ primary node nào. Các kịch bản phổ biến dẫn đến điều này bao gồm:
- Một primary node bị lỗi vĩnh viễn mà không có replica khỏe mạnh nào tiếp quản, hoặc quá trình automatic failover không hoàn tất thành công.
- Một primary node bị xóa không đúng cách khỏi cluster, để lại các hash slot của nó bị bỏ rơi (orphaned).
- Một thao tác resharding chưa hoàn tất hoặc bị lỗi.
- Một cluster khởi động với không đủ node để bao phủ tất cả các hash slot.
Mục tiêu trước mắt của bạn là xác định các hash slot nào chưa được gán và sau đó gán lại chúng cho các primary node khỏe mạnh để đưa cluster trở lại trạng thái OK.
Quy trình Debug: Xác định các Hash Slot Bị Bỏ Rơi
Đầu tiên, chúng ta cần xác nhận trạng thái của cluster và xác định các hash slot gặp vấn đề. Kết nối tới bất kỳ node nào trong cluster của bạn bằng redis-cli.
1. Kiểm tra trạng thái Cluster
Kiểm tra cơ bản nhất sẽ ngay lập tức cho bạn biết liệu cluster có khỏe mạnh hay không.
redis-cli -h <any_cluster_ip> -p <any_cluster_port> cluster info
Tìm các trường cluster_state và cluster_slots_assigned. Bạn có thể sẽ thấy kết quả tương tự như sau:
cluster_state:fail
cluster_slots_assigned:16380
cluster_slots_ok:16380
cluster_slots_pfail:0
cluster_slots_fail:4
...
Điểm mấu chốt ở đây là cluster_state:fail và cluster_slots_assigned nhỏ hơn 16384 (tổng số hash slot). cluster_slots_fail sẽ cho biết có bao nhiêu hash slot chưa được gán.
2. Xác định các Hash Slot chưa được gán và Node bị lỗi
Tiếp theo, hãy xem hash slot nào thực sự gây ra vấn đề và liệu có node nào bị đánh dấu là lỗi hay không.
redis-cli -h <any_cluster_ip> -p <any_cluster_port> cluster slots
Lệnh này sẽ liệt kê tất cả các dải hash slot và các primary/replica node chịu trách nhiệm cho chúng. Bạn sẽ tìm kiếm các mục không có primary node liên kết với chúng, hoặc nơi primary node hiển thị trạng thái fail hoặc PFAIL.
Ngoài ra, hãy kiểm tra trạng thái của từng node:
redis-cli -h <any_cluster_ip> -p <any_cluster_port> cluster nodes
Tìm các dòng chỉ ra các node có cờ (flag) fail hoặc PFAIL. Ghi lại ID và IP:Port của chúng. Nếu một primary node bị đánh dấu là fail và các hash slot của nó không được bao phủ bởi một replica đang hoạt động, thì đó chính là các hash slot bị bỏ rơi của bạn.
3. Xác thực bằng redis-cli --cluster check
Tiện ích redis-cli --cluster check này là vô giá để kiểm tra sâu hơn:
redis-cli --cluster check <any_cluster_ip>:<any_cluster_port>
Lệnh này sẽ thực hiện kiểm tra toàn diện tình trạng của cluster, bao gồm vùng phủ hash slot, kết nối node và trạng thái replication. Nó thường cung cấp các khuyến nghị cụ thể hoặc làm nổi bật chính xác các hash slot không được phục vụ.
# Ví dụ về kết quả đầu ra chỉ ra các hash slot bị thiếu
[ERR] Node <node_id> is not part of the cluster, but still has some slots. Please use CLUSTER RESET to fix this.
[ERR] Missing 4 slots.
[ERR] The following slots are not covered by any node: 1024-1027
!!! Some of the cluster hash slots are not covered. Rebalance is advised. !!!
Giải pháp: Khôi phục các Hash Slot chưa được phục vụ
Bây giờ chúng ta đã biết vấn đề, hãy khắc phục nó. Cách tiếp cận phụ thuộc vào việc node ban đầu đã phục vụ các hash slot có thể khôi phục được hay đã mất vĩnh viễn.
Kịch bản A: Node bị tạm dừng hoặc có thể khôi phục
Nếu node trước đây sở hữu các hash slot chưa được phục vụ chỉ đơn thuần là đang dừng hoạt động (ví dụ: do khởi động lại, sự cố mạng), giải pháp đơn giản nhất là đưa nó trở lại hoạt động trực tuyến. Khi node tham gia lại cluster, nó sẽ tự động khôi phục các hash slot của mình, và trạng thái của cluster sẽ trở lại OK.
# Ví dụ: Khởi động lại dịch vụ Redis
sudo systemctl start redis-server@<port> # Trên các hệ thống dùng systemd
# Hoặc khởi động thủ công tiến trình redis-server nếu không dùng trình quản lý dịch vụ
Theo dõi cluster info và cluster nodes sau khi khởi động lại. Nếu node hoạt động trở lại và khôi phục các hash slot của nó, bạn đã khắc phục được vấn đề.
Kịch bản B: Node bị mất vĩnh viễn hoặc cần can thiệp thủ công
Nếu primary node đã mất vĩnh viễn, hoặc nếu việc đưa nó trở lại trực tuyến không giải quyết được vấn đề (ví dụ: dữ liệu của nó bị hỏng), bạn cần gán lại các hash slot của nó cho các primary node khỏe mạnh khác. Đây là lúc redis-cli --cluster phát huy tác dụng.
Tùy chọn 1: Sử dụng redis-cli --cluster fix (Các phiên bản cũ hơn/Trường hợp đơn giản hơn)
Đối với các trường hợp đơn giản hơn, đặc biệt là trong các phiên bản Redis cũ hơn, fix đôi khi có thể giải quyết các sự không nhất quán nhỏ, bao gồm các hash slot chưa được gán, bằng cách cố gắng thiết lập lại một trạng thái nhất quán.
redis-cli --cluster fix <any_cluster_ip>:<any_cluster_port>
Lệnh này cố gắng tự động sửa các vấn đề cluster phổ biến. Nó có thể không luôn hoạt động đối với các cluster bị phân mảnh sâu hoặc các primary đã mất vĩnh viễn, nhưng đây là một nỗ lực đầu tiên tốt.
Tùy chọn 2: Resharding các Hash Slot tới các Node hiện có (Cách khắc phục phổ biến nhất)
Đây là cách mạnh mẽ nhất để gán lại các hash slot bị bỏ rơi. Bạn sẽ phân phối các hash slot chưa được gán cho các primary node khỏe mạnh còn lại.
redis-cli --cluster reshard <any_cluster_ip>:<any_cluster_port>
Lệnh sẽ nhắc bạn nhập một số thông tin:
- Bạn muốn di chuyển bao nhiêu hash slot (từ 1 đến 16384)? Nhập số lượng hash slot chưa được gán mà bạn tìm thấy từ
cluster infohoặccluster check. Ví dụ, nếucluster_slots_fail:4, hãy nhập4. - ID của node nhận là gì? Đây là ID của một primary node khỏe mạnh hiện có sẽ tiếp nhận các hash slot mới này. Bạn có thể lấy ID node từ
redis-cli cluster nodes. Hãy chọn một node chưa bị quá tải. - ID của node nguồn là gì? Vì các hash slot này chưa được gán (bị bỏ rơi), bạn có thể sẽ nhập
allđể chỉ ra rằng các hash slot có thể được lấy từ bất kỳ nguồn nào hiện đang giữ chúng (ngay cả khi nguồn đó là 'none' đối với các hash slot chưa được gán). Nếu được nhắc nhập ID node cụ thể, và các hash slot này đến từ một node bị lỗi, bạn có thể cần nhập ID của node bị lỗi đó nếu nó vẫn được cluster biết đến, hoặc đơn giản là sử dụngall. Đối với các hash slot thực sự chưa được gán,allthường là cách tiếp cận đúng.
Xác nhận kế hoạch, và quá trình resharding sẽ bắt đầu. Nó sẽ di chuyển dữ liệu liên quan đến các hash slot đó (nếu có dữ liệu nào được khôi phục hoặc tồn tại) đến primary node mới.
Tùy chọn 3: Thêm một Primary Node mới và Resharding
Nếu cluster của bạn đã dưới dung lượng hoặc nếu bạn muốn duy trì sự phân phối đồng đều của các hash slot và dữ liệu, hãy cân nhắc thêm một primary node mới trước, sau đó resharding các hash slot chưa được gán tới nó.
Bước 1: Thêm node mới làm primary
redis-cli --cluster add-node <new_node_ip>:<new_node_port> <any_existing_cluster_ip>:<any_existing_cluster_port> --cluster-master
Thao tác này sẽ thêm node mới làm primary mà ban đầu không có bất kỳ hash slot nào.
Bước 2: Reshard các hash slot tới primary mới
redis-cli --cluster reshard <any_existing_cluster_ip>:<any_existing_cluster_port>
Khi được nhắc:
- Bạn muốn di chuyển bao nhiêu hash slot? Nhập số lượng hash slot chưa được gán.
- ID của node nhận là gì? Nhập ID của primary node mới mà bạn vừa thêm.
- ID của node nguồn là gì? Nhập
all.
Các bước xác minh: Xác nhận việc khắc phục
Sau khi bạn đã cố gắng khắc phục, điều quan trọng là phải xác minh rằng cluster đang hoạt động đầy đủ.
1. Kiểm tra lại trạng thái Cluster
redis-cli -h <any_cluster_ip> -p <any_cluster_port> cluster info
Bây giờ bạn sẽ thấy:
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
...
2. Xác minh vùng phủ Hash Slot
redis-cli --cluster check <any_cluster_ip>:<any_cluster_port>
Thao tác này sẽ báo cáo không có hash slot chưa được gán và một cấu trúc cluster khỏe mạnh.
3. Kiểm tra các thao tác dữ liệu
Thực hiện một số thao tác đọc và ghi cơ bản để đảm bảo dữ liệu có thể được lưu trữ và truy xuất chính xác trên các khóa khác nhau, điều này sẽ chạm đến nhiều hash slot khác nhau.
redis-cli -h <any_cluster_ip> -p <any_cluster_port> SET mykey "hello from fixed cluster"
redis-cli -h <any_cluster_ip> -p <any_cluster_port> GET mykey
redis-cli -h <any_cluster_ip> -p <any_cluster_port> SET anotherkey "another value"
redis-cli -h <any_cluster_ip> -p <any_cluster_port> GET anotherkey
Nếu tất cả các kiểm tra này đều thành công, xin chúc mừng! Redis Cluster của bạn đã hoạt động trở lại.
Bài học kinh nghiệm & Phòng ngừa
-
Giám sát mạnh mẽ: Triển khai giám sát toàn diện cho Redis Cluster, không chỉ riêng trạng thái của từng node. Theo dõi
cluster_state,cluster_slots_assignedvà các cờ node (fail,PFAIL). Cảnh báo khi cluster ở trạng thái không phảioklà rất quan trọng. -
Gỡ bỏ Node đúng cách: Không bao giờ chỉ đơn thuần tắt một primary node mà không di chuyển các hash slot của nó đúng cách hoặc đảm bảo các replica của nó có thể failover. Sử dụng
redis-cli --cluster del-nodesau khi đảm bảo các hash slot đã được di chuyển/replication. -
Hệ số Replication: Đảm bảo hệ số replication đủ (ít nhất là 1, nghĩa là mỗi primary có ít nhất một replica) để automatic failover có thể xảy ra nếu một primary node bị dừng hoạt động.
-
Sao lưu tự động: Các ảnh chụp nhanh RDB định kỳ hoặc tính năng AOF persistence là tuyến phòng thủ cuối cùng của bạn chống lại mất dữ liệu trong các kịch bản thảm khốc.
-
Hiểu về phân phối Hash Slot: Khi xử lý thủ công các dải hash slot hoặc cố gắng hiểu sự phân phối khóa trong một cluster, đôi khi một phép tính hash nhanh có thể hữu ích để xác minh hash slot mà một khóa cụ thể nên thuộc về. Để làm điều đó, tôi thường sử dụng các công cụ dựa trên trình duyệt như ToolCraft's Hash Generator – nó tiện lợi cho các kiểm tra nhanh mà không gửi dữ liệu đi bất cứ đâu, đặc biệt khi bạn cần xác nhận hash slot của một khóa hoặc gỡ lỗi tại sao một khóa có thể không đến được node mong muốn trong quá trình resharding phức tạp.

