Latency và Throughput
Xem thử"Trung bình 590 mili giây" che giấu một sự thật
Nhóm gdev-shop đo 10 request liên tiếp của trang chi tiết sản phẩm. Chín request mất 100 ms, một request mất 5.000 ms (5 giây). Giá trị trung bình là (9 nhân 100 cộng 5.000) chia 10 bằng 590 ms. Con số này không mô tả đúng bất kỳ request nào: chín người thấy trang nhanh (100 ms), một người chờ cả 5 giây.
Hãy dự đoán trước: nếu báo cáo "độ trễ trung bình 590 ms", người đọc sẽ hiểu sai điều gì về trải nghiệm người dùng?
Họ sẽ nghĩ mọi người đều chờ khoảng nửa giây, trong khi thực tế phần lớn rất nhanh và một số ít rất tệ. Muốn nói chính xác về hiệu năng, cần hai khái niệm nền tảng: latency (độ trễ) và throughput (thông lượng), cùng cách đo đúng.
Latency là gì?
Latency (độ trễ) là khoảng thời gian từ lúc gửi một yêu cầu đến lúc nhận được phản hồi (hoặc đến khi một thao tác hoàn thành). Đơn vị thường là mili giây. Đây là điều người dùng cảm nhận trực tiếp: trang tải nhanh hay chậm.
Vì độ trễ thay đổi giữa các request, ta mô tả nó bằng percentile (phân vị) thay vì trung bình:
- P50 (trung vị): một nửa số request nhanh hơn hoặc bằng giá trị này. Mô tả trải nghiệm "điển hình".
- P95, P99: 95% hoặc 99% request nhanh hơn hoặc bằng. Mô tả đuôi chậm (tail latency), tức trải nghiệm của những người gặp tình huống xấu nhất.
Với mẫu 10 request ở đầu bài: P50 bằng 100 ms (một nửa số request nhanh bằng hoặc hơn mức đó), P90 cũng 100 ms, và P99 khoảng 5.000 ms. Chỉ nhìn vào trung bình 590 ms thì bỏ lỡ cả hai điều: phần lớn rất nhanh, và có đuôi rất chậm.
Vì sao đuôi quan trọng: một trang web thường gọi nhiều dịch vụ để hiển thị. Nếu mỗi dịch vụ có 1% request chậm, một trang cần gọi 20 dịch vụ có khoảng 18% khả năng ít nhất một lời gọi rơi vào đuôi chậm (1 trừ 0,99 mũ 20). Đuôi của từng phần cộng dồn thành trải nghiệm tệ của cả trang. Vì vậy nhiều đội đặt mục tiêu theo P95 hoặc P99, như "P99 dưới 300 ms".
Throughput là gì?
Throughput (thông lượng) là lượng công việc hệ thống hoàn thành trong một đơn vị thời gian: số request mỗi giây (RPS hoặc QPS), số giao dịch mỗi giây, hoặc số byte mỗi giây.
| Latency | Throughput | |
|---|---|---|
| Đo | Thời gian cho một yêu cầu | Số yêu cầu hoàn thành mỗi giây |
| Đơn vị | ms | RPS, QPS, MB/s |
| Góc nhìn | Của một người dùng | Của cả hệ thống |
| Ví dụ mục tiêu | P99 dưới 300 ms | Chịu 2.000 RPS |
Một hình ảnh dễ nhớ: một con đường. Latency là thời gian một chiếc xe đi hết đường. Throughput là số xe qua một điểm mỗi phút. Đường rộng hơn (thêm làn) tăng throughput nhưng không làm một xe đi nhanh hơn. Đường ngắn hơn (bớt khoảng cách) giảm latency của từng xe.
Hai chỉ số liên quan nhưng không giống nhau:
- Hệ thống có thể throughput cao mà latency cao: một băng chuyền chạy chậm nhưng dài, nhiều kiện hàng mỗi giờ nhưng mỗi kiện đi lâu.
- Hệ thống có thể latency thấp mà throughput thấp: một người phục vụ cực nhanh nhưng chỉ có một người.
Mối liên hệ định lượng (đã gặp ở lesson về concurrency): số request đang xử lý đồng thời bằng throughput nhân latency. Ví dụ 500 RPS với latency trung bình 0,2 giây thì có khoảng 100 request đồng thời.
Latency đến từ đâu?
Đang tải Animation…
Đang tải Animation…
Đang tải sơ đồ…
Đang tải Animation…
Đang tải Animation…
Cách đọc sơ đồ
Mỗi mũi tên là một đoạn đường mà request phải đi qua, kèm thời gian giả định để minh họa. Tổng độ trễ mà người dùng thấy là tổng các đoạn nối tiếp:
- DNS lookup (khoảng 20 ms): tìm địa chỉ IP, thường được cache nên các lần sau gần như 0.
- TCP và TLS handshake (khoảng 60 ms): thiết lập kết nối an toàn, tốn vài vòng đi về mạng. Có thể tránh bằng cách tái sử dụng kết nối (keep-alive) cho các request sau.
- Mạng đến server (khoảng 20 ms): phụ thuộc khoảng cách địa lý.
- Xử lý ở server: gồm đọc cache (khoảng 2 ms), và nếu miss thì truy vấn database (khoảng 40 ms).
- Truyền response (khoảng 30 ms): phụ thuộc kích thước dữ liệu và băng thông.
Cách dùng sơ đồ này: đây là ngân sách độ trễ (latency budget). Nếu mục tiêu là 300 ms, bạn biết mỗi đoạn được dùng bao nhiêu và đâu là đoạn tốn nhất. Muốn giảm độ trễ, tối ưu đoạn lớn nhất trước: ở đây là TLS handshake (có thể giảm bằng keep-alive), rồi truy vấn database (giảm bằng index hoặc cache). Tối ưu một đoạn chỉ 2 ms không thay đổi gì đáng kể.
Bottleneck ở góc nhìn độ trễ: đoạn nào chiếm phần lớn tổng và đoạn nào có độ biến thiên lớn nhất (ví dụ truy vấn database lúc quá tải).
Quan hệ giữa tải và độ trễ: vì sao độ trễ "nổ" khi gần quá tải
Độ trễ không tăng đều theo tải. Khi tài nguyên được dùng gần hết, các request bắt đầu xếp hàng, và thời gian chờ tăng rất nhanh. Một mô hình hàng đợi đơn giản (một máy phục vụ, request đến ngẫu nhiên) cho kết quả, với mức sử dụng là tỷ lệ năng lực đang dùng:
| Mức sử dụng | Thời gian phản hồi tương đối so với lúc rảnh |
|---|---|
| 50% | khoảng 2 lần |
| 80% | khoảng 5 lần |
| 90% | khoảng 10 lần |
| 95% | khoảng 20 lần |
| 99% | khoảng 100 lần |
Công thức xấp xỉ của mô hình đơn giản này là 1 chia (1 trừ mức sử dụng). Đây là mô hình lý thuyết đơn giản hóa, nhưng bài học thực tế rất rõ: đừng chạy hệ thống ở gần 100% năng lực. Ở 90%, một đợt tăng tải nhỏ làm độ trễ tăng vọt. Vì vậy nhiều đội đặt ngưỡng cảnh báo và mở rộng ở khoảng 60 đến 70% mức sử dụng.
Đánh đổi giữa latency và throughput
Một số kỹ thuật tăng throughput bằng cách thêm độ trễ:
- Gộp (batching): gom nhiều thao tác ghi vào một lần ghi. Throughput tăng vì chi phí cố định chia cho nhiều thao tác, nhưng thao tác đầu tiên phải chờ cho đủ lô, nên độ trễ tăng.
- Hàng đợi sâu: nhận nhiều việc để luôn bận, nhưng mỗi việc phải chờ lâu hơn.
Ngược lại, các kỹ thuật giảm độ trễ có thể tốn throughput hoặc chi phí:
- Cache: giảm độ trễ đọc nhưng thêm bộ nhớ và nguy cơ dữ liệu cũ.
- Dự phòng và gọi song song: giảm độ trễ đuôi bằng cách gửi cùng yêu cầu đến hai nơi, nhưng tốn gấp đôi tài nguyên.
Câu hỏi thiết kế đúng: "đối với tính năng này, người dùng quan tâm nhanh hay nhiều?" Trang thanh toán cần độ trễ thấp và ổn định. Job xuất báo cáo cuối tháng quan tâm throughput hơn.
Những hiểu lầm phổ biến
- "Trung bình là đủ để mô tả độ trễ." Trung bình che giấu đuôi chậm. Hãy dùng P50, P95, P99.
- "Throughput cao nghĩa là latency thấp." Hai chỉ số khác nhau. Hệ thống có thể xử lý nhiều request nhưng mỗi request chậm.
- "Thêm server luôn giảm latency." Thêm server tăng throughput và giảm xếp hàng. Nó không làm một request đơn lẻ chạy nhanh hơn nếu độ trễ nằm ở nơi khác (truy vấn chậm, mạng xa).
- "Chạy ở 95% mức sử dụng là hiệu quả." Hiệu quả về chi phí nhưng độ trễ rất dễ nổ khi có biến động nhỏ.
Must Know, Good to Know, Advanced
- Must Know: định nghĩa latency và throughput; percentile P50, P95, P99 và vì sao không dùng trung bình; ngân sách độ trễ theo từng đoạn; độ trễ tăng vọt khi gần quá tải.
- Good to Know: tail latency và hiệu ứng cộng dồn khi gọi nhiều dịch vụ; đánh đổi batching; tái sử dụng kết nối.
- Advanced: lý thuyết hàng đợi chi tiết, hedged request (gửi dự phòng). Chỉ cần biết rằng có kỹ thuật chuyên sâu để giảm tail latency.
Tự kiểm tra
- Mẫu 10 request: chín request 100 ms, một request 5.000 ms. P50, trung bình và P99 xấp xỉ bao nhiêu? Con số nào mô tả đúng trải nghiệm của đa số?
- Trong ngân sách độ trễ của bài, bạn tối ưu đoạn nào đầu tiên để giảm tổng thời gian nhiều nhất? Vì sao?
- Hệ thống đang ở 90% mức sử dụng CPU và khách phàn nàn chậm thất thường. Vì sao thêm một chút tải đã làm tệ hẳn?
Đáp án gợi ý
- Mẫu gồm chín request 100 ms và một request 5.000 ms. P50 = 100 ms, trung bình = (9 × 100 + 5.000) / 10 = 590 ms, và P99 ≈ 5.000 ms (với mẫu nhỏ này P99 rơi vào request chậm nhất). Con số mô tả trải nghiệm của đa số là P50 (100 ms), còn P99 mô tả nhóm chậm nhất. Trung bình 590 ms không phản ánh trải nghiệm của ai cả.
- Trong ngân sách của bài (DNS 20, TCP và TLS 60, mạng 20, cache 2, truy vấn 40, truyền phản hồi 30 = 172 ms), đoạn lớn nhất là bắt tay TCP và TLS (60 ms). Tối ưu đầu tiên là tái sử dụng kết nối (keep-alive, HTTP/2), TLS session resumption hoặc đặt điểm kết thúc gần người dùng bằng CDN. Tối ưu đoạn lớn nhất giảm được nhiều nhất.
- Ở 90% mức sử dụng, các request đã bắt đầu xếp hàng thường xuyên, nên chỉ cần thêm một chút tải (một đợt tăng ngắn) là hàng đợi dài ra rất nhanh. Quan hệ giữa mức sử dụng và độ trễ là phi tuyến, nên độ trễ tăng vọt khi sát 100%. Cần để dư năng lực và đặt cảnh báo sớm hơn.
Nếu chỉ nhớ 3 điều
- Latency là thời gian một request, throughput là số request mỗi giây; đo latency bằng percentile (P95, P99), không dùng trung bình.
- Tổng latency là tổng các đoạn nối tiếp: lập ngân sách, tối ưu đoạn lớn nhất trước.
- Độ trễ tăng vọt khi mức sử dụng gần 100% vì hàng đợi: để dư năng lực.