Go 1.27, 연결 재사용이 바뀌어도 Close는 필요하다
JSON은 끝까지 읽었는데 응답 끝에 남은 개행 하나 때문에 HTTP 연결이 다음 요청에 재사용되지 않았다. Go 1.27은 덜 읽은 본문을 어디까지 대신 비워 줄까?

- Go 1.27은 덜 읽은 HTTP/1 응답 본문을 Close 뒤에 제한적으로 비워 연결 재사용을 시도한다.
- 비우기에는 최대 50ms 또는 256KB라는 한도가 있으며, 모든 응답의 재사용을 보장하지 않는다.
- 개발자는 여전히 응답 본문을 닫고, Client와 Transport를 재사용해야 한다.
본문을 덜 읽어도 연결을 살릴 기회가 생겼다
Go 1.27의 HTTP 클라이언트는 사용자가 응답 본문을 닫을 때, 남은 내용을 백그라운드에서 제한적으로 읽어 버린다. 본문 끝까지 도달하면 같은 연결을 다음 요청에 사용할 수 있다. Go 팀이 10월 14일 공개한 해설은 8월에 출시된 1.27의 이 변경을 소개한다.
그전에는 HTTP/1 응답을 끝까지 읽지 않고 닫으면 연결을 버리는 경우가 있었다. 이제는 net/http.Transport가 재사용을 위한 뒷정리를 맡는다. 그렇다고 resp.Body.Close() 호출까지 없어지는 것은 아니다.
상태 코드만 봤거나 JSON 뒤 개행이 남았다면
HTTP/1에서는 같은 연결의 응답이 바이트 흐름으로 이어진다. 현재 응답의 본문이 어디서 끝나는지 알아야 다음 응답을 읽을 수 있다. 상태 코드만 필요한 프로그램도 서버가 함께 보낸 본문을 처리해야 연결을 다시 쓰기 쉬웠다.
변경을 제안한 Nicholas Husin은 구현 배경 이슈에서 JSON을 읽는 코드도 예외가 아니라고 설명했다. 디코더가 객체를 읽은 뒤 서버가 붙인 개행을 남기면 본문 끝에 도달하지 않은 상태가 될 수 있다. 응답의 의미를 이해한 것과 네트워크의 바이트를 끝까지 읽은 것은 다른 일이다.
HTTP/2는 여러 스트림을 한 연결에서 처리하므로 이 문제의 구조가 다르다. 한 응답에서 읽지 않은 본문 때문에 다른 요청까지 새 TCP 연결을 만들어야 하는 것은 아니다.
큰 응답을 끝없이 내려받지는 않는다
자동 비우기는 최대 50ms 또는 256KB 범위에서 이뤄진다. 공식 해설은 남은 본문이 크거나 천천히 도착하면 읽어 버리는 비용이 새 연결을 만드는 비용보다 커질 수 있다고 설명한다.
| 상황 | Go 1.27에서의 의미 |
|---|---|
| HTTP/1 본문을 덜 읽고 닫는다. | 제한 안에서 남은 내용을 비워 재사용을 시도한다. |
| 본문이 크거나 느리게 도착한다. | 양·시간 한도를 넘겨 계속 읽지는 않는다. |
응답에 Connection: close가 있다. | 재사용할 수 없으므로 비우기를 생략한다. |
백그라운드 작업인 만큼 Close() 직후 다음 요청이 반드시 같은 연결을 잡는다는 뜻도 아니다. 비우기를 마친 연결은 이후 요청에 재사용될 수 있다.
Close는 남기고 Client·Transport 설정을 살핀다
net/http 문서는 사용을 마친 응답 본문을 호출자가 닫아야 한다고 명시한다. 대부분의 경우 재사용만을 위해 본문을 끝까지 직접 읽는 처리는 필요하지 않지만, 닫기 의무는 그대로다. Client와 Transport 역시 필요할 때마다 새로 만들기보다 재사용하는 것이 기본이다.
1.27 릴리스 노트는 유휴 연결을 과도하게 남기는 잘못된 설정에서 드물게 성능이 나빠질 수 있다고 설명한다. MaxIdleConns를 0으로 두거나 요청마다 서로 다른 Client를 쓰는 구성을 예로 든다. 특히 자체 Transport를 생성하는 코드라면 연결 풀이 어떻게 공유되는지 함께 봐야 한다.
DisableKeepAlives를 켜면 연결 재사용을 끌 수 있다. 다만 릴리스 노트는 이런 성능 저하가 Client·Transport의 부적절한 사용을 드러내는 경우가 많다고 설명한다. 기존 drain 보조 함수를 걷어내기 전에, 실행 버전과 본문을 닫는 경로, 연결 풀 구성을 먼저 맞춰 보는 것이 순서다.
자주 묻는 질문
Go 1.27이면 Body.Close를 생략해도 되나?
아니다. 응답 본문을 닫는 것은 호출자의 책임이다. 자동 비우기는 닫을 때 시작하는 제한적 처리다.
모든 HTTP 요청이 더 빨라지는가?
아니다. 이번 변경은 HTTP/1에서 남은 본문 때문에 놓치던 연결 재사용을 돕는다. 이미 연결을 재사용하던 코드나 HTTP/2에 같은 효과를 적용할 수 없다.