Skip to content

Bộ 04 · Đo lường và vận hành ​

Metric serving, load test, percentile, SLO và lập kế hoạch năng lực. Bài 01, 06, 08, 15, 16, 20–25, 27, 30, 43. Trả lời thành tiếng mỗi câu trong khoảng một phút, rồi mới xem thẻ.

Q1 · "Request X chậm hơn 4 lần" ưu tiên ​

Bài: 08, 16, 20

Ghi chú

Request X mất 8,3 s end to end với 400 token đầu ra; request Y mất 2,0 s với 85 token. Cả hai đều có TTFT 300 ms và TPOT 20 ms. PM nói X chậm hơn 4 lần. Đúng không, và PM nên so sánh cái gì?

Trả lời trong 60 giây

  • Công thức latency: thời gian end-to-end là phần chờ token đầu tiên cộng một khoảng TPOT cho mỗi token sau đó, nên E2E ≈ TTFT + TPOT × (N − 1). Với X là 0,3 + 399 × 0,02 ≈ 8,3 s, với Y là 0,3 + 84 × 0,02 ≈ 2,0 s, khớp với cả hai phép đo.
  • Vì sao X không chậm hơn: hai request có cùng TTFT và cùng TPOT, nên server đang phục vụ chúng với tốc độ y hệt nhau. X lâu hơn chỉ vì nó viết nhiều token hơn (400 so với 85).
  • PM nên so sánh gì: TTFT, tức người dùng chờ token đầu tiên bao lâu, và TPOT, tức luồng chạy nhanh tới đâu sau đó. Không so E2E giữa các request khác độ dài được, vì câu trả lời dài hơn thì lâu hơn dù cùng tốc độ.
  • Tính ngược TPOT từ E2E: sau token đầu tiên có N − 1 khoảng cách, nên TPOT = (E2E − TTFT) ÷ (N − 1). Đó là lý do chia cho N − 1, không phải N.

Các con số chính: TPOT = (E2E − TTFT) ÷ (N − 1); ví dụ (2,3 − 0,3) s ÷ 400 = 5 ms cho 401 token.

Câu hỏi tiếp theo hay gặp: "TPOT trung bình trông ổn nhưng người dùng nói luồng bị giật?" Trung bình che giấu các khoảng cách không đều, nên tôi sẽ nhìn phân phối của các khoảng cách giữa token (p95, p99, max) thay vào đó. Nguyên nhân thường gặp là prefill dài của các request khác, chen ngang luồng stream.

Mẹo

Tôi đã chia cho N thay vì N − 1, và đổ lỗi cho độ dài hàng đợi về chuyện giật (nó giải thích khởi đầu chậm, không giải thích khoảng cách không đều).

Q2 · Hai công cụ, hai TPOT ưu tiên ​

Bài: 20

Ghi chú

Một load test chạy 50 cuộc chat ngắn (20 token, khoảng cách 50 ms) và 10 câu trả lời dài (1.000 token, khoảng cách 10 ms). Dashboard nói TPOT ≈ 13,5 ms; script của một đồng nghiệp nói ≈ 43 ms. Cái nào đúng cho "người dùng điển hình cảm nhận gì"? Và sau khi bật speculative decoding, một script phía client báo 45 ms mỗi message với 3 token mỗi message.

