From Local to Global: Building Seamless B2C Product Integration at Mercari

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

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

Một bài trong series Global App (ngoài sheet). Bối cảnh: Mercari 2025.

Bối cảnh

  • Sản phẩm của các shop B2C Nhật (Mercari Shops) phải xuất hiện gần real-time trên Global Foundation. Hai thế giới khác data model: C2C một món một listing; B2C một sản phẩm có nhiều biến thể (cỡ, màu), mỗi biến thể tồn kho riêng. Hàng triệu sản phẩm, hàng nghìn shop.

Thay đổi chính

  • Hai đường đồng bộ qua cùng một service ProductSync:
    • Live sync: event Pub/Sub (tạo/sửa/xoá sản phẩm, đổi tồn kho), giao qua PubSub gRPC Pusher (sản phẩm nội bộ của Mercari, đẩy message thành request gRPC với tốc độ kiểm soát được). Mỗi event gọi API của Shops để lấy trạng thái mới nhất thay vì tin payload.
    • Historical sync: batch từ file export BigQuery trên GCS cho listing cũ (hết hàng, ngừng bán) và để sửa dữ liệu lệch; cấu hình theo job: offset bắt đầu/kết thúc, kích thước trang, độ song song, rate limit.
  • Sync Tracker: chống trùng theo message ID, kiểm timestamp chống event đến sai thứ tự, ghi lại để giám sát và audit.
  • Chuỗi tách bước: sync → lưu → phát event → SearchIndexer cập nhật index bất đồng bộ, không chặn luồng sync.
  • Ranh giới trong modular monolith: một module riêng nhận event từ Shops và đổi sang model của Global Foundation, chỉ gọi API nội bộ của module inventory; inventory có API riêng cho sản phẩm có biến thể nhưng dùng lại API nội bộ sẵn có; search thống nhất interface cho C2C và B2C.
  • Phát hành theo bậc: live sync bắt đầu với một shop; index nhưng mặc định loại sản phẩm shop khỏi kết quả search; bật hiển thị qua feature flag cho người dùng nội bộ; rồi thêm shop vào whitelist bằng cấu hình. Historical sync chạy giờ thấp điểm, từ shop ít sản phẩm tới shop nhiều, chỉnh RPS theo capacity của cả service phụ thuộc, thử lại phần lỗi.

Vì sao

  • Dữ liệu trong event có thể cũ hoặc thiếu; đọc lại từ nguồn sự thật đổi lấy độ đầy đủ, với giá là phụ thuộc vào API của hệ khác (cần retry, rate limit, xuống cấp nhẹ nhàng).

Bài học cho SWE

  • Hai đường (stream cho cái mới, batch cho cái cũ và để sửa) qua cùng một chỗ ghi, có bộ theo dõi chống trùng và chống sai thứ tự.
  • Nhập dữ liệu mới vào production theo bậc: một đơn vị nhỏ, index nhưng ẩn, bật cho nội bộ, rồi mở rộng bằng cấu hình.

Liên quan