How we store and process millions of orders daily

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

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

Bối cảnh

  • Grab Order Platform xử lý hàng triệu đơn GrabFood/GrabMart mỗi ngày (2022).
  • Giải pháp cũ: ghi đồng bộ vào cả DynamoDB lẫn Aurora, và giữ dữ liệu mãi mãi.
  • Phân tích trước khi thiết kế:
    • Truy vấn chia hai loại. Transactional (tạo/cập nhật đơn, lấy đơn theo id, đơn đang chạy của một khách) là sống còn. Analytical (lịch sử theo nhiều điều kiện, thống kê) thì không sống còn.
    • Giờ cao điểm: QPS ghi gấp 3 lần đọc theo khoá chính; QPS đọc theo khoảng gấp 4 lần.
  • Mục tiêu: ổn định (vẫn tạo và hoàn thành được đơn khi một phần hệ thống hỏng); scale và chi phí; nhất quán mạnh cho OLTP, nhất quán sau cho OLAP.

Thay đổi chính

  • Hai DB cho hai loại truy vấn:
    • OLTP = DynamoDB. Dữ liệu giữ ngắn (3 tháng), là nguồn sự thật cho xử lý đơn.
    • OLAP = MySQL RDS. Cùng dữ liệu nhưng giữ lâu hơn.
    • OLAP hỏng không ảnh hưởng giao dịch online.
  • DynamoDB chi tiết:
    • Partition key là order_id.
    • Truy vấn "đơn đang chạy của khách" dùng GSI dạng sparse index: khi đơn hoàn thành thì xoá pax_id_gsi, nên GSI chỉ chứa đơn đang chạy.
    • Adaptive capacity xử lý hot key, mỗi key nóng được dùng hết sức của một partition.
    • Bật TTL thẳng trên bảng lớn có thể làm quá tải bộ quét nền và gây sự cố. Họ chỉ gắn TTL cho item mới, tự xoá item cũ bằng script, rồi mới bật TTL.
  • MySQL RDS (không chọn Aurora): RDS đã chín, đủ cho việc ít quan trọng; Aurora tính tiền theo IOPS. Bảng partition theo tháng, drop partition cũ hơn 6 tháng.
  • Pipeline Kafka nối hai DB:
    • Producer lỗi thì đẩy vào SQS để retry, rồi dead letter queue.
    • Consumer retry có back-off; trường hợp xấu nhất thì tua lại stream.
    • Message trùng: chặn bằng unique key.
    • Sai thứ tự: chỉ cập nhật nếu bản mới hơn (version theo micro giây); update tới trước create thì giả lập upsert.

Vì sao

Theo Grab: một DB không tối ưu được cả hai mẫu truy vấn; tách ra thì chọn được DB hợp từng loại và cô lập lỗi. Kết quả nêu trong bài: tiết kiệm đáng kể chi phí cloud, nhưng không có con số.

Bài học cho SWE

  • Bắt đầu từ mẫu truy vấn và traffic, rồi mới chọn DB.
  • Pipeline bất đồng bộ phải xử lý được trùng lặp và sai thứ tự ngay từ thiết kế.
  • Retention là quyết định kiến trúc: giữ dữ liệu mãi mãi là một khoản chi phí.
  • Tính năng "tự động" của managed DB (TTL) cũng có thể gây sự cố khi bật trên dữ liệu lớn.
  • Bước tiếp họ nêu: MySQL khó làm full-text search, nên đang tính tới Elasticsearch.

Liên quan