Trả lời trong 60 giây

  • Theo request (mỗi request một phiếu): lấy khoảng cách của từng request và lấy trung bình trên 60 request: (50 × 50 + 10 × 10) ÷ 60 = 2.600 ÷ 60 ≈ 43 ms. Đây là con số của đồng nghiệp.
  • Theo token (mọi khoảng cách đều tính): một cuộc chat 20 token có 19 khoảng cách và một câu trả lời 1.000 token có 999, nên trung bình là (50 × 19 × 50 + 10 × 999 × 10) ÷ (950 + 9.990) = 147.400 ÷ 10.940 ≈ 13,5 ms. Đây là con số của dashboard, và nó bị 10 câu trả lời dài chi phối vì chúng cung cấp 9.990 trong 10.940 khoảng cách.
  • Cái nào đúng: "người dùng điển hình" nghĩa là theo request, vì 50 trong 60 người dùng cảm nhận khoảng cách 50 ms. Con số theo token phần lớn mô tả 10 câu trả lời dài.
  • Script speculative decoding: speculative decoding gửi token theo cục, nên một message mang nhiều token. Script bấm giờ message, không phải token, nên con số thật là 45 ms ÷ 3 = 15 ms mỗi token.

Các con số chính: TPOT theo token đánh trọng số request dài theo số khoảng cách của chúng.

Câu hỏi tiếp theo hay gặp: "Bạn sẽ đưa cái nào vào SLO?" Percentile theo request, như p99 TPOT theo request, vì như vậy mỗi người dùng được tính một lần bất kể câu trả lời của họ dài bao nhiêu.

Mẹo

Tôi đã trộn số khoảng cách vào phiếu theo request và quên nhân với số request trong tổng theo token.

Q3 · Tốc độ prefill từ một lần quét TTFT ưu tiên ​

Bài: 15, 24

Ghi chú

TTFT một request, max_tokens = 1, trung vị: 256 token → 23 ms, 8.000 token → 280 ms. Mô hình TTFT = chi phí cố định + prompt ÷ throughput. Throughput prefill và chi phí cố định là bao nhiêu, và chi phí cố định gồm những gì?

Trả lời trong 60 giây

  • Throughput là độ dốc: từ 256 lên 8.000 token thêm 7.744 token và 280 − 23 = 257 ms, nên prefill chạy ở 7.744 ÷ 0,257 s ≈ 30 nghìn token/s. Lấy hiệu giữa hai điểm triệt tiêu chi phí cố định.
  • Chi phí cố định là hệ số chặn: ở 30 nghìn token/s, bản thân prompt 256 token mất 256 ÷ 30 nghìn ≈ 8,5 ms, nên phần còn lại trong 23 ms là overhead: 23 − 8,5 ≈ 14,5 ms.
  • Chi phí cố định gồm gì: mọi thứ không tăng theo độ dài prompt, tức HTTP và tokenize, lập lịch, bước decode đầu tiên, và detokenize rồi stream token đầu tiên.

Các con số chính: throughput = Δtoken ÷ ΔTTFT.

Câu hỏi tiếp theo hay gặp: "Sao không chia 256 cho 23 ms?" Vì 23 ms gồm cả 14,5 ms chi phí cố định, nên 256 ÷ 23 ms ≈ 11 nghìn token/s gộp overhead vào tốc độ. Thấp gần 3 lần so với con số thật 30 nghìn.

Mẹo

Tôi đã chia trên một điểm. Hãy dùng hai điểm: độ dốc cho tốc độ, hệ số chặn cho overhead.

Q4 · "Benchmark nói ta ổn mà" ưu tiên ​

Bài: 21, 25

Ghi chú

Một benchmark vòng kín với 32 người dùng đồng thời đo được thời gian trung bình trong hệ thống là 4 s. Lúc ra mắt, người dùng thật đến với 10 req/s. Chuyện gì xảy ra? Lẽ ra bạn nên chạy load test nào, và vì sao một bộ tạo tải biết chờ có thể che giấu một lần khựng 3 s?

