Halving the Time: How Uber Eats Rebuilt Its Search Pipeline

Bài tóm tắt Uber 2026 4. Điều chỉnh Độ khó: Trung bình

Uber · 2026 · 4. Điều chỉnh · Độ khó: Trung bình — bài gốc

Bối cảnh

  • Latency search của Uber Eats đã tăng tới mức không chấp nhận được. Ba nguyên nhân chính: retrieval lấy hàng chục nghìn ứng viên rồi hydrate đầy đủ tất cả trước khi ranking bỏ phần lớn; hydration là một pha nguyên khối chặn cả ranking lẫn hiển thị; DAG có phụ thuộc giả (bước chờ output mà nó không cần). Theo Uber, các nút thắt vô hình cho tới khi đo đúng độ phân giải. Kết quả: latency giảm một nửa qua nhiều luồng việc song song trên cả stack.

Thay đổi chính

  • Đổi metric chính từ latency API backend sang ATF (Above-the-Fold): từ lúc gửi query tới khi màn hình đầu có kết quả và ảnh hiện đủ; API nhanh lên mà người dùng không thấy khác nếu nghẽn ở truyền payload, render template hay tải ảnh. Phân trang với cache phía server (trang đầu nhỏ, phần còn lại cache cho lúc cuộn) và render template song song (trước đó tuần tự, tăng tuyến tính theo cỡ trang): ATF nhanh hơn hơn 200 ms.
  • Retrieval: thí nghiệm offline và online cho thấy vài chiến lược retrieval từ khoá phạm vi rộng tốn nhiều latency mà ít đóng góp (kết quả đã có từ nguồn khác, gồm semantic); bỏ chúng giảm khoảng 120 ms không hồi quy conversion. Dedupe chuỗi cửa hàng sớm hơn. Gom item theo sản phẩm bằng embedding mức sản phẩm: số lượt tra dữ liệu giảm hơn 100 lần, retrieval −50 ms, đủ nhỏ để phục vụ hoàn toàn từ bộ nhớ.
  • Ranking: tách hydration thành hai pha song song, hydration cho ranking chỉ lấy tín hiệu chấm điểm và hydration cho hiển thị (giá, khuyến mãi, tồn kho) bất đồng bộ: hơn 100 ms. Bỏ phụ thuộc giả (ranking item song song với hydration) −35 ms; bỏ phụ thuộc tín hiệu item trực tiếp khỏi model xếp hạng cửa hàng để hai bước chạy độc lập (mục tiêu −20 ms). Request hedging ở bốn tầng phụ thuộc của hydration hiển thị (quá ngưỡng thì gửi bản sao tới instance khác, lấy cái về trước), hiệu quả vì latency chủ yếu do dao động riêng lẻ của shard chứ không do chậm đồng loạt: −40 ms. Phục vụ model trên GPU, cache model relevance.
  • Quảng cáo: dữ liệu bid lưu dạng dòng lặp lại metadata cho mỗi bid, tốn serialize; chuyển sang dạng cột khớp mẫu truy cập khi chấm điểm, đưa dữ liệu quảng cáo (campaign, pacing) vào bộ nhớ ứng dụng thay vì gọi DB, bỏ các vòng serialize thừa giữa thành phần, lọc trường không dùng trước khi gửi: tổng khoảng 130 ms.
  • Tinh chỉnh hạ tầng (khoảng 200 ms tổng): encode/decode kết quả lớn theo khúc song song thay vì tuần tự (hơn 50 ms); embedding giảm độ chính xác số thực còn 5 chữ số thập phân + mã hoá số nguyên độ dài thay đổi: nhỏ hơn 46%, query DB nhanh gấp đôi; service mesh mỗi đích một kết nối với trần request đang bay cố định, service throughput cao âm thầm chạm trần và xếp hàng, mở nhiều kết nối song song giảm latency tới 53%; trong Go, đối tượng tham chiếu bằng con trỏ cấp trên heap và GC chiếm hơn 40% CPU ở vài service, đổi định nghĩa mô hình dữ liệu sang value type để cấp trên stack.
  • Vòng lặp agent: giao cho coding agent một mục tiêu tiết kiệm latency và công cụ riêng (kéo profile latency production, chỉ ra span nghẽn nhất, viết bản sửa, mở PR, chạy benchmark latency trước khi merge); lặp đo → tìm → sửa → kiểm tới khi đạt mục tiêu hoặc lợi ích biên dưới ngưỡng. Điều kiện then chốt: kiểm nhanh bằng khung đánh giá có LLM hỗ trợ để chắc latency giảm không làm tệ chất lượng search. Theo Uber, hiệu quả nhất với loại việc nhỏ lẻ nhưng cộng dồn lớn: việc thừa trên đường găng, phát metric chặn thay vì bất đồng bộ, lấy config thừa trong vòng query, mẫu cấp phát gây GC.
  • Hướng tiếp: microbatching đầu–cuối để ứng viên đi tiếp ngay khi có, không chờ shard chậm nhất ở mỗi pha (ước hơn 100 ms); search theo sản phẩm thay vì item (catalog nhỏ đi khoảng 100 lần, thử sớm p99 −50%); Zero-Pass Ranking chấm và lọc ngay ở tầng index; stream kết quả bằng HTTP multipart.

Vì sao

  • Theo Uber, triết lý là làm ít việc hơn, bắt đầu việc sớm hơn, và đo liên tục; latency là bài toán cả stack, không chỉ backend.

Bài học cho SWE

  • Chọn metric người dùng thật sự cảm thấy (màn hình đầu hiện xong), không chỉ latency của một tầng.
  • Hydrate sau khi lọc, và tách dữ liệu cần cho quyết định khỏi dữ liệu cần cho hiển thị.
  • Rà DAG tìm phụ thuộc giả: chúng tích tụ theo thời gian và tuần tự hoá việc song song được.
  • Hedging hiệu quả khi chậm là dao động độc lập của từng instance; vô ích khi chậm đồng loạt.
  • Giới hạn ẩn của hạ tầng chung (một kết nối mỗi đích, trần in-flight) có thể là nút thắt lớn nhất.
  • Agent tối ưu hiệu quả khi có vòng kiểm nhanh cả hiệu năng lẫn chất lượng trước khi merge.

Liên quan