Chiến lược xử lý khi node bị down hoặc mất kết nối mạng
Khi một node trong cluster Cassandra bị sập hoặc mất kết nối mạng, hệ thống sẽ tự động chuyển hướng các request viết (write) đến các node còn lại nếu cấu hình hinted_handoff được bật. Tuy nhiên, nếu node đó không quay lại sau một khoảng thời gian nhất định, dữ liệu sẽ bị đánh dấu là lỗi hoặc bị xóa tùy thuộc vào gc_grace_seconds.
Bước 1: Xác định trạng thái của node bị lỗi.
Thực hiện lệnh để kiểm tra trạng thái của toàn bộ cluster. Mục tiêu là tìm node có trạng thái DOWN hoặc UNREACHABLE.
nodetool status
Kết quả mong đợi: Danh sách các node với trạng thái UN (Up/Normal) hoặc UN (Up/Draining). Node bị lỗi sẽ hiển thị DN (Down/Normal) hoặc UN (Up/Leaving) nếu đang bị tách ra. Nếu thấy DN, node đó không phản hồi.
Bước 2: Xử lý node bị treo (Zombie Node) không thể khởi động lại.
Trường hợp node đã bị sập vật lý hoặc filesystem bị hỏng khiến nó không thể tham gia lại cluster. Bạn cần loại bỏ node này khỏi giao thức Gossip để cluster ổn định.
nodetool removenode <TOKEN_NODE_BỊ_LỖI>
Thay thế <TOKEN_NODE_BỊ_LỖI> bằng giá trị token của node bị lỗi (có thể lấy từ bước 1). Kết quả mong đợi: Cassandra báo Removing node... và trạng thái của node đó biến mất khỏi danh sách nodetool status. Dữ liệu trên node đó sẽ được coi là mất, các node khác sẽ tự động tái phân phối (rebalance) dữ liệu.
Bước 3: Khôi phục node đã được sửa lỗi.
Sau khi khắc phục nguyên nhân (ví dụ: sửa cấu hình, thay ổ cứng), khởi động lại Cassandra trên node đó. Để đảm bảo node nhận dữ liệu mới nhất, hãy thực hiện repair trước khi đưa vào hoạt động đầy đủ.
systemctl start cassandra
nodetool repair
Kết quả mong đợi: Node hiển thị trạng thái UN trong nodetool status và quá trình repair hoàn thành không lỗi.
Phân tích và sửa lỗi Compaction, Hinted Handoff, và Anti-Entropy
Đây là ba cơ chế cốt lõi đảm bảo tính nhất quán dữ liệu. Khi chúng bị lỗi, hiệu năng sẽ giảm hoặc dữ liệu bị phân mảnh.
Bước 1: Xử lý lỗi Compaction bị tắc nghẽn.
Khi compaction bị treo, disk I/O tăng cao, gây chậm truy vấn. Nguyên nhân thường do quá nhiều SSTables chưa được hợp nhất. Kiểm tra số lượng SSTables.
nodetool compactionstats
Kết quả mong đợi: Xem số lượng SSTables đang chờ compaction. Nếu số lượng quá lớn (ví dụ > 1000 cho một keyspace), cần can thiệp.
Thực hiện compaction thủ công để dọn dẹp nhanh chóng (chỉ dùng trong sự cố).
nodetool compact <KEYSPACE_NAME> <TABLE_NAME>
Kết quả mong đợi: Quá trình compaction chạy xong, số lượng SSTables giảm, I/O disk trở lại bình thường.
Bước 2: Kiểm tra và làm sạch Hinted Handoff.
Hinted Handoff lưu các write tạm thời khi node đích không online. Nếu node đích không quay lại, các hint này sẽ tồn tại và gây tốn disk. Kiểm tra số lượng hint đang chờ.
nodetool tpstats
Kết quả mong đợi: Tìm dòng HintedHandoff. Nếu có số lượng task đang chạy hoặc hàng đợi (queue) lớn, cần can thiệp.
Xóa các hint quá hạn (khi node đích đã chắc chắn bị loại bỏ vĩnh viễn hoặc đã được sửa).
nodetool clearhintedhandoff
Kết quả mong đợi: Hàng đợi hint được làm sạch, giảm áp lực lên disk I/O của node.
Bước 3: Xử lý lỗi Anti-Entropy (Repair).
Lệnh repair bị lỗi thường do xung đột phiên bản hoặc lỗi checksum. Kiểm tra log để tìm lỗi cụ thể.
tail -n 100 /var/log/cassandra/system.log | grep -i "repair"
Kết quả mong đợi: Tìm thấy thông báo lỗi như Repair failed hoặc Checksum mismatch.
Để khắc phục lỗi checksum, hãy chạy repair với chế độ xóa dữ liệu bị hỏng (nếu chấp nhận mất dữ liệu không nhất quán) hoặc chỉ sửa lại metadata.
nodetool repair -full
Kết quả mong đợi: Quá trình repair chạy lại và hoàn thành, đảm bảo dữ liệu trên các replica đồng nhất.
Tái cân bằng dữ liệu (rebalance) khi mở rộng hoặc thu hẹp cluster
Khi thêm hoặc bớt node, Cassandra tự động phân phối lại dữ liệu dựa trên token ring. Tuy nhiên, trong môi trường sản xuất, việc để hệ thống tự động balance có thể gây tải cao đột ngột. Cần kiểm soát quá trình này.
Bước 1: Chuẩn bị trước khi thêm node mới.
Trước khi khởi động node mới, hãy tắt tính năng tự động balance để tránh việc các node cũ phải chuyển dữ liệu ngay lập tức gây nghẽn mạng.
nodetool status
Xác nhận số node hiện tại. Sau đó, thêm node mới vào cluster.
systemctl start cassandra
Chờ node mới xuất hiện trong nodetool status với trạng thái UN.
Bước 2: Kích hoạt Rebalance thủ công.
Sau khi node mới online, dữ liệu chưa được phân phối đều. Sử dụng nodetool decommission để rút node cũ (nếu muốn thu hẹp) hoặc chạy nodetool rebuild để chuyển dữ liệu từ node cũ sang node mới.
Để chuyển dữ liệu từ node A sang node B (rebalance):
nodetool rebuild <SOURCE_NODE_IP>
Kết quả mong đợi: Node đích (node mới) bắt đầu nhận dữ liệu từ node nguồn. Quá trình này có thể mất vài giờ tùy thuộc vào lượng dữ liệu.
Bước 3: Thu hẹp cluster (Decommission).
Để loại bỏ node khỏi cluster một cách an toàn, dữ liệu trên node đó sẽ được di chuyển sang các node còn lại trước khi tắt hẳn.
nodetool decommission
Chạy lệnh này trên node cần loại bỏ. Kết quả mong đợi: Node chuyển sang trạng thái LEAVING, sau đó là DOWN và biến mất khỏi nodetool status. Dữ liệu đã được phân phối lại cho các node còn lại.
Bước 4: Verify kết quả cân bằng.
Sử dụng công cụ bên thứ ba hoặc lệnh kiểm tra phân bố token.
nodetool ring
Kết quả mong đợi: Danh sách token ring cho thấy dữ liệu được phân bổ đều trên các node còn lại, không có khoảng trống (gap) lớn.
Tối ưu hóa tham số JVM và Garbage Collection cho workload lớn
Hiệu năng của Cassandra phụ thuộc rất lớn vào cách JVM quản lý bộ nhớ. Default configuration thường không phù hợp cho workload sản xuất lớn. Cần tinh chỉnh để giảm thiểu thời gian Garbage Collection (GC) gây ra latency spike.
Bước 1: Xác định bộ nhớ RAM dành cho Cassandra.
Quy tắc chung: Dành 50% RAM cho JVM Heap, nhưng không vượt quá 32GB Heap. Phần RAM còn lại dành cho OS Page Cache (ổ đĩa). Nếu RAM server là 64GB, Heap nên đặt là 32GB.
Bước 2: Cấu hình JVM với G1GC.
Cassandra 4.x và 5.x sử dụng G1GC (Garbage First Garbage Collector) mặc định. Cần chỉnh sửa file cassandra-env.sh để tối ưu.
Đường dẫn file: /etc/cassandra/cassandra-env.sh
Sửa các dòng sau trong file (thay thế HEAP_SIZE bằng số GB phù hợp, ví dụ 32G):
JVM_OPTS="$JVM_OPTS -Xms32g -Xmx32g"
JVM_OPTS="$JVM_OPTS -XX:+UseG1GC"
JVM_OPTS="$JVM_OPTS -XX:MaxGCPauseMillis=500"
JVM_OPTS="$JVM_OPTS -XX:G1HeapRegionSize=16m"
JVM_OPTS="$JVM_OPTS -XX:+ParallelRefProcEnabled"
JVM_OPTS="$JVM_OPTS -XX:+ExplicitGCInvokesConcurrent"
JVM_OPTS="$JVM_OPTS -XX:+HeapDumpOnOutOfMemoryError"
JVM_OPTS="$JVM_OPTS -XX:HeapDumpPath=/var/log/cassandra"
Kết quả mong đợi: File cấu hình được lưu. Các tham số này giúp GC chạy nhanh hơn, giới hạn thời gian dừng (pause time) ở 500ms và tạo dump file khi hết bộ nhớ.
Bước 3: Tối ưu hóa compaction trong Cassandra.
Tăng tốc độ compaction bằng cách điều chỉnh số lượng thread compaction dựa trên số CPU core.
Đường dẫn file: /etc/cassandra/cassandra.yaml
Sửa dòng concurrent_compactors:
concurrent_compactors: 2
Ghi chú: Giá trị này thường đặt bằng số core CPU chia 2 hoặc 4, tùy thuộc vào loại ổ cứng (SSD có thể cao hơn HDD). Kết quả mong đợi: Tốc độ hợp nhất SSTables tăng lên, giảm backlog compaction.
Bước 4: Verify cấu hình JVM sau khi restart.
Khởi động lại dịch vụ Cassandra để áp dụng thay đổi.
systemctl restart cassandra
Đợi 1-2 phút, sau đó kiểm tra quá trình JVM đang chạy với các tham số đã đặt.
jps -l | grep cassandra
ps -ef | grep cassandra | grep -oP 'JVM_OPTS.*' | head -1
Kết quả mong đợi: Quá trình Cassandra chạy với các tham số Heap Size và GC options đã cấu hình. Kiểm tra log để đảm bảo không có lỗi khởi động liên quan đến bộ nhớ.
tail -n 50 /var/log/cassandra/system.log | grep -i "jvm"
Kết quả mong đợi: Log hiển thị thông báo khởi động thành công với cấu hình G1GC và Heap size mong muốn.
Điều hướng series:
Mục lục: Series: Triển khai Database phân tán với Apache Cassandra và Ubuntu 24.04
« Phần 6: Giám sát và bảo trì cluster Cassandra trong môi trường sản xuất