Trả lời trong 60 giây

  • Chuyện gì xảy ra lúc ra mắt: theo định luật Little, throughput = số request đang xử lý ÷ thời gian trong hệ thống, nên server hoàn thành 32 ÷ 4 s = 8 req/s. Người dùng thật đến với 10 req/s, nên hàng đợi tăng 10 − 8 = 2 req/s, tức 120 request đang chờ sau một phút, và cứ tăng không giới hạn.
  • Vì sao benchmark trông ổn: một vòng kín chỉ gửi request mới khi request cũ xong, nên khi server chậm lại, tốc độ đến của nó cũng chậm lại. Đó là lý do nó không bao giờ cho thấy quá tải.
  • Nên chạy test nào: để tìm throughput tối đa, chạy quét concurrency vòng kín. Để thấy latency dưới lưu lượng lúc ra mắt, chạy test vòng hở với request đến kiểu Poisson ở 10 req/s, vì người dùng thật không chờ nhau.
  • Client biết chờ che giấu lần khựng thế nào (coordinated omission): lấy một test lên lịch 5 req/s trong 60 s, tức 300 request. Một client chờ từng response chỉ gửi ≈ 1 request trong lần khựng 3 s thay vì 15 request theo lịch, nên p99 không bao giờ thấy lần khựng. Một client gửi đúng lịch ghi được cả 15 request chậm trên 300, tức 5%, cao hơn 1% khá nhiều, nên p99 rơi vào trong lần khựng ở ≈ 2,6 s.

Các con số chính: L = λ × W; tốc độ tăng hàng đợi = số đến − số hoàn thành.

Câu hỏi tiếp theo hay gặp: "Lưu lượng tăng 30% trên một server đang bận 70%?" Utilization thành ρ = 0,7 × 1,3 = 0,91. Thời gian trong hệ thống tỷ lệ với 1 ÷ (1 − ρ), đi từ 1 ÷ 0,3 ≈ 3,3 lên 1 ÷ 0,09 ≈ 11,1, nên request mất lâu hơn 11,1 ÷ 3,3 ≈ 3,3 lần. Đó là lý do gần bão hoà, một chút lưu lượng tăng thêm làm latency bùng nổ.

Mẹo

Tôi đã giải thích vì sao test bỏ sót nhưng không nói chuyện gì xảy ra (hãy tính tốc độ tăng). Để tìm throughput tối đa, quét concurrency, không quét request rate.

Q5 · Các cái bẫy của percentile ưu tiên ​

Bài: 06, 22

Ghi chú

Ba dashboard: P99 TTFT tăng gấp đôi từ 0,8 lên 1,5 s mà không có deploy nào và thời gian theo từng request không đổi; đội vận hành lấy trung bình P99 của bốn replica (0,6; 0,7; 0,6; 3,0 s) thành "P99 của fleet = 1,2 s"; và một agent thực hiện 20 lời gọi tuần tự tới một API có P99 = 2 s. Mỗi cái sai ở đâu?

Trả lời trong 60 giây

  • Dashboard thứ nhất, dịch chuyển cơ cấu: nếu có nhiều prompt dài đến hơn, P99 TTFT trộn chung tăng lên dù không request nào chậm đi, vì độ dài prompt quyết định TTFT. Để kiểm tra, hãy phân nhóm theo độ dài prompt và so latency cùng tỷ trọng lưu lượng của từng nhóm.
  • Dashboard thứ hai, percentile không lấy trung bình được: phải gộp histogram của các replica trước rồi mới lấy percentile. Với bốn replica, 1% chậm nhất của fleet là ≈ 4% request của replica tệ, tức P96 của nó. Con số đó nhiều khả năng ≈ 2 s, nên P99 thật của fleet cao hơn 1,2 s khá nhiều.
  • Dashboard thứ ba, phần đuôi cộng dồn: mỗi lời gọi có 1% khả năng chậm, nên khả năng ít nhất một trong 20 lời gọi chậm là 1 − 0,99²⁰ ≈ 18% số tác vụ. Để chỉ 1% số tác vụ bị chậm, mỗi lời gọi cần đạt khoảng P99.95, vì 20 × 0,05% ≈ 1%.

Các con số chính: 1 − (1 − q)ᵏ ≈ k × q với q nhỏ.

