Vì sao request đầu tiên luôn chậm hơn? TCP handshake “ăn” mất 1 RTT
Tóm tắt
Trước khi gửi byte dữ liệu đầu tiên, client và server phải bắt tay TCP, tốn trọn một vòng đi-về (RTT). Các request tiếp theo đi lại trên kết nối cũ (keep-alive) nên nhanh hơn đúng 1 RTT.
Dòng thời gian với RTT = 80ms
| Mốc | Sự kiện |
|---|---|
| 0 → 40ms | Client gửi SYN sang server. |
| 40 → 80ms | Server đáp SYN-ACK (ack = seq của SYN + 1). |
| 80ms | Client gửi ACK kèm luôn GET / — byte dữ liệu đầu tiên mới rời máy. |
| 160ms | Response của request đầu tiên về tới client. |
| +80ms | Request thứ hai (GET /app.js) đi trên kết nối cũ: chỉ cần 1 RTT. |
Áp dụng thế nào?
- Tái sử dụng kết nối: Bật keep-alive và connection pooling (HTTP client, DB driver) để tránh bắt tay lặp lại.
- Frontend: Dùng
<link rel="preconnect">cho domain quan trọng (font, API, CDN) để bắt tay sớm. - Hạ tầng: HTTP/2 gộp nhiều request trên một kết nối; HTTP/3 (QUIC) gộp bắt tay transport và TLS để giảm số RTT. Đưa server lại gần user (CDN/edge) để rút ngắn chính RTT.
- Khi đo hiệu năng: Tách riêng thời gian kết nối khỏi thời gian xử lý của server để không đổ oan cho backend.