Go 1.27의 HTTP/1 연결 재사용 개선

1 hour ago 3

Go 1.27의 net/http.Transport는 응답 본문을 닫을 때 읽지 않은 데이터가 남아 있으면 백그라운드에서 읽어 버려, HTTP/1 연결을 재사용할 수 있도록 함 자동으로 읽어 버리는 범위는 최대 50ms 또는 256KB로 제한하며, Connection: close 헤더가 있는 응답은 이 작업을 건너뜀 HTTP/1에서는 현재 응답 본문을 끝까지 읽어야 다음 응답의 시작을 찾을 수 있음. Go 1.26까지는 본문을 덜 읽고 닫으면 기존 연결을 폐기해 연결 수립 비용이 반복됨 HTTP/1로 index.golang.org에 상태 코드만 확인하는 요청을 100회 보낸 예제는 측정 환경에서 Go 1.26 약 710ms, Go 1.27 약 150ms로 거의 5배 빨라짐 이제는 본문이 더 필요하지 않을 때 닫기만 하는 방식을 권장함. HTTP/2는 스트림을 다중화하므로 연결 재사용을 위해 남은 본문을 읽어 버릴 필요가 없음 새 연결을 만드는 비용 Go의 net/http는 HTTP/1.0, HTTP/1.1, HTTP/2를 지원하며, 모두 TCP 위에서 동작하고 HTTPS 엔드포인트와 통신할 때는 보통 TLS도 사용함 TLS 1.2를 사용하는 새 연결에서는 HTTP 요청을 보내기까지 총 3 RTT가 필요함 TCP 연결은 SYN, SYN-ACK, ACK 순서로 수립하며, 마지막 ACK에 첫 TLS 메시지를 함께 보낼 수 있어 1 RTT가 걸림 TLS 핸드셰이크는 암호화 키를 교환하고 서버 신원을 검증하며 2 RTT가 걸림 리전 간 통신에서는 편도 지연이 50ms 이상인 경우가 흔함. RTT가 100ms라면 연결 설정에만 300ms가 들고, TLS 핸드셰이크의 CPU 비용도 추가됨 대역폭이 충분하거나 응답이 작으면 실제 HTTP 요청 처리는 1 RTT를 조금 넘는 시간에 끝날 수 있음 도입부의 예제는 http.Get으로 요청한 뒤 본문을 읽지 않고 defer resp.Body.Close()로 닫으며 상태 코드만 반환함 GODEBUG=http2client=0으로 HTTP/1을 사용해 index.golang.org에 100회 요청했을 때, 해당 측정 환경에서 Go 1.26은 약 710ms, Go 1.27은 약 150ms가 걸림 이 엔드포인트는 전 세계에 분산되어 지연이 비교적 낮고, TLS 1.3을 지원해 TLS 핸드셰이크도 1 RTT에 끝나지만 성능 차이가 뚜렷했음 HTTP 버전별 연결 재사용 방식 HTTP/1.0은 공...

Read Entire Article