Lập trình 22/09/2026 6 phút

Distributed tracing: metric nói 'request chậm 39ms', tracing chỉ đúng dbQuery mới là thủ phạm 80%

Metric cho biết một request chậm, nhưng không nói chậm ở CHẶNG nào. Tracing giải quyết điều đó bằng span lồng nhau: mỗi chặng một span, tất cả cùng traceID, mỗi span trỏ về cha để dựng lại cây. Bài này tự cài một tracer tối giản trong Go (không cần backend) và đo thật một request đi qua handler → auth → db → cache: cây span cho thấy dbQuery chiếm 31/39ms = 80%, đúng chặng cần tối ưu.

Lập trình 22/09/2026 7 phút

pprof: đừng đoán hàm nào chậm, đo — CPU profile và heap profile tìm đúng thủ phạm

Tracing chỉ ra chặng nào chậm; nhưng trong một chặng, HÀM nào ngốn CPU hay giữ RAM? Đừng đoán — pprof của Go đo trực tiếp. Bài này chạy thật runtime/pprof: CPU profile chỉ ra main.hotHash chiếm 100% CPU (qua sha256), heap profile chỉ ra main.allocBig giữ đúng 197.76MB còn allocSmall biến mất vì đã bị GC. Kèm cách đọc hai cột flat vs cum mà nhiều người nhầm.

Lập trình 22/09/2026 6 phút

runtime/metrics: quan sát goroutine, heap và GC từ bên trong app Go — bắt rò rỉ goroutine tại chỗ

Metric ứng dụng (phần 3-6) cho biết dịch vụ thế nào, nhưng runtime Go bên dưới cũng cần quan sát: bao nhiêu goroutine đang sống, heap lớn bao nhiêu, GC chạy mấy lần và dừng thế giới bao lâu. Bài này đo thật bằng gói runtime/metrics: sinh 5000 goroutine + cấp phát 1.3GB, thấy goroutines 1→5001, 27 lần GC, 0.70ms STW; rồi thả ra thấy goroutines về 1 — chính là cách bắt rò rỉ goroutine, một trong những lỗi Go nguy hiểm nhất.

Lập trình 22/09/2026 6 phút

Cardinality explosion: một label user_id làm nổ metric store 2000 lần — nguyên nhân số 1 sập Prometheus

Label làm metric mạnh lên (cắt lát theo method, status), nhưng đặt sai một label là tự tay cho nổ. Bài này đo thật với client_golang: cùng một counter, label an toàn {method, status} sinh 10 chuỗi thời gian; thêm một label user_id thành 20.000 chuỗi — nổ đúng 2000 lần. Vì cardinality là TÍCH số giá trị mọi label, không phải tổng; và user_id/request_id/URL trong thực tế là vô hạn, chuỗi tăng không ngừng tới khi Prometheus ngốn hết RAM và sập.

Lập trình 22/09/2026 6 phút

Sampling: head sampling 1% bỏ sót 99% lỗi, error-biased giữ 4% mà bắt 100% lỗi

Trace và log mỗi request thì đúng nhất, nhưng hàng triệu request/ngày là khối dữ liệu không kham nổi. Sampling giảm khối lượng — nhưng sampling ngẫu nhiên (head) bỏ mù đúng thứ cần thấy: lỗi hiếm. Bài này đo thật trên 100.000 trace: head sampling 1% chỉ bắt 14/1029 lỗi (bỏ sót 99%); error-biased sampling giữ tổng cộng chỉ 4% mà bắt trọn 1029/1029 lỗi. Cùng bàn cái giá của tail sampling và vì sao metric không sample.

Lập trình 22/09/2026 6 phút

Timing attack: so sánh token bằng == làm rò rỉ bí mật qua thời gian — và cách so constant-time

So sánh một token hay chữ ký bằng == trông vô hại, nhưng nó thoát sớm ở byte đầu tiên khác nhau — nên thời gian so sánh tiết lộ bạn đã đoán đúng bao nhiêu byte. Bài này đo thật trong Go: so sánh thoát sớm cho thời gian tuyến tính theo số byte khớp (từ 1.2ns khi khớp 0% lên 50.692ns khi khớp 100%), còn ConstantTimeCompare phẳng ~54.700ns bất kể khớp bao nhiêu. Về lý thuyết, kênh thời gian đó cho phép dò token từng byte.