6호04 / 05
Go 1.27 — 읽지 않은 HTTP/1 응답 본문을 Transport가 알아서 비운다, 100회 요청이 710ms에서 150ms로
원문 Go Blog ↗
Go 블로그, 10월 14일, Nicholas Husin과 Damien Neil. Go 1.27의 net/http 변경을 설명합니다.
문제
HTTP/1은 한 연결에 응답이 순서대로 옵니다. 다음 응답을 읽으려면 이전 응답 본문을 끝까지 읽어야 합니다. Go 1.26까지 Transport는 본문을 다 읽지 않은 채 Body.Close()를 부르면 연결을 버리고 새 연결을 맺었습니다. TLS 핸드셰이크를 포함한 비용입니다.
걸리는 코드는 흔합니다.
- 상태 코드만 보고 본문은 읽지 않는 코드
json.Decoder로 디코딩한 뒤 Close — 디코더가 끝의 개행 문자를 남겨 "다 읽지 않음"이 됨
그래서 많은 팀이 io.Copy(io.Discard, resp.Body)를 Close 전에 넣는 헬퍼를 두고 있었습니다. HTTP/2는 스트림 다중화라 이 문제가 없습니다.
변경
1.27의 Transport는 읽지 않은 HTTP/1 본문을 비동기로 드레인합니다. 한도는 50ms 또는 256KB — 그 안에 다 읽히면 연결을 재사용하고, 넘으면 버립니다. 응답에 Connection: close가 있으면 어차피 버릴 연결이므로 드레인하지 않습니다.
수치
GODEBUG=http2client=0으로 HTTP/1을 강제하고 index.golang.org에 100회 요청: Go 1.26 약 710ms, Go 1.27 약 150ms. 저자 머신, 저지연, TLS 1.3 조건입니다.
글에 없는 것
이 동작을 끄는 방법은 없습니다. 드레인 한도(50ms/256KB)를 조정하는 설정도 없습니다. 글은 이 동작이 향후 버전에서 바뀔 수 있다고만 밝힙니다.
실무에서 할 일
1.27로 올리면 수동 드레인 헬퍼를 지워도 됩니다. 글의 권고도 "직접 드레인하지 말고 다 쓰면 Close하라"입니다. HTTP/2에서는 애초에 불필요한 작업이었습니다.
주의할 점 하나. 큰 본문을 일부러 안 읽고 끊던 코드 — 예를 들어 헤더만 보고 큰 파일 다운로드를 중단하는 코드 — 는 이제 최대 50ms 또는 256KB를 더 읽습니다. 대부분 무시할 수준이지만, 그런 패턴이 핫패스에 있으면 한 번 재보세요.
6호의 다른 글
요약으로 한 번에 보기 →- 01Telegram Desktop 원클릭 계정 탈취 — 링크 하나로 세션 파일을 빼간다, 조용히 고쳐졌다
- 02광고 타겟팅이 스파이웨어 배달 경로가 됐다 — Citizen Lab의 AdFection 보고서
- 03"패스키는 함정이다" vs "아니다" — 논쟁의 실제 쟁점은 어테스테이션 하나
- 04Go 1.27 — 읽지 않은 HTTP/1 응답 본문을 Transport가 알아서 비운다, 100회 요청이 710ms에서 150ms로지금 읽는 글
- 05윤초가 끝난다 — 2027년 5월 20일부터 연속 UTC, UT1과의 허용 차이는 1시간
2026년 10월 15일에 올라온 글
그날 대시보드 →댓글
불러오는 중…