Chương 51. Metrics

Chương trước nói về logging.

Log giúp ta điều tra một chuyện cụ thể:

Job này đã đi qua những bước nào?
Request này lỗi vì sao?
User này gặp vấn đề ở đâu?

Chương này nói về metrics.

Metrics không kể câu chuyện chi tiết của một request hay một job.

Metrics trả lời câu hỏi khác:

Toàn hệ thống đang thế nào theo thời gian?

Ví dụ:

Mỗi phút có bao nhiêu submission?
API chậm đến mức nào?
Bao nhiêu job đang chờ?
Worker xử lý được bao nhiêu bài/phút?
Gemini timeout tăng hay giảm?
Database connection có gần đầy không?
Chi phí AI hôm nay tăng bất thường không?

Thông điệp chính của chương:

> Log giúp điều tra từng sự kiện. Metrics giúp nhìn xu hướng và sức khỏe hệ thống. Nếu log là nhật ký điều tra, metrics là bảng đồng hồ đo nhịp tim, tốc độ, nhiệt độ và mức tải.

---

51.1. Một tình huống: "hôm nay chấm bài chậm hơn mọi ngày"

Teacher nói:

Hôm nay hệ thống chấm bài chậm hơn hẳn.

Nếu chỉ có log, bạn có thể mở vài job cụ thể.

Ví dụ:

job_123 gọi AI mất 90 giây.
job_124 gọi AI mất 87 giây.
job_125 retry một lần.

Nhưng bạn vẫn chưa biết toàn cảnh:

Có phải mọi job đều chậm?
Hay chỉ một vài job?
Queue có đang backlog không?
Worker có ít hơn mọi ngày không?
AI provider có timeout tăng không?
Database có đang nghẽn không?
Số submission hôm nay có tăng gấp 5 không?

Metrics trả lời những câu hỏi này.

Ví dụ dashboard cho thấy:

Submission rate tăng 4 lần lúc 22:00.
Queue oldest job age tăng từ 30 giây lên 18 phút.
Worker active chỉ còn 3 thay vì 12.
AI timeout không tăng.
Database bình thường.

Bây giờ ta biết vấn đề chính:

Không phải AI chậm.
Không phải database chậm.
Worker capacity không đủ so với lượng job.

Đó là sức mạnh của metrics.

---

51.2. Metrics là gì?

Metric là một con số được ghi lại theo thời gian.

Ví dụ:

api_requests_total = 123456
api_request_duration_ms = ...
queue_length = 850
worker_active_count = 12
grading_jobs_failed_total = 42
database_connections = 80

Một metric riêng lẻ chưa đủ.

Điều quan trọng là nó thay đổi theo thời gian.

Ví dụ:

queue_length lúc 10:00 = 100
queue_length lúc 10:10 = 1.000
queue_length lúc 10:20 = 10.000

Đây là câu chuyện:

Queue đang phình ra.

Metrics giúp nhìn xu hướng, không chỉ nhìn một khoảnh khắc.

---

51.3. Metrics khác logs như thế nào?

Log:

Job job_789 failed because AI timeout.

Metric:

ai_timeout_count tăng từ 2/phút lên 80/phút.

Log giúp trả lời:

Job cụ thể này bị gì?

Metric giúp trả lời:

Vấn đề này có đang lan rộng không?

Khi incident xảy ra, bạn thường dùng metrics trước để định vị vùng cháy:

API lỗi tăng?
Queue tăng?
Database connection đầy?
AI timeout tăng?

Sau đó dùng logs để điều tra case cụ thể.

Hai thứ không thay nhau.

Chúng là hai góc nhìn khác nhau.

---

51.4. Ba loại metric căn bản

Rất nhiều hệ thống metrics xoay quanh ba loại:

Counter.
Gauge.
Histogram.

Đừng học thuộc khô.

Hãy nhớ bằng ba câu hỏi:

Counter:
  Từ trước đến giờ đã xảy ra bao nhiêu lần?

Gauge:
  Hiện tại đang là bao nhiêu?

Histogram:
  Các giá trị phân bố như thế nào?

Ví dụ AI Judge:

Counter:
  grading_jobs_completed_total

Gauge:
  queue_length