Câu hỏi tiếp theo hay gặp: "Một P99 cần bao nhiêu mẫu?" Bạn muốn khoảng 100 mẫu nằm ngoài percentile để có độ chính xác ≈ 10%. Chỉ 1% số mẫu nằm ngoài P99, nên cần khoảng 100 ÷ 0,01 ≈ 10.000 mẫu.

Mẹo

Tôi đã nói "tải tăng" (thứ đó sẽ hiện thành xếp hàng) và đổ lỗi độ dài câu trả lời cho TTFT (độ dài prompt mới quyết định TTFT). Với agent, tôi đã đọc "1%" là theo tác vụ.

Q6 · Speedup 3,5% có thật không? ưu tiên ​

Bài: 06

Ghi chú

Trước: 5 lần chạy với TPOT trung bình 20,0 ms. Sau một tinh chỉnh: 5 lần chạy trung bình 19,3 ms. Mỗi lần chạy dao động σ ≈ 0,8 ms. Một đồng nghiệp nói "nhanh hơn 3,5%, ship thôi."

Trả lời trong 60 giây

  • Nhiễu trên một trung bình: một lần chạy dao động σ = 0,8 ms, và lấy trung bình n lần làm nó co lại còn σ ÷ √n, nên mỗi trung bình 5 lần dao động 0,8 ÷ √5 ≈ 0,36 ms.
  • Nhiễu trên hiệu số: so hai trung bình là gộp nhiễu của cả hai, làm nó lớn hơn √2 lần: 0,36 × √2 ≈ 0,51 ms. Dải 95% khoảng 2 lần con số đó, nên ≈ ±1,0 ms.
  • Kết luận: khoảng chênh đo được là 20,0 − 19,3 = 0,7 ms, nằm trong dải nhiễu ±1,0 ms, nên speedup chưa được chứng minh.
  • Chứng minh thế nào: dải 2 × 0,8 × √2 ÷ √n phải co về 0,7 ms hoặc nhỏ hơn, cần n ≈ 11+ lần chạy mỗi bên. Lựa chọn khác là ghép cặp các lần chạy để phần nhiễu chung triệt tiêu nhau.

Các con số chính: dải 95% trên một hiệu số ≈ ±2 × √2 × σ ÷ √n.

Câu hỏi tiếp theo hay gặp: "Cùng ý tưởng cho chất lượng model?" Đúng. So hai model theo từng câu hỏi (so sánh theo cặp), như trong bộ về lượng tử hoá, để phần nhiễu chung triệt tiêu giống như khi ghép cặp các lần chạy.

Mẹo

Tôi không có mô hình tư duy để bắt đầu: σ, rồi σ ÷ √n, rồi × √2 cho một hiệu số, rồi một khoảng chênh vượt quá ≈ 2 lần mức đó.

Q7 · Goodput và điểm vận hành ưu tiên ​

Bài: 23, 25, 27, 43

Ghi chú

SLO: TTFT < 500 ms và TPOT < 30 ms. Ở 6 req/s, 5% thất bại với 429; trong số thành công, 90% đạt TTFT và 85% đạt TPOT. Goodput là bao nhiêu? Và một lần quét đạt đỉnh 5.000 token/s, nhưng mọi người dùng phải nhận ít nhất 100 token/s ở P99. Bạn ghi gì vào tài liệu năng lực?

