Chương 52. Tracing
Chương 50 nói về logs.
Chương 51 nói về metrics.
Chương này nói về tracing.
Nếu log trả lời:
Chuyện gì đã xảy ra?
Metrics trả lời:
Toàn hệ thống đang khỏe hay chậm theo thời gian?
Thì trace trả lời:
Một request hoặc một job đã đi qua những bước nào, mất bao lâu ở mỗi bước, và chậm/lỗi ở đâu?
Thông điệp chính của chương:
> Tracing giúp nhìn đường đi của một request/job qua nhiều bước và nhiều service. Nó đặc biệt hữu ích khi hệ thống có microservices, queue, worker, external API, hoặc những flow dài khó hiểu chỉ bằng log rời rạc.
---
52.1. Một tình huống: request "nộp bài" nhanh, nhưng điểm vẫn lâu
Student bấm nộp bài.
Frontend gọi:
POST /submissions
API trả rất nhanh:
202 Accepted
job_id=job_789
Nhìn metric API, mọi thứ đẹp:
POST /submissions p95 = 220ms
5xx gần như 0
Nhưng user vẫn nói:
Em chờ 15 phút chưa có điểm.
Log có thể cho thấy vài mốc.
Metrics có thể cho thấy queue backlog tăng.
Nhưng trace giúp nhìn một flow cụ thể:
Submit request
-> auth check: 12ms
-> permission check: 18ms
-> save submission: 45ms
-> create grading job: 20ms
-> enqueue job: 8ms
Grading job
-> wait in queue: 12m 30s
-> download file: 400ms
-> extract files: 1.2s
-> call Gemini: 91s
-> parse response: 100ms
-> save result: 60ms
Bây giờ ta thấy rõ:
API không chậm.
AI call có lâu, nhưng không phải vấn đề lớn nhất.
Vấn đề lớn nhất là job chờ trong queue 12 phút 30 giây.
Trace biến cảm giác "chậm" thành một đường đi có thời gian từng đoạn.
---
52.2. Trace là gì?
Trace là bản ghi đường đi của một operation.
Operation có thể là:
- Một HTTP request.
- Một background job.
- Một message được xử lý.
- Một workflow.
Ví dụ trace của request:
GET /teacher/dashboard
-> authenticate
-> query courses
-> query submissions summary
-> query grading stats
-> call billing service
-> render response
Trace giúp ta thấy:
Tổng thời gian là bao lâu?
Bước nào tốn nhiều thời gian nhất?
Bước nào lỗi?
Request đi qua service nào?
Trace không thay log.
Trace là bản đồ đường đi.
Log là các ghi chú trên đường.
---
52.3. Span là gì?
Span là một đoạn trong trace.
Nếu trace là cả chuyến đi, span là từng chặng.
Ví dụ:
Trace: POST /submissions
Span 1: auth_check
Span 2: permission_check
Span 3: db_insert_submission
Span 4: enqueue_grading_job
Mỗi span thường có:
- Tên.
- Thời gian bắt đầu.
- Thời gian kết thúc.
- Duration.
- Status: success/error.
- Attributes/tags.
- Parent span.
Ví dụ:
db_insert_submission duration=45ms status=ok
Span giúp ta không chỉ biết request chậm, mà biết chậm ở bước nào.
---
52.4. Parent và child span
Trace có cấu trúc cây.
Một span có thể chứa span con.
Ví dụ:
POST /submissions
auth_check
permission_check
create_submission
db_insert_submission
db_insert_outbox_event
enqueue_job
POST /submissions là span cha.
Các bước bên trong là span con.
Cấu trúc này giúp ta thấy:
Tổng request mất 220ms.
Trong đó create_submission mất 70ms.
Trong create_submission, db_insert_submission mất 45ms.
Không có trace, ta có thể chỉ thấy:
Request 220ms.
Trace cho ta kính hiển vi thời gian.
---
52.5. Trace ID là gì?
Trace ID là id chung cho toàn bộ trace.
Ví dụ:
trace_id=tr_abc
Mọi span trong cùng trace mang cùng trace id.
Logs cũng nên gắn trace id nếu có thể.
Ví dụ log:
{
"event": "grading_job_enqueued",
"trace_id": "tr_abc",
"request_id": "req_123",
"job_id": "job_789"
}
Nhờ vậy từ log ta có thể nhảy sang trace.
Từ trace ta có thể nhảy sang log.
Observability tốt là các tín hiệu nối được với nhau.
---
52.6. Trace context là gì?
Trace context là thông tin giúp truyền trace qua các service.
Ví dụ API Service gọi Submission Service.
Nếu không truyền trace context, Submission Service tạo trace mới.
Bạn sẽ thấy hai trace rời rạc.
Nếu có truyền trace context:
API Service span
-> Submission Service span
cùng nằm trong một trace.
Qua HTTP, trace context thường được truyền bằng header.
Ví dụ theo chuẩn W3C:
traceparent: ...
Bạn không cần nhớ cú pháp.
Chỉ cần hiểu:
> Muốn trace đi qua nhiều service, ta phải truyền ngữ cảnh trace qua boundary.
---
52.7. Vì sao tracing quan trọng khi có nhiều service?
Trong monolith, request thường nằm trong một process.
Log và profiler có thể đủ cho nhiều vấn đề.
Trong microservices, một request có thể đi:
API Gateway
-> Auth Service
-> Course Service
-> Submission Service
-> Grading Service
-> Billing Service
Nếu user nói:
Dashboard chậm.
Bạn cần biết:
Chậm ở gateway?
Auth?
Course service?
Submission query?
Billing call?
Network giữa service?
Trace cho thấy đường đi qua các service.
Không có trace, mỗi service chỉ thấy một mảnh.
Team dễ đổ lỗi qua lại:
API nói database.
Database nói query bình thường.
Billing nói không phải tôi.
Gateway nói upstream timeout.
Trace giúp đưa mọi mảnh lên cùng một bản đồ.
---
52.8. Trace trong monolith có cần không?
Có thể vẫn cần.
Monolith lớn cũng có nhiều bước:
- Middleware.
- Auth.
- Permission.
- Service layer.
- Database queries.
- Cache.
- External API.
- File storage.
Ví dụ:
GET /teacher/dashboard
auth: 10ms
permission: 20ms
query courses: 50ms
query stats: 2.5s
render: 30ms
Trace giúp thấy query stats là điểm chậm.
Không cần chờ đến microservices mới dùng tracing.
Nhưng tracing càng có giá trị khi boundary càng nhiều.
---
52.9. Trace qua HTTP tương đối dễ
HTTP request có header.
Khi Service A gọi Service B, A có thể gửi trace context qua header.
Service B nhận header và tạo span con.
Luồng:
Client
-> API Gateway
-> API Service
-> Submission Service
Trace context đi theo request.
Nhiều framework/library có instrumentation tự động cho HTTP client/server.
Vì vậy tracing qua HTTP thường dễ hơn tracing qua queue.
---
52.10. Trace qua queue khó hơn
Queue làm flow bị tách thời gian.
Ví dụ:
HTTP request tạo job lúc 10:00.
Worker xử lý job lúc 10:10.
Không còn một call stack liền mạch.
Nếu không làm gì, trace request và trace worker sẽ tách rời.
Muốn nối, khi enqueue job cần lưu trace context hoặc ít nhất lưu:
trace_id
origin_request_id
job_id
submission_id
Worker đọc job và tiếp tục trace hoặc tạo trace mới có link tới trace cũ.
Đây là điểm nhiều hệ thống bỏ sót.
Kết quả là:
API trace kết thúc ở enqueue.
Worker trace bắt đầu ở job processing.
Không biết chúng liên quan với nhau.
Với AI Judge, trace qua queue rất quan trọng.
---
52.11. Trace link là gì?
Đôi khi worker job không phải là span con trực tiếp của HTTP request.
Vì nó chạy sau, có thể retry, có thể được xử lý bởi worker khác.
Ta có thể dùng khái niệm link:
Worker trace link tới request trace ban đầu.
Nói dễ hiểu:
Hai trace không nằm cùng một cây, nhưng có quan hệ.
Ví dụ:
Trace A:
POST /submissions -> enqueue job_789
Trace B:
process job_789 -> call AI -> save result
Trace B links to Trace A.
Không cần dùng thuật ngữ quá sâu ngay.
Điểm chính:
> Queue làm trace không còn thẳng như HTTP. Ta phải chủ động nối bằng job id, trace context hoặc trace link.
---
52.12. Trace giúp thấy thời gian chờ trong queue
Một lỗi observability phổ biến:
Chỉ đo thời gian worker xử lý job.
Ví dụ:
worker_processing_time = 95s
Nghe có vẻ ổn nếu AI call mất 90s.
Nhưng user có thể chờ 15 phút.
Vì còn:
queue_wait_time = 13m 30s
Trace hoặc metrics nên tách:
time_in_queue
time_processing
end_to_end_time
Với AI Judge:
Student care about end_to_end_time.
Engineer care about queue_wait and processing breakdown.
Trace giúp thấy cả hai.
---
52.13. Trace và database query
Trace có thể instrument database queries.
Ví dụ:
GET /teacher/dashboard
db query courses: 30ms
db query assignments: 80ms
db query grading_stats: 2.8s
Ta không cần đoán query nào chậm.
Trace chỉ ra.
Nhưng cẩn thận:
- Không ghi full query chứa dữ liệu nhạy cảm nếu không cần.
- Không tạo quá nhiều span cho từng query nhỏ nếu chi phí cao.
- Nên normalize query hoặc dùng query name.
Ví dụ tốt:
db.operation=select
db.statement_name=teacher_dashboard_stats
duration=2.8s
Không nhất thiết log full SQL với tham số nhạy cảm.
---
52.14. Trace và external API
External API là nơi trace rất hữu ích.
Ví dụ worker:
download_submission_file: 300ms
call_gemini: 91s
save_result: 60ms
Nếu job chậm, trace cho thấy AI call chiếm gần hết thời gian.
Nếu AI call retry:
call_gemini attempt=1 timeout 90s
backoff 30s
call_gemini attempt=2 success 80s
Trace giúp nhìn retry có làm job dài hơn thế nào.
Với AI product, trace external API call rất đáng giá.
Nhưng không nên ghi full prompt/response nhạy cảm vào trace.
Chỉ ghi metadata an toàn:
provider
model
attempt
status
duration
token_count
cost estimate nếu cần
---
52.15. Trace và cache
Trace cũng giúp thấy cache có hoạt động không.
Ví dụ:
get_course_config
redis_get: 5ms cache_hit=true
Hoặc:
get_teacher_dashboard
cache_lookup: 4ms cache_hit=false
db_query_stats: 2.3s
cache_write: 8ms
Nếu latency cao vì cache miss nhiều, trace giúp thấy.
Metrics cho biết cache hit rate toàn hệ thống.
Trace cho biết request cụ thể miss ở đâu.
---
52.16. Trace và permission
Permission check có thể chậm hoặc sai.
Ví dụ:
permission_check: 1.8s
Nếu request detail submission chậm, ta có thể nghĩ database chính chậm.
Nhưng trace cho thấy:
permission check gọi nhiều query membership.
Khi authorization phức tạp, trace giúp hiểu permission layer có đang thành bottleneck không.
Nhưng đừng ghi dữ liệu permission nhạy cảm quá chi tiết vào trace.
Ghi đủ:
action=submission.view
resource_type=submission
result=allow/deny
duration
---
52.17. Sampling trong tracing
Trace có thể tốn chi phí nếu lưu mọi request.
Nhiều hệ thống dùng sampling:
Trace một phần request bình thường.
Trace toàn bộ request lỗi.
Trace toàn bộ request chậm.
Trace flow quan trọng.
Ví dụ:
Sample 10% GET bình thường.
Sample 100% POST /submissions.
Sample 100% failed grading jobs.
Sampling nên thông minh.
Nếu sample quá ít, bạn không thấy lỗi hiếm.
Nếu sample tất cả, chi phí có thể cao.
Với flow quan trọng như chấm bài, nên trace nhiều hơn ít nhất trong giai đoạn đầu.
---
52.18. Trace không nên chứa dữ liệu nhạy cảm
Trace attributes dễ bị lạm dụng.
Không nên đưa vào trace:
- Password.
- Token.
- API key.
- Full prompt có dữ liệu học sinh.
- Nội dung bài làm.
- Feedback private.
- File content.
- Email nếu không cần.
Nên đưa metadata an toàn:
submission_id
job_id
tenant_id
provider
model
duration
status
attempt
error_type
Trace giúp điều tra đường đi.
Nó không nên trở thành bản sao dữ liệu private.
---
52.19. Trace UI nhìn như thế nào?
Một trace viewer thường hiển thị waterfall.
Nghĩa là các span được xếp theo thời gian.
Ví dụ:
POST /teacher/dashboard 3.2s
|-- auth_check 10ms
|-- permission_check 40ms
|-- query_courses 80ms
|-- query_stats 2.8s
|-- format_response 30ms
Nhìn vào là thấy:
query_stats chiếm gần hết thời gian.
Waterfall rất trực quan.
Nó giúp người mới hiểu performance hơn rất nhiều so với chỉ đọc log.
---
52.20. Trace và N+1 query
Trace rất giỏi phát hiện N+1 query.
Ví dụ dashboard load một danh sách 100 submissions.
Trace hiện:
query submissions: 80ms
query user for submission 1: 5ms
query user for submission 2: 5ms
...
query user for submission 100: 5ms
Mỗi query nhỏ.
Nhưng tổng cộng nhiều.
Nếu chỉ nhìn slow query, không query nào quá chậm.
Nhưng trace cho thấy pattern lặp.
Giải pháp có thể là:
- Eager load.
- Batch query.
- Join hợp lý.
- Data loader.
Trace giúp thấy cấu trúc chậm, không chỉ một query chậm.
---
52.21. Trace và retry
Retry làm flow phức tạp hơn.
Trace có thể cho thấy:
call_ai attempt 1: timeout 90s
backoff: 30s
call_ai attempt 2: timeout 90s
backoff: 60s
call_ai attempt 3: success 80s
Tổng job mất:
90 + 30 + 90 + 60 + 80 = 350s
Nếu user hỏi sao job lâu, trace trả lời rất rõ.
Nếu retry storm xảy ra, metrics cho thấy toàn hệ thống retry tăng.
Trace cho thấy một job cụ thể retry như thế nào.
---
52.22. Trace và timeout
Timeout ở proxy/API/worker/external API có thể khó debug.
Trace giúp thấy:
Gateway timeout at 30s.
Backend span kept running to 45s.
Database query took 40s.
Hoặc:
Worker timeout at 120s.
AI call took 118s.
Save result never happened.
Nếu không trace, ta có thể chỉ thấy user nhận 504.
Trace cho thấy request chết ở biên nào.
---
52.23. OpenTelemetry là gì ở mức khái niệm?
OpenTelemetry là một bộ chuẩn và công cụ mở để thu thập telemetry:
- Traces.
- Metrics.
- Logs.
Với tracing, OpenTelemetry giúp app tạo spans và truyền trace context theo cách chuẩn.
Ý tưởng:
Instrument app bằng OpenTelemetry.
Gửi traces đến backend như Jaeger, Tempo, Honeycomb, Datadog, New Relic, Grafana Cloud...
Điểm hay là giảm phụ thuộc vào một vendor ngay từ code.
Bạn không cần hiểu toàn bộ OpenTelemetry ngay.
Chỉ cần hiểu:
> Nó là cách phổ biến để chuẩn hóa việc tạo, truyền và xuất trace/metric/log trong hệ thống hiện đại.
---
52.24. Auto instrumentation và manual instrumentation
Auto instrumentation là thư viện tự tạo span cho thứ phổ biến:
- HTTP server.
- HTTP client.
- Database client.
- Redis.
- Message queue.
Manual instrumentation là bạn tự thêm span cho logic nghiệp vụ.
Ví dụ:
grade_submission
build_prompt
call_ai_provider
parse_ai_feedback
save_grading_result
Auto instrumentation cho bạn nền.
Manual instrumentation cho bạn ý nghĩa domain.
Nếu chỉ có auto, trace có thể nói:
HTTP call, DB query.
Nhưng không nói:
Đây là bước build rubric prompt.
Đây là bước parse feedback.
Với hệ thống nghiệp vụ quan trọng, cần cả hai.
---
52.25. Trace tốt bắt đầu từ naming tốt
Span name nên rõ.
Không tốt:
process
handle
do_work
call
Tốt hơn:
create_submission
enqueue_grading_job
download_submission_file
call_ai_provider
save_grading_result
Tên span nên mô tả bước có ý nghĩa.
Khi nhìn waterfall, người đọc phải hiểu hệ thống đang làm gì.
Trace không chỉ cho máy.
Trace là công cụ để con người đọc đường đi.
---
52.26. Trace attributes nên có gì?
Attributes là metadata của span.
Ví dụ cho AI call:
provider=gemini
model=...
attempt=1
status=timeout
input_tokens=...
output_tokens=...
Ví dụ cho job:
job_id=job_789
job_type=grading
submission_id=sub_123
tenant_id=school_a
attempt=2
Chọn attributes như chọn log fields:
Đủ để điều tra.
Không lộ dữ liệu nhạy cảm.
Không tạo cardinality quá nguy hiểm nếu backend trace tính phí/đánh index theo field.
---
52.27. Trace không thay thiết kế tốt
Trace giúp thấy vấn đề.
Nó không tự sửa vấn đề.
Nếu trace cho thấy:
queue wait = 20 phút
Bạn vẫn cần giải quyết bằng:
- Tăng worker.
- Tối ưu job.
- Tách queue ưu tiên.
- Kiểm soát retry.
- Tính lại quota AI.
Nếu trace cho thấy:
permission_check = 2s
Bạn vẫn cần tối ưu query/cache/rule.
Observability là đèn pin.
Không phải cái búa tự sửa nhà.
---
52.28. Khi nào nên ưu tiên tracing?
Tracing đặc biệt đáng ưu tiên khi:
- Có nhiều service.
- Có queue/worker.
- Request đi qua nhiều dependency.
- Latency khó giải thích.
- Có external API chậm.
- Có N+1 query.
- Có retry/timeout phức tạp.
- User phàn nàn "chậm" nhưng metrics chưa đủ chỉ ra nguyên nhân.
Nếu app còn rất nhỏ, logs + metrics tốt có thể đủ lúc đầu.
Nhưng với AI Judge có API + queue + worker + AI provider, tracing rất đáng cân nhắc sớm cho flow chấm bài.
---
52.29. AI Judge: trace một flow chấm bài
Một trace tốt cho AI Judge có thể nhìn như:
submit_assignment_request
authenticate_user
check_assignment_permission
create_submission
create_grading_job
enqueue_grading_job
process_grading_job
wait_in_queue
download_submission_file
extract_submission
load_rubric
build_ai_prompt
call_ai_provider
parse_ai_response
save_grading_result
publish_grading_completed_event
Nhìn trace này, ta biết:
User chờ lâu vì queue?
Hay vì download file?
Hay vì AI provider?
Hay vì parse response?
Hay vì save result?
Không cần đoán.
---
52.30. AI Judge: trace qua queue cần gì?
Khi API tạo job, job payload nên có đủ context an toàn:
job_id
submission_id
tenant_id
origin_request_id
trace_context hoặc trace_id/link
created_at
Worker khi nhận job:
Tạo span process_grading_job.
Gắn job_id/submission_id.
Nối với trace/request ban đầu nếu có.
Đo queue wait bằng now - created_at.
Nếu làm vậy, ta nối được web request và worker processing.
Nếu không, production sẽ có hai mảnh rời:
API nói đã enqueue.
Worker nói đã xử lý job.
Nhưng nối hai chuyện rất mệt.
---
52.31. Những lỗi tracing phổ biến
Một số lỗi hay gặp:
Chỉ trace HTTP, quên worker/queue.
Không truyền trace context qua service.
Span name quá chung chung.
Trace chứa dữ liệu nhạy cảm.
Không sample hợp lý nên quá tốn.
Không trace request lỗi/chậm.
Chỉ có auto instrumentation, không có span nghiệp vụ.
Không gắn job_id/submission_id.
Không nối trace với log.
Nhìn trace nhưng không có metrics để biết vấn đề lan rộng không.
Tracing là một phần của observability.
Nó mạnh nhất khi đi cùng logs và metrics.
---
52.32. Checklist tracing
Hỏi:
- Request quan trọng có trace không?
- Worker/job quan trọng có trace không?
- Có truyền trace context qua HTTP không?
- Có nối flow qua queue không?
- Span name có dễ hiểu không?
- Span có đo duration của bước quan trọng không?
- Có attributes đủ để điều tra không?
- Có tránh dữ liệu nhạy cảm không?
- Có sample request lỗi/chậm đầy đủ không?
- Có nối trace với logs bằng trace_id/job_id không?
- Trace có giúp trả lời "chậm ở đâu" không?
Nếu trace không giúp trả lời "chậm ở đâu", nó cần được thiết kế lại.
---
52.33. Bảng chọn nhanh
| Câu hỏi | Trace giúp thế nào | |---|---| | Request chậm ở đâu? | Xem span nào chiếm nhiều thời gian | | Service nào gây chậm? | Xem waterfall qua service | | Job chờ hay xử lý lâu? | Tách queue wait và processing time | | AI provider có chiếm thời gian không? | Span call_ai_provider | | Có N+1 query không? | Thấy nhiều span DB lặp | | Retry làm job dài không? | Thấy các attempt và backoff | | Timeout ở lớp nào? | Thấy span kết thúc/lỗi ở proxy/app/dependency | | Log của trace này ở đâu? | Dùng trace_id/request_id/job_id | | Queue có làm đứt trace không? | Truyền trace context/link qua job payload |
---
52.34. Tóm tắt bằng AI Judge
Với AI Judge:
Metrics nói:
chấm bài hôm nay chậm trên toàn hệ thống.
Logs nói:
job_789 timeout ở Gemini attempt 1.
Trace nói:
job_789 chờ queue 12 phút, gọi AI 91 giây, lưu result 60ms.
Ba góc nhìn này bổ sung nhau.
Trace đặc biệt hữu ích cho flow:
student submit
-> API tạo submission
-> enqueue job
-> worker xử lý
-> gọi AI
-> lưu kết quả
-> thông báo user
Điểm khó nhất là queue.
Muốn trace qua queue, phải truyền hoặc liên kết context bằng job id, trace id, origin request id.
---
52.35. Kết luận của chương
Tracing giúp ta nhìn đường đi của một request hoặc job.
Trace là cả hành trình.
Span là từng chặng trong hành trình.
Trace context giúp nối hành trình qua service boundary.
Qua HTTP, việc nối trace tương đối tự nhiên.
Qua queue, ta phải chủ động truyền context hoặc tạo link.
Thông điệp cần nhớ:
> Trace trả lời câu hỏi "chậm/lỗi ở bước nào trong hành trình này?". Khi hệ thống có nhiều service, worker, queue và external API, tracing giúp biến một flow mơ hồ thành một bản đồ thời gian có thể đọc được.
Ở chương tiếp theo, ta sẽ nói về alerting và SLO: alert tốt là alert cần hành động, vì sao alert quá nhiều làm team tê liệt, SLI/SLO/SLA khác nhau thế nào, và vì sao nên báo động theo triệu chứng người dùng thay vì từng lỗi nhỏ rời rạc.