Histogram:
  grading_duration_seconds

Ba loại này đủ để mô tả rất nhiều chuyện.

---

51.5. Counter

Counter là số chỉ tăng.

Ví dụ:

api_requests_total
grading_jobs_completed_total
grading_jobs_failed_total
ai_requests_total
ai_timeouts_total

Counter thường dùng để tính rate.

Ví dụ:

api_requests_total tăng thêm 6.000 trong 5 phút
=> khoảng 1.200 request/phút

Nếu chỉ nhìn counter tuyệt đối:

api_requests_total = 10.000.000

không hữu ích lắm.

Nhưng nhìn tốc độ tăng:

requests per second
requests per minute
errors per minute

rất hữu ích.

Counter dùng cho việc "đã xảy ra bao nhiêu lần".

---

51.6. Gauge

Gauge là số có thể tăng hoặc giảm.

Nó mô tả trạng thái hiện tại.

Ví dụ:

queue_length
worker_active_count
database_connections
memory_usage
cpu_usage
disk_usage
in_progress_jobs

Queue length là gauge vì:

Job đến -> tăng.
Worker xử lý xong -> giảm.

Database connections cũng vậy:

Request mở connection -> tăng.
Connection trả về pool -> giảm.

Gauge trả lời:

Bây giờ đang là bao nhiêu?

Nhưng phải nhìn theo thời gian.

queue_length = 1.000 có thể không xấu nếu vài giây sau giảm.

Nhưng nếu nó tăng liên tục, đó là vấn đề.

---

51.7. Histogram

Histogram dùng để đo phân bố giá trị.

Thường dùng cho:

  • Request duration.
  • Job processing time.
  • Query duration.
  • File upload size.
  • AI API latency.

Ví dụ:

api_request_duration_seconds
grading_duration_seconds
database_query_duration_seconds

Vì sao không chỉ dùng average?

Vì average có thể che giấu user bị chậm.

Ví dụ 10 request:

9 request mất 100ms.
1 request mất 10s.

Average khoảng 1.09s.

Nhìn average, ta thấy "cũng được".

Nhưng một user đã chờ 10 giây.

Histogram giúp tính percentile như p95, p99 để thấy phần đuôi chậm.

---

51.8. p50, p95, p99 là gì?

p50 nghĩa là 50% request nhanh hơn hoặc bằng giá trị đó.

p95 nghĩa là 95% request nhanh hơn hoặc bằng giá trị đó.

p99 nghĩa là 99% request nhanh hơn hoặc bằng giá trị đó.

Ví dụ:

p50 latency = 120ms
p95 latency = 900ms
p99 latency = 4s

Diễn giải:

Một nửa request khá nhanh.
Nhưng 5% request chậm đến gần 1 giây hoặc hơn.
1% request rất chậm, khoảng 4 giây.

p50 cho biết trải nghiệm bình thường.

p95/p99 cho biết trải nghiệm của nhóm user xấu hơn.

Production phải nhìn phần đuôi.

Vì user phàn nàn thường nằm ở phần đuôi.

---

51.9. Average dễ đánh lừa

Average vẫn có ích.

Nhưng nếu chỉ nhìn average, bạn dễ bị lừa.

Ví dụ:

100 request.
95 request mất 100ms.
5 request mất 10s.

Average khoảng 595ms.

Nghe không quá tệ.

Nhưng 5 user đã chờ 10 giây.

Nếu endpoint là:

Nộp bài.

5 user đó có thể bấm retry, tạo thêm tải và lỗi.

p95/p99 giúp thấy đuôi latency.

Khi nói về performance, hãy hỏi:

p95 thế nào?
p99 thế nào?

Không chỉ average.

---

51.10. Latency

Latency là thời gian để xử lý một việc.

Ví dụ:

API request latency.
Database query latency.
AI provider latency.
Job processing latency.
Queue wait latency.

Với AI Judge, cần phân biệt:

API latency:
  POST /submissions mất bao lâu?

Queue wait:
  job chờ bao lâu trước khi worker nhận?

Processing latency:
  worker xử lý job bao lâu?

End-to-end latency:
  từ lúc student nộp đến lúc có điểm mất bao lâu?

Nếu chỉ đo API latency, bạn có thể thấy:

