Sitar-agent: Building a reliable dynamic configuration sidecar at scale

Bài tóm tắt Airbnb 2026 3. Quy mô lớn Độ khó: Trung bình

Airbnb · 2026 · 3. Quy mô lớn · Độ khó: Trung bình — bài gốc

Phần tiếp của Airbnb 2026.

Bối cảnh

  • Config thay đổi vài lần mỗi phút, phải tới hàng nghìn service, hàng chục nghìn pod, trong vài chục giây, không cần deploy lại. Config luôn phải đọc được kể cả khi Sitar Service sập (cũ một chút thì được, không đọc được thì không). Fleet viết bằng Java, Python, Go, TypeScript, Ruby.

Thay đổi chính

  • Vòng đời giao config: commit vào Sitar Service (version, changelog, ACL) → Snapshot Service mỗi giờ đóng gói toàn bộ config lên S3 → khi pod khởi động, sidecar chạy trước, tải snapshot từ S3 vào đĩa chung với container chính, rồi đồng bộ phần thay đổi từ sau snapshot với Sitar Service, xong mới báo ready để container chính khởi động → sau đó poll vài giây một lần có jitter → client library đọc file trên đĩa vào cache trong bộ nhớ, phát hiện file đổi thì tự làm mới.
  • Viết lại từ Ruby sang Java (2024); snapshot S3 là kết quả của đợt này: khởi động nhanh hơn, không phụ thuộc Sitar Service lúc khởi động, không có đỉnh tải khi deploy hàng loạt.
  • Sidecar hay library trong container chính: library tiết kiệm JVM mỗi pod và bớt một container; nhưng phải viết lại logic cho 5 ngôn ngữ, mất cô lập (bug hay tăng tài nguyên của bên này làm chết bên kia), log và metric lẫn nhau. Kết luận: tiết kiệm không đủ bù, giữ sidecar.
  • Giữ mô hình pull, giảm chi phí mỗi lần poll: poll mỗi 10 giây; push giảm tải và độ trễ nhưng phức tạp hơn. Thay vào đó: cache phía server TTL 10 giây (config đổi bằng tay nên trễ vài giây không sao, phần lớn lần poll trúng cache); khi miss thì client gửi token là dòng DB đã quét cuối cùng để server bỏ qua phần cũ. Server vẫn stateless.
  • Kho local Sparkey → SQLite: Sparkey thiết kế cho ghi một lần đọc nhiều, không có điều phối đọc/ghi đa luồng (phải khoá cả file khi ghi), mỗi lần ghi phải index lại toàn bộ, trong khi gần như mỗi chu kỳ 10 giây đều có config đổi; không có thư viện cho mọi ngôn ngữ. Benchmark SQLite và RocksDB theo ma trận kích thước dữ liệu, QPS đọc, bộ nhớ: RocksDB nhanh nhất (đọc nhanh hơn SQLite 2–3 lần) nhưng phải tune compaction, block cache, ít thư viện đa ngôn ngữ đều tay; SQLite có binding chính thức cho cả 5 ngôn ngữ, WAL cho đọc trong lúc ghi, một file, không cần tune, và đủ nhanh. Chọn SQLite.
  • Chuyển an toàn: shadow read (vẫn đọc Sparkey, đọc song song SQLite để so) rồi feature flag mở dần từ service ít quan trọng tới Tier 0 cuối cùng.

Vì sao

  • Mọi quyết định cân giữa bốn yêu cầu: luôn đọc được, lan nhanh, chịu được hàng chục nghìn pod cùng poll, chạy cho mọi ngôn ngữ mà không nhân công bảo trì.

Bài học cho SWE

  • Bootstrap từ snapshot tĩnh (S3) tách độ tin cậy lúc khởi động khỏi availability của dịch vụ điều khiển, và tránh thundering herd khi deploy.
  • Trước khi chuyển sang push, thử làm pull rẻ hơn (cache ngắn ở server, token gia tăng); pull stateless đơn giản hơn nhiều khi vận hành.
  • Chọn công nghệ "đủ nhanh, dễ vận hành, có mặt ở mọi ngôn ngữ" thay cho "nhanh nhất" khi team phải hỗ trợ nhiều runtime.

Liên quan