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

Nagle và TCP_NODELAY: bắt tận tay cú trễ 40ms trốn trong TCP

Có một cú trễ đúng 40ms ẩn trong TCP khiến nhiều hệ request-response chậm bí ẩn: thuật toán Nagle gặp delayed ACK. Bài này chạy thật trong Go và tái hiện được ngay trên localhost — mẫu write-write-read với Nagle bật dính 40,9ms mỗi vòng, tắt Nagle chỉ 5µs, chênh gần 9000 lần. Giải thích cơ chế, vì sao Go mặc định tắt Nagle, và khi nào Nagle lại có ích.

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

Socket buffer và listen backlog: hai hàng đợi ẩn quyết định TCP nghẽn ở đâu

Đằng sau mỗi socket TCP là hai hàng đợi trong kernel ít người để ý: buffer nhận/gửi và hàng đợi backlog. Buffer đầy thì TCP chặn người gửi (flow control, khác UDP mất gói); backlog đầy thì kết nối mới bị rớt lúc tải đỉnh. Bài này chạy thật trong Go: client bị chặn sau 44KB với buffer nhỏ, và mở được đúng 4097 kết nối trước khi backlog đầy (somaxconn=4096).

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

HTTP keep-alive: vì sao 500 request chỉ nên mở 1 kết nối, không phải 500

Bài 1 cho thấy bắt tay TCP tốn một RTT mỗi kết nối. Keep-alive giải đúng chuyện đó ở tầng HTTP: giữ kết nối mở để nhiều request dùng chung, bắt tay đúng một lần. Bài này chạy thật trong Go và đếm kết nối TCP thực: 500 request với keep-alive mở đúng 1 kết nối và nhanh hơn 3,9 lần so với tắt keep-alive mở 500 — cùng những cái bẫy vô tình làm mất keep-alive.

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

Connection pool: vì sao pool mặc định 2 làm bạn mở 546 kết nối cho 2000 request

Keep-alive tái dùng một kết nối cho các request tuần tự, nhưng khi nhiều request chạy song song, mỗi luồng cần một kết nối cùng lúc — đó là việc của connection pool. Bài này chạy thật trong Go: 2000 request song song 50 luồng với pool mặc định (2) mở tới 546 kết nối vì churn, còn pool đủ lớn chỉ mở 50 và nhanh hơn. Giải thích cách chọn kích cỡ pool đúng.

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

TLS handshake: cái giá thật của HTTPS đo được, và session resumption cắt nó ra sao

HTTPS an toàn nhưng không miễn phí: sau bắt tay TCP, TLS thêm một bắt tay riêng tốn CPU (toán khóa công khai) và một RTT. Bài này chạy thật trong Go với self-signed cert: TLS full handshake tốn 391µs so với TCP thường 23µs — thêm ~368µs, phần lớn là CPU. Session resumption (500/500 kết nối resumed) bỏ phần đắt; giải thích vì sao trên localhost nó chỉ nhanh 1,1 lần còn trên mạng thực tiết kiệm cả một RTT.

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

DNS resolution: chuyến đi mạng ẩn xảy ra trước cả bắt tay TCP

Trước khi net.Dial kịp bắt tay TCP, có một bước vô hình phải xong: phân giải tên miền thành IP. Bài này chạy thật trong Go: DNS cold tốn 6,97ms (có lúc vọt lên 140ms), cached chỉ 794µs (~9 lần nhanh hơn), còn /etc/hosts thì 1µs không đi mạng. Và httptrace tách được DNS chiếm bao nhiêu trong một request — vì sao DNS chậm/timeout là nguyên nhân 'app chậm' hay bị bỏ sót.