
Go 1.28 개발판의 HTTP/2 주차(parking) 기능은 유휴 연결을 처리하는 고루틴을 작업이 없을 때 종료하고, 새 작업이 생기면 새 고루틴이 이어받도록 한다. 한 벤치마크에서 유휴 연결 5,000개를 둔 서버는 주차 기능을 켰을 때 끈 경우보다 RSS가 약 85~93MiB 낮았지만, 이 결과는 특정 개발판과 시험 조건에 한정된다.
기능과 측정 조건
HTTP/2 연결은 활성 스트림이 없어도 열린 상태로 남을 수 있다. 기존 서버에서는 연결을 처리하는 고루틴이 serveLoop에서 대기했지만, Go 1.28 개발 코드는 안전 조건이 충족되고 처리할 작업이 없으면 이 고루틴을 종료할 수 있다. 새 작업이 도착하면 새 고루틴이 serveLoop를 실행한다. 핸들러가 실행 중이어도 serveLoop에 당장 처리할 일이 없으면 주차될 수 있지만, 모든 연결이나 실행 중인 핸들러가 주차되는 것은 아니다.
주차는 Go 구현 내부의 명칭이며 공개 API가 아니다. 시험에 사용한 GODEBUG=http2serveparking=0도 임시·비공개 설정이므로 이후 버전에서 안정적으로 쓸 수 있는 옵션으로 보면 안 된다.
측정은 같은 벤치마크 코드와 장비에서 세 구성을 비교했다. Go 1.27.2, 주차를 켠 Go 1.28 개발판, 그리고 GODEBUG=http2serveparking=0으로 주차를 끈 같은 Go 1.28 바이너리다. 시험한 Go 1.28 리비전은 5c51011e82ed754af072baaf4338ff35e76fe705이며, 벤치마크 코드는 86753bd4d1f79621a4f3c6927c8239419e54bde2 커밋으로 고정했다.
각 구성에서 유휴 HTTP/2 연결 0개, 1,000개, 5,000개를 측정했다. 연결 수별로 열 차례씩 측정하는 전체 실험을 같은 Linux 장비에서 세 번 반복하고, 연결이 안정된 뒤의 표본 중앙값을 사용했다. 장비는 Intel Core i7-1265U, Linux 6.18.56, 약 32GiB 메모리였으며 GOMAXPROCS=12, GOGC=100으로 설정했다. 측정 전에 강제로 가비지 컬렉션을 실행하지 않았다.
RSS는 Linux가 보고하는 프로세스 상주 메모리, 고루틴 수는 Go 런타임이 보고하는 고루틴 개수다. StackInuse는 사용 중인 고루틴 스택 메모리, HeapAlloc은 런타임이 보고하는 할당 힙 메모리를 나타낸다. 각 지표는 서로 다른 값을 측정한다.
측정 결과와 해석
연결 5,000개에서 RSS 차이가 가장 컸다. 아래는 각 전체 실행에서 얻은 RSS 중앙값이며, 단위는 MiB다.
| 실행 | Go 1.27.2 | Go 1.28 주차 끔 | Go 1.28 주차 켬 | 주차로 줄어든 양 |
|---|---|---|---|---|
| 1 | 249.89 | 218.28 | 129.19 | 89.08 |
| 2 | 247.18 | 223.73 | 131.11 | 92.62 |
| 3 | 245.60 | 217.94 | 133.25 | 84.70 |
같은 Go 1.28 바이너리에서 주차를 켜자 RSS가 세 차례 실행에서 84.7~92.6MiB, 약 38.9~41.4% 줄었다. 연결 1,000개에서는 감소 폭이 약 15.7~16.6MiB였다. 연결이 없는 기준 RSS는 구성별로 약 8.5~8.7MiB였다. 연결이 늘면서 발생한 메모리 증가를 보기 위해 기준 RSS를 뺀 값도 계산했지만, 주요 비교는 실제 측정된 프로세스 RSS를 기준으로 했다.
고루틴 수와 스택 메모리도 같은 방향으로 변했다. 연결 5,000개에서 주차를 끄면 고루틴이 약 10,007개, 켜면 약 5,007개로 측정됐다. 이 벤치마크에서는 차이가 정확히 5,000개였다. 연결 1,000개에서는 차이가 1,000개였다. 연결 5,000개일 때 StackInuse는 주차를 끄면 약 99MiB, 켜면 약 21MiB였으며, 세 차례 실행에서 감소량은 약 78MiB였다.
이 결과만으로 RSS 감소분 전체가 스택에서 비롯됐다고 볼 수는 없다. RSS에는 Go 스택 외에도 힙, 런타임 상태, 운영체제의 영향이 반영될 수 있다. HeapAlloc 결과도 일정하지 않았다. 어떤 실행에서는 주차를 켰을 때 힙 사용량이 더 적었지만, 다른 실행에서는 약간 더 많았다. 따라서 일정한 힙 절감량이나 전체 메모리의 고정 비율이 항상 줄어든다고 해석해서는 안 된다.
적용 범위와 한계
이 측정은 한 대의 장비와 하나의 벤치마크 설계, Go 1.28의 특정 개발 리비전을 대상으로 했다. 정식 Go 1.28 릴리스 결과가 아니며, 실제 트래픽이나 활성 스트림, 애플리케이션 부하가 섞인 환경이 아니라 대부분 유휴 연결을 시험했다. 같은 Go 1.28 바이너리에서 주차 설정만 바꿔 비교했지만 시스템 잡음이 완전히 제거된 것은 아니다. 세 차례 실행에서 반복되는 경향과 범위를 보여줄 뿐, 모든 환경에 적용되는 보장은 아니다.
고정 커밋의 벤치마크 소스와 시험한 Go 리비전을 확인할 수 있다. 유휴 HTTP/2 연결을 많이 유지하는 서버를 운영한다면 이 변경을 실제 작업 부하에서 측정해 보는 것이 적절하다.
댓글 (0)
로그인하면 이 기사에 내 생각을 남길 수 있어요