Đang nghiên cứu tối ưu cho dự án thì phát hiện một điều cũng khá wow. Một website nhẹ thì load nhanh hơn, chuyện này thì hiển nhiên rồi. Nhưng điều có thể mọi người chưa biết là một trang 14KB có thể load nhanh hơn một trang 15KB đến hơn nửa giây, trong khi sự khác biệt giữa trang 15KB và 16KB lại gần như không đáng kể, nghe wow không :)))
Lý do nằm ở một thuật toán tên là TCP slow start.
TCP là gì?
Giao thức này thì chắc mọi người đều biết rồi, thôi cứ viết ra cho ai chưa biết nhé. HTTP/1.1 hay HTTP/2 đều chạy trên nền TCP (trừ HTTP/3 thì chạy trên QUIC/UDP). TCP (Transmission Control Protocol) đảm bảo dữ liệu được truyền đi đầy đủ, theo đúng thứ tự. Nó làm việc bằng cách chia dữ liệu thành các gói (packet), gửi đi và yêu cầu bên nhận xác nhận (ACK). Nếu gói nào mất thì TCP sẽ gửi lại. Hiểu nôm na là ông shipper ship hàng cho bạn sẽ chờ bạn ký xác nhận thì mới gọi là giao thành công còn không thì ông shipper mang hàng về để đảm bảo không mất đơn hàng.
TCP slow start
Khi kết nối TCP mới được mở, server không biết đường truyền giữa nó và client có thể chịu được bao nhiêu dữ liệu. Để tránh “dội nước vỡ ống”, TCP bắt đầu gửi một lượng nhỏ dữ liệu, gọi là initial congestion window (IW). Cứ tưởng tượng bandwidth là độ rộng của một ống nước. Server không biết ống nước của mọi người to hay nhỏ, nên nó sẽ không xả nước ào ào ngay lập tức. Thay vào đó, nó sẽ bắt đầu một cách an toàn là gửi đi một lượng nhỏ dữ liệu.
Theo chuẩn RFC 6928, hầu hết hệ điều hành hiện nay dùng 10 segment làm cửa sổ khởi đầu. Mỗi segment thường trùng với MSS (Maximum Segment Size) – thường là 1460 byte nếu MTU = 1500 byte.
Tính ra:
10 × 1460 byte = 14600 byte ≈ 14KB
Nghĩa là ở chuyến “burst” đầu tiên, server chỉ có thể gửi tối đa khoảng 14KB dữ liệu (bao gồm cả HTTP headers). Nếu response lớn hơn, phần dư phải chờ thêm một round trip nữa.
Round Trip Time (RTT)
RTT là độ trễ để dữ liệu đi từ client => server rồi quay về. Ở mạng tốt (fiber, 4G gần), RTT chỉ 20-40ms, bạn sẽ không thấy khác biệt lớn. Nhưng ở môi trường độ trễ cao (mạng vệ tinh, 3G yếu, congested WiFi…), RTT có thể lên đến hàng trăm ms.
Ví dụ mạng quốc tế từ VN sang Mỹ:
- Người dùng ở Hà Nội truy cập server đặt ở California.
- Tín hiệu đi qua tuyến cáp quang biển ~13.000 km.
- Một vòng khứ hồi thường 250-300ms.
- Nghĩa là mỗi lần vượt cửa sổ 14KB, phải chờ thêm ~300ms.
Chỉ thêm một chút dữ liệu vượt ngưỡng 14KB thôi, nhưng người dùng phải ngồi đợi thêm gần một phần ba giây, một độ trễ không hề nhỏ trong trải nghiệm web :)))
Điều cần làm
Dĩ nhiên, hãy làm website của mình nhỏ nhất có thể. Mục tiêu dưới 14KB cho mỗi trang là một mục tiêu rất tốt. Con số 14KB này đã bao gồm compression, nên thực tế mọi người có khoảng ~50KB uncompressed data. Hãy nghĩ xem, máy tính dẫn đường cho tàu Apollo 11 chỉ có 72KB bộ nhớ.
Nếu mọi người bỏ hết mấy thứ chưa cần thiết như video tự chạy, popup, banner cookie, nút mạng xã hội, script theo dõi, framework thừa thãi… thì có lẽ trang web của mọi người đã đạt mục tiêu rồi. Nhưng nếu không thể, quy tắc 14KB vẫn hữu ích. Hãy đảm bảo 14KB dữ liệu đầu tiên chứa những thứ có thể render ra được cái gì đó hữu ích cho người dùng ví dụ như CSS quan trọng, vài đoạn text đầu tiên, và JS cốt lõi.
Lưu ý: Quy tắc 14KB bao gồm cả HTTP headers không được nén ở response đầu tiên và cả hình ảnh. Vì vậy, hãy chỉ tải những ảnh thực sự cần thiết ngay lập tức và tối ưu chúng thật nhỏ.
Điểm cần nhớ
Một số server hoặc CDN có thể tăng cửa sổ ban đầu lên 30 packet, hoặc cache lại thông tin kết nối để lần sau gửi được nhiều hơn. Các giao thức mới như HTTP/3 và QUIC cũng khuyến nghị tuân theo quy tắc 10 packet (~14KB) ban đầu này. Vì vậy, nó vẫn là một con số rất đáng để mọi người quan tâm.