Beyond synthetic testing: Capturing and replaying real database workloads at Airbnb

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

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

Bối cảnh

  • Fleet MySQL-compatible của Airbnb (2026): hàng trăm cụm, hàng nghìn use case, hàng triệu QPS. Bài toán: định cỡ cụm cho tăng trưởng, giữ hành vi qua nâng cấp và migration, tái hiện sự cố để debug.
  • Hệ capture cũ mượn từ pipeline observability: mỗi ngôn ngữ tự log query vào Kafka, mỗi use case tự xử lý, replayer riêng. Bảo trì nặng, chủ sở hữu mơ hồ, và thiếu ngữ cảnh giao dịch nên không replay chính xác được, không so được kết quả trên DB mới.
  • Benchmark tổng hợp (sysbench) không phủ được phổ query thật; digest của performance_schema chỉ là bản tóm tắt, không đủ để tái hiện.

Thay đổi chính

  • Một điểm capture không phụ thuộc client: ProxySQL vốn đã nằm giữa ứng dụng và DB; bật query logging theo query rule cho đúng một cụm, ghi ra đĩa local, ít ảnh hưởng hiệu năng. Log Mover sidecar chuyển file lên object storage.
  • Log Processor (offline): ProxySQL chạy trên Kubernetes thành pool pod stateless, mỗi file log trộn query của nhiều cụm → giải mã định dạng nhị phân, tách theo cụm, ghép lại câu lệnh của từng giao dịch đúng thứ tự (log xen kẽ nhiều kết nối), chia bucket 5 phút theo cụm và pod, kèm metadata. Viết lại INSERT để chèn tường minh last_insert_id đã ghi nhận, vì engine khác (hoặc MySQL 8.0 cấu hình khác) có thể cấp auto-increment khác và làm query sau trả rỗng; đổi lại không còn kiểm cơ chế auto-increment của đích.
  • Log Replayer: API server (web UI, trạng thái job trong DB), scheduler chia job thành batch task (mỗi task một file), đẩy vào message queue; worker scale tới hàng nghìn instance. Mọi task trong batch có cùng "expected start time" để worker bắt đầu đồng loạt, giữ được độ đồng thời gốc; trong file, worker giãn query theo timestamp gốc nhân hệ số tốc độ. Task lỗi thì scheduler ngừng lên lịch tiếp.
  • Hai chế độ: replay only (một đích, tốc độ 1×/2×/3× hoặc theo QPS, đo lỗi, histogram latency theo digest, tài nguyên) cho load test và capacity; replay and compare (hai đích cùng lúc, so kết quả) cho nâng cấp/migration.
  • Dữ liệu cá nhân: log mã hoá khi truyền và khi lưu, quyền tối thiểu chỉ cho team DB, chỉ bật logging trong cửa sổ cần test, chỉ replay vào môi trường tương đương production, không bao giờ vào môi trường thấp hơn.

Kết quả (theo Airbnb)

  • MySQL 5.7 → 8.0: một số workload chậm đi (metadata lock bảo thủ hơn). 8.0 bỏ query cache, nên replay 5.7 có/không query cache trước rồi mới so 5.7-không-cache với 8.0; phép chia đôi này lộ ra ứng dụng gửi nhiều query trùng lặp mà cache âm thầm hấp thụ. Ca nặng nhất: một mẫu query từ 0,03 lên 2,6 giây, đọc 273 MB mỗi join thay vì 5 MB, do thay đổi cách đọc dòng khi sort từ 8.0.20.
  • Đúng đắn: innodb_autoinc_lock_mode mặc định mới cấp ID xen kẽ, không tuần tự, trong khi vài ứng dụng giả định tuần tự. Replay-and-compare trên hai bản khôi phục từ cùng snapshot lộ mẫu query không có thứ tự xác định (không ORDER BY, hoặc ORDER BY không có khoá phá hoà) trả dòng khác trên engine mới khi có LIMIT; làm việc với team chủ để thêm thứ tự tường minh.
  • Capacity: replay 2× trước mùa cao điểm; một cụm lớn khi tăng 80% traffic ghi thì commit latency trung bình từ khoảng 6 lên 34 ms, lộ trần trước khi traffic thật tới. Có công cụ tự phục vụ cho team, cũng để tìm cụm dư để bin-pack. Nâng cấp toàn fleet lên 8.0 không có sự cố production lớn, làm cụm rủi ro nhất trước.

Bài học cho SWE

  • Theo Airbnb: benchmark tổng hợp cho biết DB xử lý workload bạn tưởng tượng; replay cho biết workload bạn thật sự có.
  • Capture ở proxy thay cho ở client: một điểm, không đổi ứng dụng, đủ ngữ cảnh giao dịch.
  • Replay đúng phải tái tạo cả đồng thời (cùng giờ xuất phát cho các worker) chứ không chỉ chuỗi câu lệnh.
  • Nâng cấp DB lộ ra giả định ngầm của ứng dụng (thứ tự dòng, ID tuần tự, query trùng được cache che); so kết quả trên hai đích là cách tìm chúng trước production.

Liên quan