Go는 아주 쉽고 빠르게 HTTP 기능들을 구현할 수 있지만
성능 요구사항이 높아지다 보면 TIME_WAIT 등 자주 접하는 문제들이 있으며
자연스럽게 Go HTTP 튜닝 방법을 찾게 됩니다.
이번 포스팅에선 일반적인 Go HTTP 옵션들을 정리해봤습니다.
1. HTTP 통신을 위한 프로세스당 FD 개수 한도 설정
일반적으로 다음과 같이 리눅스가 설치되고 시스템 자원의 한도 값 중 프로세스당 FD의 개수에 대한 한도 값을 보면 다음과 같이 1024로 설정되어 있습니다.
$> ulimit -n
1024
HTTP는 프로토콜의 특성상 TCP의 연결이 자주, 많이 발생하므로 1024는 부족해서, 조금만 트래픽 부하를 주어도 'Too many open files'와 같은 오류를 발생시킬 수 있습니다. 따라서 이 값을 충분히 늘려주어야 합니다.
다음과 같이 /etc/security/limits.conf에 시스템 전체에 대한 프로세스당 사용 가능한 fd의 개수를 충분히 설정할 것을 권고합니다. (user별로 할 수도 있으나)
/etc/security/limits.conf
* soft nofile 81920
* hard nofile 81920
$> service sshd restart
이후 접속된 shell에서는 다음과 같이 최대 fd의 개수가 늘어났음을 볼 수 있습니다. 설정이 되었으면 다음과 같은 명령을 수행해 해당 한도 값을 사용하도록 할 수 있습니다.
$> ulimit -n
81920
2. HTTP 1.1 Client Options
HTTP 1.1에서 Client의 성능을 최대한 내기 위해서는 다음과 같은 HTTP 모듈의 값을 적절히 조절해야 합니다.
설정 옵션 | 설명 | 설정 안내 |
http.Transport. MaxIdleConns |
모든 Host들에 대해 최대 유휴(keep-alive) Connection의 개수, 0 제한 없음 | 기본값, DefaultTransport=100개 |
http.Transport. MaxIdleConnPerHost |
Host 당 최대 유휴(keep-alive) Connection의 개수 0으로 설정할 경우 DefaultMaxIdleConnsPerHost 값을 사용 |
기본값은 2로 설정되어 있기 때문에 , 성능시험을 할 경우 , 순간적으로 idle conn per host 가 2 이상이 되는 경우가 많아 계속 접속을 끊고, TIME_WAIT 가 발생하게 됩니다. 반드시 100개 이상의 적절한 값으로 설정하기 바랍니다. |
http.Transport. MaxConnPerHost |
Host 당 최대 connection의 수 제한 | 너무 과도한 connection이 연결될 경우, 서버, 클라이언트 모두 성능이 저하될 수 있으므로 적절한 값 설정 필요. HTTP 1.1의 경우 시험 결과 512가 1024개 보다 더 효율적 |
http.Transport. TLSHandshakeTimeout |
TLS Handshake를 기다리는 최대 시간, 0 제한 없음 | 기본값. DefaultTransport=10초 |
http.Transport. IdleConnTimeout |
유휴 connection이 close 될 때까지 기다리는 최대 시간, 0 제한 없음 | 기본값. DefaultTransport=90초 |
http.Transport. ResponseHeaderTimeout |
Request 전송 후 response 헤더를 기다리는 시간. 설정되지 않으면 사용하지 않음 | 기본값 |
http.Transport. MaxResponseHeaderBytes |
서버로 부터 수신된 Response 헤더로 가용한 최대 크기 | 기본값 |
net.Dialer.Timeout | Connection Timeout | 기본값, 보통 30초 |
net.Dialer.Deadline | 연결 실패에 대해 절대 시점 지정. Timeout 값이 설정되면 더 일찍 실패 할 수 있음. 0은 Deadline이 없거나, Timeout 옵션과 같은 OS 값을 따른다. | 기본값, 보통 30초 |
net.Dialer.KeepAlive | 활성화된 연결에 대한 keep-alive 주기 | 기본값. (OS가 지원하면 enable 됨) |
http.Client.Timeout | Request 전송 후 응답을 기다리는 제한 시간을 설정 | 지연이 예상될 경우, 적절한 값 설정 필요. |
3. HTTP 1.1 Server Options
HTTP 1.1 서버에서 성능을 최대한 내기 위해서는 다음과 같은 HTTP 모듈의 값을 적절히 조절 해야 합니다.
설정 옵션 | 설명 | 설정 안내 |
http.Server.ReadTimeout | body를 포함한 전체 request를 읽기 위한 최대 주기 | 큰 데이터가 들어오는 경우, 충분한 값으로 설정 필요 |
http.Server. ReadHeaderTimeout |
HTTP header를 모두 읽기 위해 허용된 최대 시간 | 기본값 권고 |
http.Server.WriteTimeout | 응답을 보내기 위해 허용되는 최대 시간 | 큰 데이터가 응답되는 경우, 충분한 값으로 설정 필요 |
http.Server.IdleTimeout | HTTP 연결 keep-alive일 때 다음 request를 기다리는 최대 시간 | 기본값 권고 |
http.Server.MaxHeaderBytes | Request 헤더의 최대 허용 크기 | 기본값 권고 |
4. HTTP/2 Client Options
HTTP/2에서 Client의 성능을 최대한 내기 위해서는 다음과 같은 HTTP 모듈의 값을 적절히 조절 해야 합니다.
설정 옵션 | 설명 | 설정 안내 |
http2.Transport. MaxHeaderListSize |
intial setting frame의 SETTINGS_MAX_HEADER_LIST_SIZE에 설정할 값 얼마나 큰 크기의 헤더 사이즈를 허용할지 설정, 기본 값 10MB |
기본값 |
http2.Transport. StrictMaxConcurrentStreams |
서버의 SETTINGS_MAX_CONCURRENT_STREAMS를 전역 적으로 사용할지 여부를 제어 False이면, 연결 당 SETTINGS_MAX_CONCURRENT_STREAMS 제한을 유지하기 위해 서버에 새 TCP 연결이 생성 True이면, 서버의 SETTINGS_MAX_CONCURRENT_STREAMS을 전역적 제한으로 해석하고, 필요시 RoundTrip 블록의 호출자가 자기 차례를 기다림. |
성능을 위해서는 False, Max Concurrent Stream이 꽉 차면 연결을 새로 맺어야 성능에 유리 |
5. HTTP/2 Server Options
HTTP/2 서버에서 성능을 최대한 내기 위해서는 다음과 같은 HTTP 모듈의 값을 적절히 조절 해야 합니다.
설정 옵션 | 설명 | 설정 안내 |
http2.Sever.MaxHandlers | 모든 연결에서 한 번에 실행될 수있는 http.Handler ServeHTTP goroutines의 수를 제한 | 기본값 |
http2.Sever. MaxConcurrentStreams |
동시에 각 클라이언트에서 동시에 사용할 수 있는 최대 stream의 개수, 기본 값은 적어도 100 이상 | 이 값을 초과하면 클라이언트에서 새로운 연결을 시도하므로 적절하게 큰 값을 줄 필요 있음. (예: 4000) |
http2.Sever. MaxReadFrameSize |
읽을 수 있는 최대 HTTP/2 프레임의 크기. 16k에서 16M 사이 값 | 기본값 |
http2.Sever.IdleTimeout | IDLE(유휴) 클라이언트를 GOAWAY로 닫아야 하는 시간을 지정 | 기본값 |
http2.Sever. MaxUploadBufferPerConnection |
연결 당 초기 flow control window의 크기. 65535보다 크고 2^32-1보다 작은 값 | 기본값 |
http2.Sever. MaxUploadBufferPerStream |
stream 당 초기 flow control window의 크기. 65535보다 크고 2^32-1보다 작은 값 | 기본값 |
'Programming > Go' 카테고리의 다른 글
[ko]Wire-Jacket: IoC Container of google/wire for cloud-native (0) | 2021.10.07 |
---|---|
Go/Golang Release & pkg.go.dev package update (0) | 2021.10.06 |
Go/Golang Dependency Injection (12) | 2021.09.10 |
Go/Golang Scheduling (8) | 2021.09.02 |
Go/Golang Test (2) | 2021.08.26 |