Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «HTTP/2 проти HTTP/3: еволюція протоколу». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**HTTP/2 проти HTTP/3**: HTTP/2 мультиплексує потоки через одне TCP-з'єднання, але втрачений TCP-пакет блокує всі потоки. HTTP/3 використовує QUIC поверх UDP, де кожен потік відновлюється незалежно. ```bash curl -I --http2 https://site.com # → HTTP/2 200 curl -I --http3 https://site.com # → HTTP/3 200 ``` **Ключова різниця:** HTTP/3 усуває HOL-блокування на рівні TCP-пакетів через QUIC, що найбільше відчутно на мобільних мережах з втратою пакетів понад 1%.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**HTTP/2** мультиплексує запити через одне TCP-з'єднання; **HTTP/3** замінює TCP на QUIC (Quick UDP Internet Connections) поверх UDP і вирішує проблему блокування на рівні пакетів, яку TCP не може обійти. ## Теорія ### TL;DR - HTTP/2 — спільна магістраль: всі машини їдуть паралельно, але одна поламана машина блокує весь потік. HTTP/3 дає кожній машині окрему дорогу. - Головна різниця: в HTTP/2 залишається HOL-блокування (head-of-line) на рівні TCP-пакетів. HTTP/3 використовує QUIC, де кожен потік відновлюється незалежно. - На стабільних мережах HTTP/2 і HTTP/3 порівняні. При 3% втраті пакетів HTTP/3 тримає понад 90% пропускної здатності, тоді як HTTP/2 падає на 40%. - Правило вибору: внутрішня мережа або стабільний LAN → HTTP/2. Мобільний трафік, відеопотоки, глобальний трафік → HTTP/3. ### Швидкий приклад ```bash # Перевіряємо протокол сервера curl -I --http2 https://yourdomain.com # → HTTP/2 200 curl -I --http3 https://yourdomain.com # → HTTP/3 200 # У Chrome DevTools: вкладка Network → колонка Protocol # Шукайте "h2" або "h3" ``` ```javascript // Node.js: логуємо активний протокол для кожного запиту app.use((req, res, next) => { const v = req.httpVersion; const proto = v >= '3' ? 'h3' : v === '2.0' ? 'h2' : 'h1'; console.log(`${proto}: ${req.path}`); next(); }); // Вивід: h3: /api/feed (коли HTTP/3 активний) ``` Переговори про протокол відбуваються через ALPN під час TLS handshake. Браузер і сервер домовляються про `h2` або `h3` ще до першого запиту. ### Ключова різниця: HOL-блокування на рівні TCP HTTP/2 вирішив проблему HOL-блокування HTTP/1.1, запустивши потоки (streams) в одному TCP-з'єднанні. Але TCP гарантує строгий порядок байтів. Якщо один пакет губиться, всі потоки зупиняються в черзі, навіть ті, яких цей пакет не стосується. Це і є TCP packet-level HOL blocking. HTTP/3 переносить мультиплексування всередину QUIC, який працює поверх UDP. QUIC призначає кожному потоку власне відновлення після втрати. Загублена UDP-датаграма блокує тільки свій потік. Решта продовжує роботу. При 5% втраті пакетів HTTP/2 втрачає близько 40% пропускної здатності, HTTP/3 тримається вище 90%. ### Коли що обрати - Стабільний LAN або корпоративна мережа → HTTP/2. TCP справляється, HOL рідко спрацьовує, налаштування простіше. - Мобільні користувачі зі змінними мережами → HTTP/3. QUIC відновлюється після втрати пакетів по потоках, а не по всьому з'єднанню. - Відеопотоки → HTTP/3. YouTube скоротив перебуферизацію на мобільних на 10%, Netflix зменшив час до першого кадру на 25%. - API з малими пейлоадами → HTTP/2. HPACK-стиснення заголовків дає реальний ефект, а QUIC додає 20% навантаження на CPU на ARM-серверах без відчутного виграшу. - За Cloudflare або великим CDN → HTTP/3 вже увімкнений за замовчуванням. - Корпоративні файрволи → HTTP/2 як запасний варіант. UDP 443 часто заблокований, і QUIC автоматично перемикається на h2. ### Таблиця порівняння | Характеристика | HTTP/2 | HTTP/3 | |---|---|---| | **Транспорт** | TCP | QUIC поверх UDP | | **Мультиплексування** | Так, потоки в одному TCP | Так, потоки повністю незалежні | | **HOL-блокування** | На рівні потоків вирішено, пакетний залишається | Відсутнє - відновлення по потоках | | **Handshake** | TCP + TLS (2-3 RTT) | QUIC + TLS 1.3 (1 RTT, 0-RTT при відновленні) | | **Стиснення заголовків** | HPACK | QPACK | | **Міграція з'єднання** | Ні - прив'язка до IP+порт | Так - Connection ID виживає при зміні мережі | | **Шифрування** | Опціональне (TLS) | Обов'язкове (TLS 1.3 вбудований) | | **Підтримка браузерів (2025)** | 98% | 92% (Chrome 91+, Firefox 88+, Safari 14+) | | **Навантаження на CPU** | Базове | ~20% більше на ARM через QUIC | | **Найкраще для** | Стабільні мережі, швидке налаштування | Мобільні, стрімінг, мережі з втратами | ### Як це працює всередині Браузер надсилає розширення ALPN під час TLS handshake зі списком підтримуваних протоколів (`h2`, `h3`). Сервер вибирає один і відповідає. Для HTTP/2 Chromium парсить вхідні байти як HPACK-стиснені HEADERS та DATA фрейми, прив'язані до stream ID на TCP-сокеті. Для HTTP/3 стек переходить на QUIC. Кожен QUIC-пакет містить stream ID. `quic::QuicConnection` в Chromium обробляє UDP-датаграми та підтверджує кожен потік незалежно через selective ACK, пропускаючи заблоковані потоки замість очікування. Функція 0-RTT кешує ключі шифрування сервера з попередньої сесії, і при повторному підключенні клієнт надсилає HTTP-запит у першому ж пакеті. Сервер оголошує підтримку HTTP/3 через заголовок `Alt-Svc`: ``` Alt-Svc: h3=":443"; ma=86400 ``` Конфіг nginx для одночасного увімкнення обох протоколів: ```nginx listen 443 ssl; http2 on; http3 on; ssl_protocols TLSv1.3; add_header Alt-Svc 'h3=":443"; ma=86400'; ``` ### Типові помилки **Увімкнення HTTP/3 без відкриття UDP 443 на файрволі.** QUIC використовує UDP-порт 443. Корпоративні файрволи часто блокують весь UDP. Результат: браузер перемикається на HTTP/2, помилки немає, і ти годинами дивишся чому в DevTools немає h3. ```bash # Відкриваємо UDP 443 на Linux iptables -A INPUT -p udp --dport 443 -j ACCEPT # Перевіряємо доступність QUIC curl --http3 https://yoursite.com # Якщо бачиш: curl: (92) HTTP/3 not supported # UDP заблоковано або занадто малий буфер сокета: sysctl net.core.rmem_max=2500000 ``` **Плутанина між HPACK і QPACK.** HTTP/2 використовує HPACK зі спільною динамічною таблицею для всіх потоків з'єднання. HTTP/3 використовує QPACK з таблицями на рівні кожного потоку, щоб не відтворювати HOL на рівні стиснення. Якщо перенести HPACK-логіку h2-сервера на h3, отримаєш баги з витісненням записів і потенційне подвоєння розміру заголовків. В nginx явно прописуй `http3_qpack_blocks 16384;`. **Очікування що QUIC завжди швидший.** На стабільних мережах з великою пропускною здатністю QUIC додає CPU-навантаження без приросту throughput. API з малими пейлоадами на добре підключених серверах можуть деградувати. Бенчмаркуй перед переходом. **Ігнорування ризиків 0-RTT replay.** QUIC 0-RTT відновлює зашифровану сесію в першому пакеті. Але ці дані може відтворити зловмисник у мережі. Cloudflare обмежує 0-RTT тільки GET-запитами і не застосовує до POST/PUT. Якщо у тебе є GET-ендпоінти зі зміною стану, це важливо врахувати. **Відсутність тесту h2-fallback в навантажувальних тестах.** Близько 8% користувачів ще не мають підтримки HTTP/3. Якщо навантажувальний тест запускається тільки через Chrome з h3, ти не бачиш патерни h2-трафіку, включно з TCP HOL-спайками при перевантаженні. ### Де зустрічається в реальних проектах - Cloudflare маршрутизує 80% трафіку через HTTP/3, включно з бекендами Discord-ботів. - YouTube використовує h3 на мобільних і скоротив перебуферизацію приблизно на 10%. - Netflix доставляє відеочанки через h3 і зменшив медіанний час до першого кадру на 25%, відкривши реалізацію як `quic-go`. - Next.js 14+ визначає активний протокол для streaming SSR-відповідей. - Deno Deploy використовує HTTP/3 за замовчуванням для всіх edge-деплоїв. ### Питання на співбесіді **Q:** Що таке HOL-блокування (head-of-line blocking) в HTTP/2 та HTTP/3? **A:** В HTTP/2 втрачений TCP-пакет зупиняє всі потоки на з'єднанні, доки TCP не повторить передачу. В HTTP/3 QUIC відновлює втрати по потоках, тому зупиняється тільки постраждалий потік. **Q:** Як QUIC-handshake перевершує TCP + TLS? **A:** TCP потребує тристоронньої схеми перед стартом TLS. QUIC поєднує транспортний і крипто-обмін в один раунд: 1 RTT для нових з'єднань, 0-RTT для відновлення де ключі кешовані з попередньої сесії. **Q:** Що таке QPACK і навіщо він потрібен в HTTP/3 замість HPACK? **A:** HPACK використовує спільну динамічну таблицю для всіх потоків. В HTTP/3 потоки незалежні, тому спільна таблиця відтворила б HOL на рівні стиснення заголовків. QPACK тримає таблиці per-stream щоб цього уникнути. **Q:** Що відбувається коли корпоративний файрвол блокує UDP 443? **A:** Браузер пробує QUIC, отримує відмову і автоматично перемикається на HTTP/2 через TCP. Користувач не бачить помилки, в логах немає h3-трафіку. Перевіряй заголовок `Alt-Svc` і доступність UDP через Wireshark (фільтр: `quic`). **Q (senior):** При 5% втраті пакетів — яка різниця у throughput між HTTP/2 і HTTP/3 кількісно? **A:** За даними дослідження Google QUIC, HTTP/2 втрачає близько 40% throughput через TCP tail-loss і таймаути перепередачі. HTTP/3 з QUIC selective ACK тримає понад 90%. Різниця: TCP блокує ціле з'єднання на одній втраті, QUIC відновлюється локально в потоці. ## Приклади ### Вплив HOL-блокування на паралельні запити Найпростіший спосіб побачити блокування в дії — Chrome DevTools з мережевим throttling на 3G. ```javascript // 10 паралельних запитів до ресурсів // HTTP/2: всі зупиняться якщо TCP втратить пакет // HTTP/3: тільки постраждалий потік призупиниться const urls = Array.from({ length: 10 }, (_, i) => `/api/item/${i}`); const start = performance.now(); const results = await Promise.all( urls.map(url => fetch(url).then(r => r.json())) ); console.log(`Усі 10 завантажено за ${(performance.now() - start).toFixed(0)}ms`); // При 1% втраті пакетів (throttling у DevTools): // HTTP/2: ~4500ms (TCP HOL спрацьовує) // HTTP/3: ~2800ms (потоки відновлюються незалежно) ``` Стеж за колонкою Protocol у DevTools. Запити з міткою `h3` завершуються більш рівномірно порівняно з `h2` в умовах слабкого сигналу. ### Міграція з'єднання в QUIC Ця функція найбільше важлива для мобільних застосунків, але їй приділяють найменше уваги. ```javascript // HTTP/2 (TCP): при перемиканні WiFi на 4G змінюється IP // TCP-з'єднання прив'язане до IP+порт: новий handshake, новий TLS, ~500ms затримка // HTTP/3 (QUIC): використовує Connection ID, а не IP+порт // При зміні мережі QUIC-сесія продовжується з тим самим ID // Connection ID: abc123 // WiFi: 192.168.1.5:443 → З'єднання: abc123 // 4G: 10.0.0.15:443 → З'єднання: abc123 (та сама сесія, без повторного handshake) // Для відеозастосунку: відтворення не переривається // коли користувач виходить із зони WiFi ``` Я бачив на практиці як це спричиняє непомітні баги з токенами авторизації прив'язаними до IP: сервер бачить той самий Connection ID, але нову IP-адресу, і деякий auth-middleware позначає це як спробу перехоплення сесії. Перевір що робить твій middleware зі зміною IP перед тим як вмикати QUIC в продакшені. ### Числа продуктивності по сценаріях втрати пакетів ``` Втрата пакетів 0%: HTTP/2: ~2500ms HTTP/3: ~2300ms (мінімальний приріст) Втрата пакетів 1%: HTTP/2: ~4500ms (TCP HOL починає впливати) HTTP/3: ~2800ms (QUIC відновлюється по потоках) Втрата пакетів 3% (типове перевантаження 3G/4G): HTTP/2: ~8500ms HTTP/3: ~3500ms (в 2.4 рази швидше) ``` Ці цифри з контрольованих навантажувальних тестів. Реальні результати залежать від відстані до сервера і CDN-ноди, але закономірність зберігається: перевага HTTP/3 зростає зі збільшенням втрат пакетів і зникає на чистих мережах.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.