POST /submissions = 200ms

nhưng user vẫn chờ điểm 20 phút.

Vì phần chậm nằm ở queue/worker, không nằm ở API request.

---

51.11. Traffic

Traffic là lượng việc đi qua hệ thống.

Ví dụ:

requests per second
submissions per minute
grading jobs per minute
file uploads per hour
AI requests per minute

Traffic giúp hiểu tải.

Nếu latency tăng, câu hỏi đầu tiên:

Traffic có tăng không?

Nếu traffic tăng 10 lần, hệ thống chậm là dễ hiểu.

Nếu traffic không tăng mà latency tăng, có thể có:

  • Deploy mới.
  • Query chậm.
  • Dependency lỗi.
  • Database lock.
  • External API chậm.
  • Resource leak.

Traffic là nền để diễn giải các metric khác.

---

51.12. Errors

Error metrics cho biết hệ thống đang thất bại bao nhiêu.

Ví dụ:

http_5xx_total
http_4xx_total
grading_jobs_failed_total
ai_timeouts_total
payment_webhook_failed_total
file_upload_failed_total

Không phải mọi 4xx là lỗi hệ thống.

Ví dụ:

401/403 có thể là user chưa đăng nhập hoặc không có quyền.
404 có thể bình thường.

Nhưng 4xx tăng đột biến cũng đáng xem.

5xx thường nghiêm trọng hơn vì là lỗi phía server.

Với worker, job failed rate rất quan trọng.

Nếu job fail tăng, user chịu ảnh hưởng dù API vẫn 200.

---

51.13. Saturation

Saturation là mức độ tài nguyên đang bị dùng gần hết.

Ví dụ:

  • CPU gần 100%.
  • Memory gần hết.
  • Disk gần đầy.
  • Database connection pool gần max.
  • Queue backlog lớn.
  • Thread pool đầy.
  • Worker concurrency hết.
  • Rate limit gần chạm.

Saturation trả lời:

Hệ thống còn dư sức không?

Một hệ thống có latency bình thường nhưng saturation tăng dần có thể sắp gặp vấn đề.

Ví dụ:

Database connection usage = 95%

Hiện tại request vẫn chạy.

Nhưng chỉ cần traffic tăng nhẹ là lỗi.

---

51.14. Bốn câu hỏi vàng cho service

Với một service, hãy hỏi:

1. Có bao nhiêu request/job?
2. Mất bao lâu?
3. Lỗi bao nhiêu?
4. Có gần hết tài nguyên không?

Đó chính là:

  • Traffic.
  • Latency.
  • Errors.
  • Saturation.

Nếu chỉ bắt đầu với bốn nhóm này, bạn đã hơn rất nhiều hệ thống mù.

Sau đó mới thêm metric chuyên biệt cho domain.

---

51.15. Metrics cho web server

Với web/API server, nên đo:

request_count theo endpoint/status
request_duration theo endpoint
5xx_rate
4xx_rate
in_flight_requests
request_body_size nếu cần
response_size nếu cần

Ví dụ:

GET /teacher/dashboard p95 = 3.2s
POST /submissions p95 = 250ms
GET /results/{id} 5xx tăng sau deploy

Endpoint-level metrics rất hữu ích.

Nếu chỉ đo toàn bộ app:

api p95 = 800ms

ta chưa biết endpoint nào chậm.

Nhưng cũng đừng đưa raw user_id/request_id vào label metric.

Endpoint pattern là tốt:

/submissions/{id}

Không phải:

/submissions/sub_123

---

51.16. Metrics cho database

Database nên có metric:

connection_count
connection_pool_wait
query_duration
slow_query_count
lock_wait
deadlock_count
cpu
memory
disk
iops
replication_lag nếu có replica

Nhưng chỉ có database CPU không đủ.

Ví dụ:

CPU 40% nhưng request chậm.

Có thể do lock wait hoặc connection pool wait.

Hoặc:

DB khỏe nhưng app mở quá nhiều connection.

Metrics phải giúp nhìn đúng tầng.

Database là nơi cần theo dõi nghiêm túc vì rất nhiều bottleneck tụ ở đó.

---

51.17. Metrics cho queue

