Meet Bandaid, the Dropbox service proxy

Bài tóm tắt Dropbox 2018 3. Quy mô lớn Độ khó: Nâng cao

Dropbox · 2018 · 3. Quy mô lớn · Độ khó: Nâng cao — bài gốc

Bối cảnh

  • Bandaid bắt đầu là reverse proxy bù cho điểm yếu của các service phía server, rồi thành service proxy giúp Dropbox chuyển sang SOA. Viết bằng Go như phần lớn hạ tầng lõi; hỗ trợ TLS termination, HTTP/2, gRPC, service discovery, reload cấu hình không restart, health check.
  • Lý do tự xây theo Dropbox: tích hợp hạ tầng nội bộ, dùng lại thư viện, tự đổi khi cần.

Thay đổi chính

  • Hàng đợi trong user-space, luôn xử lý LIFO. Khi không quá tải hàng đợi gần rỗng nên LIFO hay FIFO như nhau; khi quá tải, xử lý request mới nhất trước vì request cũ sắp timeout. Request nằm hàng đợi quá timeout thì bị fail luôn.
  • Giữ kernel accept queue rỗng: Bandaid luôn accept TCP rồi tự xếp hàng. Lý do: client timeout và đóng kết nối bằng FIN khi request còn trong accept queue của kernel; server không biết, vẫn xử lý rồi mới gặp RST khi ghi. Retry dồn thêm kết nối đã chết vào queue.
  • Không khuyến nghị drop khi hàng đợi đầy vì khó phân biệt quá tải với traffic bùng nổ.
  • Worker pool cố định để khống chế concurrency tới upstream; số worker quá lớn so với số host khoẻ làm mất tác dụng graceful degradation.
  • Nhiều hàng đợi cho một upstream, mỗi hàng có weight, kích thước, rate limit, priority: dùng cho canary theo tỉ lệ (90/10, đổi trong vài giây nhờ hot reload) và cô lập route quan trọng với route phụ trên cùng host. Dequeue theo priority có tham số chống starvation.
  • Load balancing: round robin, least connections của N lựa chọn ngẫu nhiên, absolute least connections, pinning peer (mỗi worker gắn một host). Công thức của bài: host chậm 50 lần, chỉ chiếm 5% số host, có thể giữ khoảng 70% capacity khi dùng round robin.
  • Test tổng hợp (100.000 request, 100 worker, 10 backend) trước khi đưa lên production; loại host đã thử khi retry giảm tỉ lệ lỗi với 20% host hỏng (trừ pinning peer).

Vì sao

  • Theo Dropbox, quản lý kết nối trong hàng đợi của mình cho nhiều quyền kiểm soát hơn để giải phóng tài nguyên backend sớm khi client đã bỏ đi.

Bài học cho SWE

  • Dưới quá tải, FIFO phục vụ request mà client đã bỏ; LIFO + timeout trong hàng đợi giữ được phần việc còn có ích.
  • Hàng đợi ẩn trong kernel (accept backlog) cũng là hàng đợi cần quản lý.
  • Round robin rất nhạy với vài host chậm; thuật toán dựa trên số kết nối đang mở tự giảm tải cho host chậm.

Liên quan