Trả lời trong 60 giây

  • Goodput: chỉ những request được nhận và đạt cả hai SLO mới tính, nên goodput = 6 × 0,95 × 0,90 × 0,85 ≈ 4,4 req/s. Chỉ bằng 73% con số 6 req/s mà dashboard hiển thị.
  • Đổi mức sàn người dùng thành giới hạn latency: 100 token/s mỗi người dùng nghĩa là mỗi token mất tối đa 1 ÷ 100 s = 10 ms, nên P99 TPOT phải giữ ≤ 10 ms. Trong lần quét, chọn concurrency cao nhất vẫn đạt giới hạn đó (32 người dùng, ≈ 3.400 token/s), không bao giờ chọn đỉnh 5.000 token/s, vì đỉnh không đạt SLO.
  • Ghi gì vào tài liệu năng lực: năng lực = min(bức tường bão hoà, bức tường SLO, bức tường bộ nhớ), vì bức tường nào chạm trước là giới hạn thật.
  • Vì sao cấu hình nhanh nhất có thể thua: bước lớn làm vỡ TPOT trước, và giới hạn nhận request thấp làm vỡ TTFT trước, nên tốc độ thô không quyết định. Hãy chọn cấu hình theo throughput an toàn theo SLO.

Các con số chính: goodput = rate × tỷ lệ thành công × tích các tỷ lệ đạt SLO.

Câu hỏi tiếp theo hay gặp: "Bức tường bộ nhớ là gì?" Đó là dung lượng token của pool KV chia cho số token mỗi request giữ khi nó kết thúc, cho ra bao nhiêu request vừa cùng lúc. Với đầu ra agent dài, nó thường là bức tường ràng buộc, vì mỗi request cuối cùng giữ rất nhiều token.

Mẹo

Tôi đã chọn điểm "gần nhất" với mục tiêu và nghiêng về phía đỉnh. "Ít nhất" nghĩa là điểm ngoài cùng bên phải vẫn còn đạt.

Q8 · "40 ÷ 8 = 5 GPU" ưu tiên ​

Bài: 43

Ghi chú

Phút bận nhất trung bình 40 req/s và một H100 giữ được SLO tới 8 req/s. Quản lý nói 5 GPU. Với biên 20% cho đợt dồn và phải sống sót khi một replica hỏng, cần bao nhiêu? Và khi lưu lượng vượt kế hoạch, có nên nâng max_num_seqs từ mức đã test 128 lên 512 không?

Trả lời trong 60 giây

  • Năng lực dùng được mỗi GPU: biên 20% cho đợt dồn nghĩa là chạy mỗi GPU ở 80% giới hạn SLO của nó, nên mỗi cái xử lý 8 × 0,8 = 6,4 req/s.
  • Số GPU cho tải: 40 ÷ 6,4 = 6,25, và không chạy được một phần tư GPU, nên 7 GPU phục vụ được phút bận nhất.
  • Sống sót khi hỏng: nếu một replica chết, N − 1 cái còn lại vẫn phải ít nhất là 7, nên N − 1 ≥ 7 cho 8 GPU, không phải 5 như quản lý nói.
  • Đừng nâng max_num_seqs lên 512: nhồi nhiều sequence hơn mức đã test 128 làm người dùng đang stream chậm đi, và preemption bắt đầu.
  • Làm gì thay vào đó: bảo vệ điểm vận hành đã test. Giữ giới hạn ở 128, timeout hoặc từ chối phần hàng đợi dư bằng 429, và autoscale sớm để năng lực mới tới trước khi hàng đợi dồn lên.

Các con số chính: N − 1 ≥ đỉnh ÷ (năng lực SLO mỗi GPU × (1 − biên)).

Câu hỏi tiếp theo hay gặp: "Sao không dùng VTC khi quá tải?" VTC cân bằng việc phục vụ giữa các tenant, nhưng nó không cắt bớt tải, nên server vẫn quá tải.

Mẹo

Tôi đã trả lời "N + 2" theo trí nhớ thay vì giải bất phương trình.

Q9 · Có nên gọi người trực không? ưu tiên ​

Bài: 23

Ghi chú

SLO: 99,5% tốt trong 30 ngày, khoảng 2 triệu request mỗi tháng. Trong giờ vừa qua 3% request là xấu. Error budget lớn bao nhiêu, burn rate là bao nhiêu, và bao lâu nữa thì cạn?