Queue metrics cực kỳ quan trọng với hệ thống có job nền.

Các metric nên có:

queue_length
oldest_job_age
jobs_enqueued_total
jobs_started_total
jobs_completed_total
jobs_failed_total
jobs_retried_total
dead_letter_count

Trong đó oldest_job_age thường rất quan trọng.

Vì queue length cao chưa chắc luôn xấu nếu worker xử lý rất nhanh.

Nhưng nếu job cũ nhất đã chờ 20 phút, user thật đang chờ.

Với AI Judge:

oldest grading job age

là metric sống còn.

Nó gần với trải nghiệm user hơn queue length đơn thuần.

---

51.18. Metrics cho worker

Worker metrics nên trả lời:

Có bao nhiêu worker đang sống?
Đang xử lý bao nhiêu job?
Mỗi job mất bao lâu?
Fail vì lý do gì?
Retry có tăng không?

Ví dụ:

worker_active_count
worker_concurrency
job_processing_duration
job_success_rate
job_failure_reason_count
job_retry_count

Nếu queue backlog tăng nhưng worker_active_count giảm, có thể worker chết.

Nếu worker_active_count bình thường nhưng job_processing_duration tăng, có thể dependency chậm.

Nếu retry tăng mạnh, có thể external API hoặc bug logic.

Metrics giúp phân biệt các tình huống này.

---

51.19. Metrics cho AI provider

Với AI Judge, AI provider metrics rất quan trọng.

Nên đo:

ai_requests_total
ai_request_duration
ai_timeout_total
ai_rate_limit_total
ai_error_total
ai_input_tokens_total
ai_output_tokens_total
ai_cost_usd_total

Nếu AI timeout tăng, worker chậm là dễ hiểu.

Nếu AI cost tăng sau deploy nhưng số job không tăng, có thể prompt mới tốn token hơn.

Nếu rate limit tăng, cần xem concurrency/retry/quota.

AI provider không phải hộp đen.

Bạn cần đo cách mình dùng nó.

---

51.20. Metrics cho file/storage

File cũng cần metrics:

file_upload_started_total
file_upload_completed_total
file_upload_failed_total
file_processing_duration
storage_used_bytes
signed_url_created_total
download_failed_total

Nếu user báo upload lỗi, metrics có thể cho biết:

Upload failure tăng từ 1% lên 20%.

Nếu storage cost tăng, metric storage usage giúp phát hiện:

Cleanup job chết.
File tạm không bị xóa.
Export report tăng bất thường.

File storage không nên bị bỏ khỏi observability.

---

51.21. Domain metrics

Ngoài metric kỹ thuật, cần metric gần nghiệp vụ.

Với AI Judge:

submissions_created_total
grading_completed_total
grading_failed_total
time_to_grade_seconds
teacher_score_override_total
regrade_requested_total

Metric domain giúp hiểu hệ thống từ góc người dùng.

Ví dụ:

API khỏe.
Database khỏe.
Nhưng grading_completed_total giảm mạnh.

Có gì đó sai ở pipeline chấm bài.

Metric kỹ thuật nói hệ thống máy móc.

Metric domain nói sản phẩm có đang hoàn thành việc chính không.

---

51.22. SLI ở mức khái niệm

SLI là Service Level Indicator.

Nói dễ hiểu:

Một chỉ số thể hiện chất lượng dịch vụ người dùng nhận được.

Ví dụ:

Tỉ lệ request thành công.
p95 latency của API.
Tỉ lệ bài được chấm trong 5 phút.
Tỉ lệ file upload thành công.

SLI khác metric thô ở chỗ nó gắn với trải nghiệm.

Ví dụ CPU usage là metric.

Nhưng tỉ lệ bài được chấm trong 5 phút là SLI tốt hơn cho AI Judge.

Chương 53 sẽ nói kỹ hơn về SLO.

Ở đây chỉ cần nhớ:

> Metric tốt nhất là metric giúp hiểu user có đang được phục vụ tốt không.

---

51.23. Label/tag trong metrics

Metric thường có label.

Ví dụ:

http_requests_total{method="POST", endpoint="/submissions", status="201"}

Label giúp phân nhóm.

Ta có thể hỏi:

