Failing to Auto Scale Elasticsearch in Kubernetes
Bài tóm tắt Zalando 2024 3. Quy mô lớn Độ khó: Trung bình
Zalando · 2024 · 3. Quy mô lớn · Độ khó: Trung bình — bài gốc
Bối cảnh
- Lounge by Zalando lưu mô tả sản phẩm trong một cụm Elasticsearch trên Kubernetes, vận hành bằng es-operator (custom resource ElasticsearchDataSet → StatefulSet). Pod rải qua mọi AZ; Elasticsearch bật zone awareness để rải shard theo AZ.
- Giờ cao điểm buổi sáng tải gấp khoảng 3 lần, nên họ scale theo lịch bằng một bộ cronjob khá phức tạp (sửa số node trong resource). Sáng mà không scale ra được là thảm hoạ.
Diễn biến
- Ngày 1: cảnh báo thiếu node Elasticsearch buổi sáng, rồi tự đóng trước khi kịp làm theo playbook. Đêm trước, cụm kẹt ở 7 node thay vì 6: StatefulSet luôn bỏ pod số lớn nhất, mà pod đó lại là node duy nhất ở eu-central-1a; vì zone awareness, Elasticsearch từ chối dời shard ra khỏi nó. Operator thử dời 999 lần suốt đêm.
- Lẽ ra khi resource đổi (lịch scale ra buổi sáng) operator phải bỏ việc đang làm để theo trạng thái mới; nhưng vòng retry khi drain node không phản ứng với huỷ context. Bug đã sửa upstream.
- Vì sao giờ mới xảy ra: pod chạy trên ephemeral storage (dữ liệu dựng lại được) nên Kubernetes không cam kết giữ AZ của pod; hôm trước cụm vừa nâng cấp lên 1.28, có lẽ đã làm xáo phân bố pod theo AZ.
- Sửa tạm 1: tăng số node ban đêm để không phải drain node cuối ở 1a. Sáng hôm sau cảnh báo y hệt: lần này không bỏ được node số 7 dù 1a còn hai node.
- Bug thứ hai: quy trình scale vào là đánh dấu node bị loại trừ → chờ hết shard → xoá pod → dọn danh sách loại trừ. Bị ngắt giữa chừng thì bước dọn không bao giờ chạy, nên node số 6 hôm trước vẫn bị loại trừ vĩnh viễn ("zombie"), và node 7 thành node dùng được duy nhất ở 1a.
- Gỡ tay node zombie khỏi danh sách. Sửa gốc khó hơn nhiều: thêm
ifcho trường hợp huỷ không đủ, vì operator có thể crash giữa chừng (lỗi một phần). PR còn dở; họ tạm chấp nhận xử lý tay.
- Ngày 3: cảnh báo lần nữa, vì bản sửa tạm chỉ chạm cronjob scale đêm chính, quên một cronjob của dự án thử nghiệm.
Bài học (theo Zalando)
Đọc code: hiểu quy trình ở mức trừu tượng không đủ; chi tiết mới là tài liệu cuối cùng.
Bài học cho SWE
- Operator nhiều bước phải bỏ việc dở được khi trạng thái mong muốn đổi, và phải để lại trạng thái sạch khi bị ngắt hay crash giữa chừng (Tự động hoá vận hành và auto-remediation).
- Ràng buộc an toàn (zone awareness) và tự động hoá (scale theo lịch) có thể chặn nhau; cần mô hình hoá cả hai, như cách Stripe coi sửa chữa là tìm đường qua các trạng thái an toàn (Stripe 2026).
- Một thay đổi nền (nâng cấp Kubernetes) làm lộ bug đã nằm sẵn; sự cố "tự khỏi" vẫn cần tìm gốc (Sự cố và postmortem).
- Sửa tạm phải phủ mọi đường gây ra lỗi (cả cronjob phụ).
Liên quan
Được nhắc tới trong
Công ty (1)
Bài tóm tắt (1)