6 Lessons we learned when debugging a scaling problem on GitLab.com
Bài tóm tắt GitLab 2019 2. Tăng trưởng Độ khó: Trung bình
GitLab · 2019 · 2. Tăng trưởng · Độ khó: Trung bình — bài gốc
Bối cảnh
- Khách hàng báo lỗi
git pullqua SSH chập chờn, chủ yếu từ CI và job tự động:ssh_exchange_identification: connection closed by remote host. Không tái hiện được, không thấy gì rõ trên graph hay log. - GitLab.com nhận khoảng 26–28 triệu kết nối Git-over-SSH/ngày (khoảng 300/giây trung bình, 2019); 16 frontend HAProxy chính + 2 cho cổng SSH thay thế, 27 backend SSH.
Diễn tiến điều tra
- Packet capture với IP của một khách bị lỗi thường xuyên: HAProxy chủ động đóng kết nối (FIN đúng chuẩn) ngay sau khi client gửi version string, nên lỗi nằm phía GitLab. (Tác giả tự nhận: lẽ ra nên dùng ngay bảng "Conversations" của Wireshark để lọc kết nối ít gói.)
- Log HAProxy (lưu trong BigQuery) có
t_state = SD: backend đóng phiên. Capture giữa HAProxy và Git server: sshd tự đóng kết nối ngay sau bắt tay TCP. - Gom lỗi theo giây trong phút: đỉnh trong 10 giây đầu mỗi phút, cao nhất khoảng giây 5–6, đỉnh trung bình gấp 3 lần nền. Tác giả gọi đây là "the tyranny of the clock": cron và scheduler của người dùng khắp internet chạy đúng đầu phút/giờ (NTP làm chúng đồng bộ hoàn hảo), chuẩn bị vài giây rồi cùng
git fetch. - Nguyên nhân:
MaxStartupscủa sshd (số kết nối đang ở giai đoạn chưa xác thực). Mặc định 10:30:100, GitLab đã đặt 100:30:200. OpenSSH 7.2 chỉ báo vượt ngưỡng ở log mức Debug, nên bật Debug ngắn trên một máy để xác nhận.
Thay đổi chính
- Tăng
MaxStartups50% (150:30:300): lỗi giảm mạnh, CPU không tăng. Lỗi còn lại dồn vào các mốc tròn: đầu giờ, mỗi 30, 15, 10 phút. - Rate limit phiên mới ở HAProxy (
rate-limit sessions): kết nối vượt ngưỡng không bị từ chối mà chờ trên socket, client chỉ thấy bắt tay chậm hơn. Tính ngưỡng từ bốn đại lượng: số frontend, số backend,MaxStartups, vàT= thời gian một phiên SSH qua được xác thực (ước 2 giây → khoảng 110/giây mỗi frontend). Triển khai xong không có tác dụng thấy được. - Phát hiện cân bằng tải lệch: HAProxy dùng
balance source(cùng IP luôn vào cùng backend, không ai nhớ vì sao chọn), một giây có backend nhận 30, backend khác 121 kết nối; CPU các backend lệch 2:1. Đổi sangleastconnthì đều hẳn. - Tăng tiếp
MaxStartupslên 250 thì lỗi gần như hết; suy ngược raTthực khoảng 2,7–3,4 giây, dài hơn ước lượng. Sau khi triển khai chính thứcleastconn, lỗi về 0. - Nhìn lại: dấu hiệu nhận diện chính xác là
t_state = SDvà client đọc 0 byte; ở đỉnh vấn đề khoảng 1,5% kết nối SSH bị rớt, lớn hơn nhiều so với tưởng ban đầu. Đo sớm thì đã ưu tiên sớm hơn. - Giai đoạn xác thực chậm một phần vì tra SSH key qua API nội bộ, mà các worker unicorn trên máy Git bị xếp hàng; việc tối ưu tiếp tục.
Bài học (theo GitLab)
- Hệ phức tạp có nhiều đòn bẩy cho cùng một nút thắt, mỗi cái có đánh đổi riêng; ước lượng sai một đại lượng (
T) làm cả phép tính sai. - Cần cảnh báo trên chính dấu hiệu lỗi trong log HAProxy, vì đáng ra nó không bao giờ xảy ra.
- Lời khuyên cho người dùng dịch vụ tập trung: thêm sleep ngẫu nhiên (khoảng 30 giây) hoặc chọn phút ngẫu nhiên trong giờ cho job định kỳ.
Bài học cho SWE
- Thundering herd không chỉ đến từ cache hết hạn; lịch tròn của con người cũng tạo đỉnh đồng bộ ở phía nhà cung cấp (Hot partition và thundering herd).
- Cho kết nối mới chờ (rate limit ở proxy) dịu hơn là từ chối; nhưng nó chỉ hiệu quả khi tải đã chia đều (Load shedding, rate limit và backpressure).
- Cấu hình "sticky" không ai nhớ lý do là món nợ; định lượng lỗi từ đầu (bao nhiêu % bị ảnh hưởng) quyết định mức ưu tiên điều tra (Sự cố và postmortem).
Liên quan
Được nhắc tới trong
Chủ đề (3)
Công ty (1)