Endpoint nào lỗi nhiều?
Status nào tăng?
Provider nào chậm?
Model nào tốn tiền?

Nhưng label phải cẩn thận.

Label có quá nhiều giá trị khác nhau sẽ gây high cardinality.

Ví dụ không nên:

http_requests_total{user_id="user_123456"}

vì có thể có hàng triệu user.

Metrics system có thể đắt/chậm.

---

51.24. High cardinality trong metrics

High cardinality là khi label có quá nhiều giá trị khác nhau.

Ví dụ nguy hiểm:

request_id
user_id
submission_id
email
file_id

Những id này rất hữu ích trong logs/traces.

Nhưng thường không nên làm metric labels.

Metric label tốt hơn:

endpoint
status_code
service
job_type
provider
model
tenant_tier nếu cần

Có trường hợp cần metric theo tenant, nhưng phải cân nhắc số tenant và chi phí.

Nguyên tắc:

Metrics để tổng hợp.
Logs/traces để điều tra id cụ thể.

---

51.25. Dashboard metrics

Dashboard tốt không phải càng nhiều biểu đồ càng tốt.

Dashboard tốt trả lời nhanh:

Hệ thống có khỏe không?
Nếu không, vùng nào đang có vấn đề?

Một dashboard AI Judge chính có thể có:

API latency/error.
Submission rate.
Queue length + oldest job age.
Worker active count.
Grading success/fail/retry.
AI latency/error/rate limit/cost.
Database connections/slow queries.
File upload failure.

Nếu mở dashboard mà vẫn không biết bắt đầu điều tra từ đâu, dashboard đó cần thiết kế lại.

---

51.26. Alert từ metrics

Metrics là nguồn chính cho alert.

Ví dụ:

API 5xx rate > 5% trong 5 phút.
Queue oldest job age > 10 phút.
AI timeout rate > 10%.
Database connection usage > 90%.
Dead letter jobs > 0.
AI cost per hour tăng 3 lần.

Alert nên dựa trên triệu chứng có ý nghĩa.

Không nên alert mọi dao động nhỏ.

Chương 53 sẽ nói kỹ hơn.

Ở đây chỉ cần nhớ:

> Metrics tốt giúp alert tốt. Metrics nhiễu tạo alert nhiễu.

---

51.27. Metrics và deploy

Khi deploy, nên gắn deploy event vào biểu đồ.

Ví dụ:

10:00 deploy version git-a1b2c3
10:05 p95 latency tăng
10:07 error rate tăng

Nhìn biểu đồ có deploy marker, ta khoanh vùng nhanh hơn.

Nếu không có deploy marker, team phải hỏi:

Có ai deploy gì không?
Deploy lúc mấy giờ?
Version nào?

Deploy và metrics nên đi cùng nhau.

Production rất hay hỏng ngay sau thay đổi.

---

51.28. Metrics retention

Metrics cũng có retention.

Raw high-resolution metrics có thể giữ ngắn hơn.

Aggregate metrics giữ dài hơn.

Ví dụ:

10s resolution giữ 7 ngày.
1m resolution giữ 30 ngày.
1h aggregate giữ 1 năm.

Retention giúp so sánh:

Hôm nay so với hôm qua.
Tuần này so với tuần trước.
Sau deploy so với trước deploy.
Deadline tháng này so với tháng trước.

Giữ mọi thứ chi tiết mãi sẽ tốn tiền.

Không giữ gì thì không học được xu hướng.

---

51.29. Metrics không được nói dối

Metric sai nguy hiểm hơn không có metric.

Ví dụ:

Job fail nhưng code vẫn increment completed_total.

Dashboard nói mọi thứ ổn.

Nhưng user không có điểm.

Hoặc:

Timer chỉ đo API enqueue job, không đo end-to-end grading.

Bạn tưởng chấm nhanh vì API 200ms.

Nhưng user chờ 20 phút.

Khi đặt metric, phải hiểu nó đo cái gì và không đo cái gì.

Tên metric phải rõ.

---

51.30. Metrics tối thiểu từ ngày đầu

Không cần quá nhiều.

Nhưng với production có API + worker, nên có tối thiểu:

API request rate/error/latency.
Queue length/oldest job age.
Job success/fail/retry/duration.
Database connection/slow query cơ bản.
External API latency/error.
Resource CPU/memory/disk.

