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

Chọn định dạng serialization nào? Tổng kết 12 phần bằng một bảng đo thật

Khép lại loạt Serialization: điểm lại JSON, Protobuf, gob, MessagePack, CBOR, zero-copy — mỗi cái mạnh ở đâu — rồi chạy thật cả năm trên cùng một đơn hàng để so kích thước, tốc độ mã hóa/giải mã và cấp phát. Kết quả đo được: Protobuf nhỏ nhất (205 byte) và giải mã nhanh nhất, JSON dễ đọc nhất nhưng giải mã chậm nhất (2793 ns). Kèm cây quyết định và lời khuyên khi nào cứ JSON là đủ.

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

TCP bắt tay 3 bước nhìn từ code: vì sao mỗi kết nối mới tốn một vòng khứ hồi

Mỗi lần net.Dial hay mở một kết nối HTTP, TCP phải bắt tay 3 bước SYN/SYN-ACK/ACK trước khi gửi được byte dữ liệu đầu tiên — tốn đúng một RTT. Bài này chạy thật trong Go: đo thời gian bắt tay, so kết nối mới mỗi request với tái dùng một kết nối (nhanh hơn 13 lần), và đọc trạng thái socket từ /proc/net/tcp để thấy LISTEN, ESTABLISHED và đống TIME_WAIT.

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

TCP vs UDP: đo thật cảnh UDP mất 99,9% gói và vì sao đó không phải lỗi

TCP đảm bảo gói tới đủ và đúng thứ tự; UDP bắn và quên, không đảm bảo gì. Bài này chạy thật trong Go: gửi 200.000 gói — TCP nhận đủ 100% đúng thứ tự, còn UDP khi bị bắn dồn dập vào buffer nhỏ mất tới 99,9%. Nhưng UDP nhanh hơn và header chỉ 8 byte. Giải thích vì sao mỗi giao thức đúng cho việc của nó, không cái nào tệ hơn.

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.