Happy Eyeballs
Happy Eyeballs (RFC 8305, версия 2) — алгоритм, которым клиент параллельно пробует IPv4 и IPv6 (и разные IP-адреса от DNS) и использует то, что подключилось первым. Устраняет знаменитую проблему «сайт медленно грузится» когда IPv6 работает криво.
Проблема которую решает
DNS вернул A + AAAA. Клиент раньше делал так:
- Пробует IPv6 (AAAA).
- Таймаут коннекта (60 секунд).
- Фолбэк на IPv4 (A).
Юзер сидит и смотрит на белый экран 60 секунд. Не «happy».
Как работает Happy Eyeballs v2
- Одновременно резолвим A и AAAA. Что ответило первым — начинаем использовать.
- Первую попытку делаем на IPv6 (если есть).
- Через Resolution Delay (~50 мс) если IPv6 не соединился — начинаем параллельно на IPv4.
- Через Connection Attempt Delay (~250 мс) если ни один не соединился — переходим к следующему адресу из результата DNS.
- Первый успешный TCP-handshake (или QUIC 0-RTT) — используется. Остальные попытки RST-ятся.
В итоге медленный IPv6 не заставляет юзера ждать — параллельный IPv4 быстро подхватит.
Задержки по стандарту
| Параметр | Значение | Что означает |
|---|---|---|
| Resolution Delay | 50 мс | Задержка перед стартом IPv4-попытки после IPv6 |
| Connection Attempt Delay | 250 мс (реком. 100-2000) | Между попытками к разным IP |
| Minimum Connection Attempt Delay | 100 мс | Нижний предел |
| Maximum Connection Attempt Delay | 2000 мс | Верхний предел |
Address sorting
В RFC 6724 определён порядок сортировки адресов от DNS. Happy Eyeballs использует его, но с обязательным чередованием семейств (IPv6, IPv4, IPv6, IPv4...) чтобы не тратить весь пул попыток на одно семейство если оно сломано.
Happy Eyeballs для протоколов
RFC 8305 определяет базово только IPv4/IPv6. Позже расширения:
- Chrome с HTTP/3 — параллельно TCP+h2 и UDP+QUIC. Быстрейший выигрывает.
- MPTCP — параллельные попытки по нескольким интерфейсам (Wi-Fi + LTE).
- SCTP fallback — если поддерживается на обоих концах.
Реализации
- Chrome / Chromium — с 2011, версия v1. С 2019 — v2 с QUIC.
- Firefox —
network.dns.disablePrefetch = false,network.http.happy-eyeballs. - Safari / iOS / macOS — с iOS 5.
- curl — с 7.59 (2018), опция
--happy-eyeballs-timeout-ms. - Go —
net.Dialerимеет встроенный HE. - Windows — TCP Fast Fallback в winsock, аналог HE.
Как проверить
# Заставить curl подождать 500мс перед IPv4-фолбэком
curl --happy-eyeballs-timeout-ms 500 https://example.com
# Только IPv6
curl -6 https://example.com
# Посмотреть какой семейством ходит браузер
# В DevTools → Network → выбрать запрос → Remote Address
Побочный эффект — двойная нагрузка
Клиент открывает две попытки, одна из них потом RST. Крупные сервисы (Google, Cloudflare) получают ~5-10% лишних SYN-пакетов. С их масштабом — ощутимо, но приемлемая цена за user experience.