Với AI Judge, thêm:

time_to_grade_seconds
ai_cost_usd
ai_rate_limit_total
grading_failed_by_reason

Đây là bộ đồng hồ cơ bản.

Không có chúng, vận hành rất mù.

---

51.31. Những lỗi metrics phổ biến

Một số lỗi hay gặp:

Chỉ đo CPU/RAM, không đo latency/error/queue.
Chỉ đo API, không đo worker.
Chỉ đo average, không đo p95/p99.
Label metric bằng user_id/request_id làm cardinality nổ.
Metric tên mơ hồ.
Metric không gắn deploy version.
Không đo external API.
Không đo cost.
Dashboard có nhiều biểu đồ nhưng không trả lời được câu hỏi.
Alert dựa trên metric nhiễu.

Hầu hết vấn đề đến từ việc đo cái dễ đo, không phải cái cần biết.

Metrics tốt bắt đầu từ câu hỏi tốt.

---

51.32. Checklist metrics

Hỏi:

  • User đang chờ gì lâu nhất?
  • API endpoint nào chậm/lỗi?
  • Queue có backlog không?
  • Job cũ nhất đã chờ bao lâu?
  • Worker có đang hoạt động không?
  • Job fail vì lý do gì?
  • External API có timeout/rate limit không?
  • Database có connection/lock/slow query không?
  • p95/p99 ra sao?
  • Cost tài nguyên đắt có tăng không?
  • Metric có label quá chi tiết không?
  • Dashboard có giúp khoanh vùng incident không?
  • Deploy mới có gắn vào biểu đồ không?

Nếu một metric không giúp trả lời câu hỏi nào, hãy cân nhắc bỏ.

Nếu một câu hỏi quan trọng không có metric trả lời, hãy thêm metric.

---

51.33. Bảng chọn nhanh

| Câu hỏi | Metric thường cần | |---|---| | API có chậm không? | request duration p95/p99 | | API có lỗi không? | 5xx rate, error count | | Traffic có tăng không? | request rate, submission rate | | Queue có nghẽn không? | queue length, oldest job age | | Worker có xử lý không? | active workers, jobs completed rate | | Job có fail không? | job failed count/rate by reason | | AI provider có vấn đề không? | latency, timeout, rate limit | | Chi phí AI có tăng không? | token/cost counters | | Database có nghẽn không? | connections, slow queries, lock wait | | User có nhận kết quả nhanh không? | time_to_grade p95/p99 |

---

51.34. Tóm tắt bằng AI Judge

Với AI Judge, metrics phải giúp nhìn toàn hệ thống:

Bao nhiêu bài được nộp mỗi phút?
Bao nhiêu job đang chờ?
Job cũ nhất chờ bao lâu?
Worker xử lý được bao nhiêu job/phút?
Chấm bài mất p50/p95/p99 bao lâu?
AI provider có timeout/rate limit không?
Database có connection/slow query không?
Chi phí AI có tăng bất thường không?

Nếu user nói:

Hôm nay chấm chậm.

Metrics giúp biết:

Chậm vì submission tăng?
Vì worker thiếu?
Vì AI chậm?
Vì retry tăng?
Vì database nghẽn?

Log cho từng job.

Metrics cho toàn cảnh.

---

51.35. Kết luận của chương

Metrics là cách hệ thống nói bằng số.

Counter cho biết chuyện gì đã xảy ra bao nhiêu lần.

Gauge cho biết hiện tại đang là bao nhiêu.

Histogram giúp hiểu phân bố nhanh/chậm và tính p95/p99.

Nhưng điều quan trọng nhất không phải thuật ngữ.

Điều quan trọng là metrics phải trả lời được câu hỏi vận hành thật:

Hệ thống có khỏe không?
Đang chậm ở đâu?
Lỗi có lan rộng không?
Có sắp nghẽn không?
User có nhận được kết quả đúng hạn không?

Ở chương tiếp theo, ta sẽ nói về tracing: cách nhìn một request hoặc job đi qua nhiều bước, vì sao tracing quan trọng khi có nhiều service, và vì sao trace qua queue khó hơn trace qua HTTP.