Lessons Learned From Scaling Uber To 2000 Engineers, 1000 Services, And 8000 Git Repositories

Bài tóm tắt Uber 2016 3. Quy mô lớn Độ khó: Dễ

Uber · 2016 · 3. Quy mô lớn · Độ khó: Dễ — bài gốc

Nguồn thứ cấp: đây là bản tóm tắt của HighScalability cho bài talk "What I Wish I Had Known Before Scaling Uber to 1000 Services" của Matt Ranney (Chief Systems Architect của Uber). Các nhận định bên dưới là theo Matt Ranney qua lời kể của HighScalability.

Bối cảnh (4/2016)

  • Uber có mặt ở 400 thành phố, 70 quốc gia, 6.000+ nhân viên, 2.000 kỹ sư (1,5 năm trước chỉ có 200), khoảng 1.000 microservice, hơn 8.000 repo git (tháng trước đó là 7.000). Một nửa đội kỹ sư mới vào chưa tới 6 tháng.
  • Bối cảnh kinh doanh: thị trường "người thắng lấy hết", nên phải lớn nhanh.
  • Lịch sử: bản đầu tiên được thuê ngoài viết; dispatch viết bằng Node.js (đang chuyển sang Go); core viết bằng Python (đang chuyển sang Go); Maps và data engineering dùng Python, Java; hệ thống metric dùng Go.

Thay đổi chính (các bài học "ước gì biết sớm")

  • Lý do có nhiều service là con người, không phải kỹ thuật. "Scale traffic không phải vấn đề, scale đội ngũ và tốc độ ra tính năng mới là động lực chính." Microservices thay giao tiếp giữa người bằng phối hợp qua API.
  • Chi phí ít ai thấy:
    • xây service mới thay vì sửa cái hỏng;
    • "đổi độ phức tạp lấy chính trị" (viết thêm code để khỏi phải nói chuyện);
    • mỗi team giữ ngôn ngữ ưa thích, dẫn tới văn hoá bị chia thành các "phe" Node, Go…, khó chia sẻ code, khó chuyển team.
    • Theo bài, Uber ổn định nhất vào cuối tuần, lúc đông khách nhất nhưng ít ai thay đổi gì.
  • RPC: HTTP/REST + JSON không có kiểu gây ra những lỗi kiểu "chuỗi rỗng hay null" khi đi qua vài hop. "Server không phải là trình duyệt": nên coi mỗi lời gọi như một lời gọi hàm có kiểu. Đây cũng là lý do chọn Thrift năm 2015 (Uber 2015).
  • Fan-out: một service p99 = 1 giây, gọi 100 service thì ~63% request chạm ít nhất một lần 1 giây. Cần distributed tracing (Zipkin/OpenTracing, lấy mẫu ~1%) và truyền context xuyên ngôn ngữ (user, xác thực, geo-fence), điều Matt tiếc là không làm sớm.
  • Hiệu năng: "không cần nhanh, nhưng phải biết mình đang ở đâu": mỗi service nên có một SLA hiệu năng, dashboard chuẩn tự sinh, cùng một định dạng flame graph cho mọi ngôn ngữ.
  • Logging: cần log có cấu trúc thống nhất (uber-go/zap), back-pressure trong logging (log quá nhiều làm sự cố tệ hơn), và "tính tiền" theo lượng log để mỗi service biết mình đang tạo ra bao nhiêu.
  • Load test trên production giờ thấp điểm, phải đánh dấu traffic test xuyên suốt hệ thống (lại là truyền context). Lý tưởng: luôn giữ tải gần đỉnh và lùi dần khi traffic thật tăng.
  • Failure testing (kiểu Chaos Monkey) nên là mặc định của production ngay từ đầu, vì thêm vào sau thì gặp kháng cự.
  • Migration: "Mọi thứ đều là legacy, ai cũng đang migrate thứ gì đó". Không còn cửa sổ bảo trì, chỉ còn mức downtime chấp nhận được.
  • "Chỉ dùng củ cà rốt, không dùng cây gậy": đừng ép dùng hệ thống mới; hãy làm công cụ dễ tới mức không ai muốn làm cách khác. Ngoại lệ: bảo mật và tuân thủ.

Vì sao

Theo Matt Ranney: tốc độ tăng trưởng 10 lần trong 1,5 năm buộc phải đánh đổi; điều tiếc nhất là đã không đưa ra các đánh đổi đó một cách có chủ đích.

Bài học cho SWE

Liên quan