The Legends of Runeterra CI/CD Pipeline

Bài tóm tắt Riot Games 2021 2. Tăng trưởng Độ khó: Trung bình

Riot Games · 2021 · 2. Tăng trưởng · Độ khó: Trung bình — bài gốc

Pipeline của một game (client Unity + game server). Wiki giữ phần hạ tầng build/test/deploy, bỏ qua chi tiết riêng của client.

Bối cảnh

  • Legends of Runeterra (2021): monorepo Git LFS khoảng 100 GB, một triệu file, 270k commit, khoảng 700 nhánh; Jenkins với scripted pipeline (logic phức tạp viết bằng Python, Groovy chỉ làm keo). Build farm trên AWS: 100 node Windows, vài node Linux và macOS, một Jenkins chính, 8 node Docker swarm.
  • Khoảng 100 lượt chạy pipeline đầy đủ mỗi ngày, trung bình 60 phút mỗi lượt; phát hành công khai vài tuần một lần.
  • Phần lớn game ở Riot dùng Perforce với trunk-based: commit lỗi chặn mọi người nên vòng lặp chủ yếu ở máy local.

Thay đổi chính

  • Nhánh phân cấp: feature branch → nhánh chung của team → main; trước đây rẽ thẳng từ main thì làm vỡ build main quá thường. Mỗi ngày một job tự merge nhánh cha xuống nhánh con; mỗi release cắt một nhánh.
  • Môi trường test riêng cho từng nhánh thay cho bộ sandbox dùng chung (dễ giẫm chân nhau). Ban đầu mỗi môi trường một game server, nhiều tới mức làm sập cụm dev; nay một game server chứa dữ liệu của nhiều môi trường. Đóng ticket JIRA thì tự xoá nhánh và môi trường.
  • Build plan bằng hash: đầu pipeline băm từng artifact để chỉ build phần đổi (tương tự remote cache của Bazel).
  • Hai loại build: Iteration (một nền tảng, bỏ bước kiểm) để thử nhanh, nhưng commit status vẫn đặt thất bại để nhắc; Merge Readiness (đầy đủ) bắt buộc trước khi merge.
  • Đồng bộ workspace bằng patcher của game: Git LFS trên Windows chậm; đầu pipeline đẩy cả repo (trừ .git) lên patcher phân phối qua CDN; các bước sau đồng bộ từ đó trong 10–15 giây thay vì 1–2 phút, và không lo dội quá tải kho LFS khi nhiều build song song.
  • Test qua HTTP thay vì UI: bản debug có HTTP server để điều khiển game; dùng chung một game server cho nhiều test, chạy game nhanh gấp 10 lần, vài trăm test chức năng trong vài phút.
  • Báo lỗi build: từ đổ stderr, qua plugin regex trên log (nặng server Jenkins, báo nhầm nhiều), tới khai báo lỗi ngay tại chỗ xảy ra trong script build: ghi file JSON metadata, gửi telemetry lên New Relic và Slack (ý tưởng học từ Dropbox).
  • Việc còn treo: pipeline phụ thuộc khoảng 50 dịch vụ; nếu mỗi cái 99% uptime thì pipeline chỉ tin cậy khoảng 0,99^50 ≈ 60% trước cả khi tính lỗi code. Muốn chuyển sang build node tạm thời.

Vì sao

  • Chi phí một build hỏng cao (một giờ, chặn cả team) nên phải đẩy kiểm tra sớm xuống nhánh và cô lập môi trường thử.

Bài học cho SWE

  • Môi trường tạm theo nhánh cần được chia sẻ tài nguyên bên dưới và tự dọn theo vòng đời ticket, không thì chính nó làm sập hạ tầng dev (Nền tảng nội bộ cho service (đường ray chung)).
  • Tách build nhanh để lặp với build đủ để merge, và để hệ thống (không phải kỷ luật) chặn merge khi chưa có build đủ (Deploy và release an toàn).
  • Độ tin cậy của pipeline là tích độ tin cậy các dependency; 50 dịch vụ "99%" cho kết quả tệ.
  • Lỗi nên được khai báo có cấu trúc tại nơi phát sinh, thay vì đoán lại từ log bằng regex.

Liên quan