http/1 в Go 1.27
В Go 1.27 net/http начал автоматически переиспользовать HTTP/1-соединения, даже если вы не дочитали тело ответа.
Установка нового соединения (TCP + TLS handshake) стоит 2–3 RTT (Round-Trip Time), а это дороже самого запроса.
Поэтому клиент и сервер стараются переиспользовать соединения.
Но в HTTP/1 ответы идут по соединению строго друг за другом: следующий ответ нельзя начать читать, пока не прочитано тело текущего.
Если код читает только статус и заголовки, а затем делает resp.Body.Close(), не дочитав тело, net/http вплоть до Go 1.26 просто выбрасывал соединение и открывал новое. Это работало правильно, но медленно.
В наглядном примере из блога Go:
100 запросов к index.golang.org по HTTP/1 занимало ~710 мс на Go 1.26 против ~150 мс на Go 1.27, т.е. имеем почти 5-кратную разницу.
Go 1.27 теперь:
- асинхронно дочитывает непрочитанное тело ответа (до 50 мс или 256 КБ);
- не тратит время, если ответ содержит
Connection: close; - соединение возвращается в пул и используется повторно.
Если кратко, то сложность переиспользования соединений теперь берёт на себя стандартная библиотека. Код остаётся простым, а сетевые запросы быстрыми.
P.S. В HTTP/2 этой проблемы нет, т.к. мультиплексирование потоков не требует дочитывать тело.