Bài http-05 kết bằng một giới hạn: HTTP/2 xóa head-of-line blocking ở tầng HTTP, nhưng mọi luồng vẫn chạy trên một kết nối TCP — mất một gói TCP là tất cả luồng bị chặn. Đó là lý do HTTP/3 ra đời, và nó làm điều táo bạo: bỏ TCP, chạy trên UDP thông qua giao thức mới tên QUIC. Bài này giải thích vì sao và đo phần đo được — thành thật rằng curl trong lab không build kèm HTTP/3, nên ta đo những gì khả dụng (trạng thái h3 của curl, Alt-Svc từ site thật, chi phí bắt tay mà QUIC tiết kiệm).

Vấn đề còn lại của HTTP/2: TCP head-of-line blocking

HTTP/2 multiplex nhiều stream trên một kết nối TCP (bài http-05). Nhưng TCP là một dòng byte có thứ tự: nếu một gói TCP bị mất, TCP giữ lại toàn bộ dữ liệu đến sau (kể cả của stream khác) cho tới khi gói mất được truyền lại. Vậy là head-of-line blocking không biến mất — nó dời từ tầng HTTP xuống tầng TCP. Một stream mất gói kéo theo mọi stream khác đứng chờ, dù chúng chẳng liên quan.

QUIC giải quyết bằng cách tự mình quản lý các stream ở tầng vận chuyển (trên UDP), nơi mỗi stream độc lập:

HTTP/3 = HTTP trên QUIC (QUIC chạy trên UDP, không dùng TCP)
+ mỗi stream độc lập ở tầng vận chuyển -> mất gói stream này không chặn stream khác
+ gộp bắt tay transport + mã hóa (TLS 1.3) -> 1 RTT (0-RTT khi nối lại)
+ connection ID -> đổi mạng (wifi<->4G) không đứt kết nối
curl --http3 https://site          # cần curl build kèm h3
curl -sI https://site | grep alt-svc   # xem site có quảng cáo h3 không

Ảnh chụp đoạn mã nền tối giải thích HTTP/3 và QUIC bỏ TCP chạy trên UDP, vấn đề còn lại của HTTP/2 TCP head-of-line blocking HTTP/2 multiplex nhiều stream trên một kết nối TCP nhưng mọi stream vẫn chung một dòng TCP mất 1 gói TCP giữ lại tất cả stream tới khi truyền lại xong HoL blocking dời từ tầng HTTP xuống tầng TCP vẫn còn, QUIC giao thức vận chuyển mới trên UDP HTTP/3 bằng HTTP trên QUIC chạy trên UDP không dùng TCP mỗi stream độc lập ở tầng vận chuyển mất gói stream này không chặn stream khác hết TCP HoL blocking gộp bắt tay transport cộng mã hóa TLS 1.3 một RTT 0-RTT khi nối lại connection ID đổi mạng wifi 4G không đứt kết nối, khám phá h3 qua Alt-Svc kiểm bằng curl client vào bằng h2 trước server trả header quảng cáo h3 alt-svc h3 443 ma 86400 lần sau client thử h3 curl --http3 cần curl build kèm h3 curl -sI grep alt-svc xem site có h3 không

Hình 1: HTTP/2 vẫn dính TCP head-of-line blocking (mọi stream chung một dòng TCP). HTTP/3 chạy trên QUIC (UDP) — mỗi stream độc lập, bắt tay 1 RTT, đổi mạng không đứt. Khám phá h3 qua Alt-Svc.

Đo thật (và những gì lab không chạy được)

curl trong lab build kèm nghttp2 nhưng không có HTTP/3, nên ta không thể gửi request h3 thật ở đây — báo trung thực điều đó và đo phần khả dụng:

Ảnh chụp bảng kết quả đo thật nền tối chạy curl 7.88 curl lab có HTTP2 nhưng không build kèm HTTP3 đo phần khả dụng báo trung thực, phần một curl lab không hỗ trợ h3 thành thật curl 7.88.1 nghttp2 1.52.0 có HTTP2 không có HTTP3 curl --http3 https ra curl option --http3 the installed libcurl version doesn't support this, phần hai site thật quảng cáo h3 qua Alt-Svc curl -sI https www.cloudflare.com grep alt-svc alt-svc h3 443 ma 86400 site có HTTP/3 client hiểu h3 sẽ chuyển, phần ba cái QUIC tiết kiệm bắt tay TCP cộng TLS tuần tự HTTP/2 DNS 0.005s TCP xong 0.030s TLS xong 0.060s HTTP/2 TCP khoảng 25ms rồi TLS khoảng 30ms bằng 2 vòng khứ hồi tuần tự QUIC HTTP3 gộp transport cộng crypto một RTT 0-RTT khi nối lại, phần bốn ba lợi thế cốt lõi của HTTP/3 hết TCP head-of-line blocking bắt tay nhanh hơn đổi mạng không đứt

