Unlocking Horizontal Scalability in Our Web Serving Tier

Bài tóm tắt Airbnb 2016 2. Tăng trưởng Độ khó: Trung bình

Airbnb · 2016 · 2. Tăng trưởng · Độ khó: Trung bình — bài gốc

Bối cảnh

  • Monolith Rails chạy trên nhiều web server, nói chuyện với vài service Java; dữ liệu lõi trong MySQL trên RDS, đã tách database theo chức năng năm 2015.
  • MySQL community dùng mô hình một thread mỗi kết nối. Số kết nối từ app server tăng theo số máy, chạm giới hạn tài nguyên của RDS: giới hạn kết nối DB trở thành trần cho số app server. Cuối hè 2015, đội thấy sẽ nghẽn ở mùa cao điểm 2016.
  • Sự cố trước đó: Threads_running vọt lên (query xấu hoặc storage chập chờn) làm latency và tỉ lệ lỗi tăng khắp stack; kỹ sư phải kill kết nối bằng tay.

Thay đổi chính

  • Thread pool chỉ có ở MySQL enterprise, không có trên RDS → cần proxy ngoài. Chọn MariaDB MaxScale nhưng nó giữ một kết nối backend cho mỗi kết nối client, nên fork để thêm connection pooling.
  • Connection pooling: N kết nối client dồn qua M kết nối backend (pool thường 10). Proxy hiểu ngữ cảnh transaction để giữ liên kết tới khi commit, và chỉ trả kết nối về pool sau khi thấy đủ gói của response (phải cài theo giao thức COM_QUERY_RESPONSE).
  • Request throttling: pool cạn trên các proxy là tín hiệu DB sắp bị dồn thread, nên proxy chủ động kill kết nối client. Theo Airbnb, cơ chế này thay cho việc kỹ sư kill kết nối bằng tay và chặn được sự cố do storage chập chờn.
  • Query blocklist: dùng parse tree của MaxScale chặn UPDATE/DELETE không có điều kiện hoặc điều kiện dị dạng, chống câu query bị hỏng do lỗi hỏng heap của Ruby VM. Đã chặn ít nhất một lần.
  • Triển khai thành service: mỗi DB lõi một cụm proxy (một worker thread mỗi instance, nhiều instance), tìm qua SmartStack; thêm routing theo AZ để bớt latency của hop mạng mới; stress test bằng framework replay workload.
  • Đầu 2016 chuyển kết nối của monolith sang proxy, không đổi code app. Tới bài viết: hơn 15 service proxy, hàng trăm instance, chưa crash lần nào; mã nguồn mở.

Vì sao

  • Kiến trúc 2 tầng (app ↔ DB) làm số app server bị trói vào giới hạn kết nối DB; tầng thứ ba tách hai thứ đó để scale app ngang.

Bài học cho SWE

  • Kết nối DB là tài nguyên hữu hạn và thường là trần ẩn khi scale app ngang.
  • Proxy ở giữa là chỗ tự nhiên cho backpressure (cắt sớm khi DB có dấu hiệu dồn) và cho rào chắn an toàn (chặn query nguy hiểm).
  • Hop mạng mới cần đo bằng workload thật; routing cùng AZ giảm phần lớn chi phí.

Liên quan