Trả lời trong 60 giây

  • Error budget: SLO cho phép 100% − 99,5% = 0,5% request xấu, và 0,5% × 2 triệu = 10.000 request xấu mỗi tháng.
  • Burn rate: giờ vừa qua có 3% xấu so với mức cho phép 0,5%, nên budget đang cháy nhanh hơn kế hoạch 3% ÷ 0,5% = 6 lần.
  • Thời gian còn lại: ở 1 lần, budget kéo dài đúng 30 ngày, nên ở 6 lần nó kéo dài 30 ÷ 6 = 5 ngày. Đó là cháy nhanh, nên có, hãy gọi người trực.

Các con số chính: số ngày còn lại = 30 ÷ burn rate.

Câu hỏi tiếp theo hay gặp: "Làm sao tránh gọi người trực vì những lần chập chờn?" Cảnh báo theo burn rate trên hai cửa sổ, như 1 giờ và 5 phút, và chỉ gọi khi cả hai đều cao. Một lần chập chờn ngắn làm cửa sổ 5 phút vọt lên nhưng cửa sổ một giờ thì không, nên không gọi.

Mẹo

Tôi đã chia 6 cho 30. Kiểm tra nhanh: ở 1 lần budget kéo dài đúng 30 ngày, nên cháy nhanh hơn thì còn ít ngày hơn.

Q10 · Autoscale theo nhầm tín hiệu ưu tiên ​

Bài: 01, 30

Ghi chú

Một autoscaler thêm replica khi CPU vượt 70%. Trong một đợt tăng đột ngột, người dùng chờ hơn 5 s mới thấy token đầu tiên nhưng CPU chỉ 12%, nên không có gì được scale. Nó nên theo dõi cái gì, và một replica mới mất bao lâu với 16 GB trọng số ở 2 GB/s?

Trả lời trong 60 giây

  • Vì sao CPU là tín hiệu sai: trong serving trên GPU, CPU gần như rảnh, nên nó vẫn ở 12% kể cả khi người dùng chờ 5 s. Bộ nhớ GPU cũng không được, vì pool KV được cấp phát trước, nên nó luôn đọc ≈ 90%.
  • Nên theo dõi gì: scale theo tín hiệu của engine, tức số request đang chờ (hàng đợi tăng), mức dùng KV cache, và TTFT. Những thứ này nhúc nhích khi người dùng thực sự bắt đầu phải chờ.
  • Khởi động lạnh: replica mới phải nạp 16 GB trọng số ở 2 GB/s, nên mất ít nhất 16 GB ÷ 2 GB/s = 8 s, cộng thời gian khởi động engine như CUDA graph và warm-up.
  • Điều đó có nghĩa là gì: vì năng lực mới đến muộn vài giây, hãy kích hoạt sớm và giữ sẵn một warm pool. Bạn cũng có thể rút ngắn việc nạp bằng bộ lưu trữ nhanh hơn hoặc nạp ít byte hơn, như trọng số đã lượng tử hoá.

Các con số chính: khởi động lạnh ≥ byte trọng số ÷ băng thông nạp.

Câu hỏi tiếp theo hay gặp: "Nếu chỉ chọn một metric thì bạn chọn gì?" num_requests_waiting, vì nó tăng trước latency, cho autoscaler một bước chạy đà.

Mẹo

Lúc đầu tôi nói utilization bộ nhớ GPU, thứ không bao giờ nhúc nhích vì đã cấp phát trước.

Tự xây ​

  • exercises/06_08_09_tail_sim.py: mô phỏng ước lượng P99 dao động bao nhiêu theo cỡ mẫu, và vét cạn con số 18% của agent 20 lời gọi. Chạy uv run exercises/06_08_09_tail_sim.py.
  • exercises/24_27_find_walls.py: tìm bức tường bão hoà, SLO và bộ nhớ từ một lần quét concurrency và trả về năng lực ràng buộc. Chạy uv run exercises/24_27_find_walls.py.