Hình 2: curl lab (nghttp2, không HTTP3) — --http3 báo the installed libcurl version doesn't support this. Site thật quảng cáo alt-svc: h3=":443". Bắt tay HTTP/2: TCP xong ~30ms rồi TLS xong ~60ms — hai vòng tuần tự mà QUIC gộp còn một.

Đọc kết quả:

  • Trung thực về giới hạn lab: curl 7.88.1 có nghttp2 nhưng không HTTP3; ép --http3 → curl: option --http3: the installed libcurl version doesn't support this. Chạy h3 thật cần curl build kèm thư viện QUIC (quiche/ngtcp2) — không có sẵn ở đây, nên ta không bịa số h3.
  • Alt-Svc là cách khám phá h3: curl -sI https://www.cloudflare.com | grep alt-svc cho alt-svc: h3=":443"; ma=86400. Cơ chế: client kết nối bằng h2/h1 trước, server trả header Alt-Svc quảng cáo rằng nó cũng phục vụ h3 ở cổng 443/UDP với thời hạn nhớ ma (max-age) giây; lần sau client thử h3. (HTTP/3 không dùng ALPN-trong-TLS để "nâng cấp" như h2, vì nó ở UDP.)
  • Chi phí QUIC tiết kiệm: đo bắt tay HTTP/2 tới site thật — time_connect (TCP xong) ~30ms rồi time_appconnect (TLS xong) ~60ms. Đó là hai vòng khứ hồi tuần tự: TCP handshake trước, TLS handshake sau. QUIC gộp thiết lập vận chuyển và mã hóa (TLS 1.3) vào một vòng — và khi nối lại có thể 0-RTT (gửi dữ liệu ngay). Trên mạng độ trễ cao (di động), tiết kiệm một RTT là cảm nhận rõ.

Đánh đổi và lưu ý

HTTP/3 không phải lúc nào cũng nhanh hơn. Trên mạng ổn định ít mất gói, HTTP/2 đã rất tốt — lợi thế h3 rõ nhất khi mạng có mất gói (di động, wifi yếu) nơi TCP HoL blocking đau. Và QUIC chạy ở user space (không phải kernel như TCP) nên tốn CPU hơn một chút; ở quy mô cực lớn điều này đáng cân nhắc.

UDP đôi khi bị chặn. Một số mạng doanh nghiệp/tường lửa chặn hoặc bóp UDP cổng 443. Vì thế HTTP/3 luôn đi kèm fallback: client thử h3, không được thì quay về h2 trên TCP. Alt-Svc chính là cơ chế cho phép "thử h3 nhưng vẫn có đường lui".

Bật h3 chủ yếu ở tầng hạ tầng. Là lập trình viên ứng dụng, bạn hiếm khi "code" h3 — nó do server/CDN/reverse proxy (nginx bản mới, Cloudflare, Caddy) và trình duyệt lo. Việc của bạn thường là bật nó ở proxy/CDN và kiểm bằng alt-svc + công cụ (trình duyệt DevTools cột Protocol hiện h3).

Ba ý mang về

  1. HTTP/3 chạy trên QUIC (UDP) để xóa TCP head-of-line blocking: HTTP/2 vẫn dính vì mọi stream chung một dòng TCP (mất một gói chặn tất cả); QUIC cho mỗi stream độc lập ở tầng vận chuyển.
  2. QUIC gộp bắt tay transport + mã hóa: đo thật HTTP/2 cần TCP (~30ms) rồi TLS (~60ms) = 2 RTT tuần tự; QUIC gộp còn 1 RTT (0-RTT khi nối lại), cộng đổi mạng không đứt nhờ connection ID.
  3. Khám phá qua Alt-Svc, có fallback: site quảng cáo alt-svc: h3=":443" để client thử h3 rồi lui về h2 nếu UDP bị chặn; h3 lợi nhất trên mạng mất gói, và thường được bật ở CDN/proxy chứ không code tay (curl cần build kèm h3 mới thử được — lab này không có).

Nguồn

Phần sau ta xử lý thứ khiến mọi lập trình viên frontend từng phát điên: CORS — vì sao trình duyệt chặn request cross-origin, preflight OPTIONS, và các header Access-Control-*.