Scalability and Load Testing for VALORANT
Bài tóm tắt Riot Games 2020 3. Quy mô lớn Độ khó: Trung bình
Riot Games · 2020 · 3. Quy mô lớn · Độ khó: Trung bình — bài gốc
Bối cảnh
- Nền tảng của VALORANT (ngoài game server) là hơn 30 microservice Go: party, matchmaking, chọn Agent, cấp trận về datacenter theo ping, lưu kết quả, store, loadout. Microservice từ đầu là bài học từ League of Legends, vốn khởi đầu là monolith (một bug kéo sập cả nền tảng, không scale riêng được).
- Lúc vào production, game mới được thử với khoảng 100 người cùng lúc; mục tiêu đặt ra là 2 triệu người đồng thời mỗi shard, dựa trên số liệu League và kế hoạch mở nhiều region.
- Test từng service không đủ vì một thao tác của người chơi kéo theo chuỗi gọi nhiều service.
Thay đổi chính
- Harness giả lập người chơi bằng Go, không chạy client thật (2 triệu process quá nặng, và không muốn nhồi code test vào client): simulated player chạy đúng các vòng polling nền của client (làm mới token, cấu hình động); scenario là chuỗi thao tác (vào hàng chờ → chọn Agent → vào game; mua đồ; đổi skin); player pool tạo người chơi theo tốc độ đăng nhập và giao scenario theo tần suất ước từ dữ liệu League.
- Một harness 4 CPU giả lập được 10.000 người; 200 container trên Riot Container Engine (Mesos + Docker trên EC2) cho 2 triệu.
- Game server giả: chỉ mô phỏng bước cấp trận và ghi kết quả, hơn 500 trận trên một core, thay vì hàng nghìn CPU cho game server thật (game server có bài load test riêng).
- Gấp đôi từng bước: bắt đầu 1.000 người, sửa mọi vấn đề, rồi nhân đôi; một test chỉ "qua" khi mọi metric (New Relic, Grafana, alert về Slack) nằm trong ngưỡng suốt thời gian chạy (test 2 triệu người kéo dài 3 giờ).
- Các thay đổi kiến trúc mà load test đòi hỏi:
- Scale DB theo chiều ngang hai lớp: mỗi service sở hữu phần dữ liệu riêng (đánh đổi: mất transaction nguyên tử giữa các phần, phải dùng ledger cho thao tác dở dang, idempotency để retry, trạng thái khoá trung gian); rồi trong mỗi service chia người chơi vào 64 bảng theo hash ID ngay từ đầu, để thêm DB chỉ là dời bảng (2 DB × 32 bảng → 4 DB × 16 bảng).
- Việc nền không gắn với request (ví dụ đánh dấu offline khi mất heartbeat): chia người chơi thành 256 phần theo hash, danh sách lưu trong Redis; instance khởi động thì nhận phần, instance mới "giành" bớt phần cho tới khi chia đều, để mỗi người chơi được xử lý đúng một lần.
- Cache ở response handler, ở phía gọi service khác, và tuỳ chọn ở edge (Cloudflare, nginx); thực tế hầu như chỉ cần cache trong app, nên logic xoá cache đơn giản hơn.
Vì sao
- Lần test 2 triệu người đầu tiên thành công khi còn chưa tới hai tuần trước ngày ra mắt; shard thật được scale theo đúng cấu hình đạt được trong test, và ngày ra mắt (6/2020) chỉ có một lỗi nhỏ ở party/matchmaking.
- Theo Riot, giá trị lớn nhất của load test và dashboard là để mọi feature team tự ra quyết định về hiệu năng service của mình.
Bài học cho SWE
- Giả lập ở đúng ranh giới cần kiểm (request lên nền tảng), thay phần đắt và đã được kiểm riêng (render, gameplay) bằng bản giả nhẹ.
- Chia trước thành nhiều phần nhỏ hơn số máy (64 bảng, 256 phần) để scale sau này chỉ là dời phần, không phải chia lại dữ liệu.
- Tăng tải theo bậc gấp đôi, sửa hết vấn đề ở mỗi bậc rồi mới lên tiếp.
Liên quan
- Riot Games 2015 · Riot Games 2019 (cùng hướng chuẩn bị ra mắt, bằng tiêm lỗi) · Dream11 2021
- Load test và kiểm chứng capacity · Sharding và tách database
#Load testing#Go#Simulated player#Mock game server#Horizontal scaling#Sharding#64 tables#Redis#Caching#Microservices
Được nhắc tới trong
Công ty (1)
Bài tóm tắt (2)