# golang 기본 클라이언트 transport 의 기본 설정은
# 한개의 호스트에 Idle Connections(time_wait)를 2개로 제한되어 있다.
# 이를 변경해서 time_wait 를 줄일 수 있다.
# 참고
http://tleyden.github.io/blog/2016/11/21/tuning-the-go-http-client-library-for-load-testing/
# 테스트 내용
https://github.com/ysoftman/test_code/blob/develop/golang/max_idle_conns_per_host/max_idle_conns_per_host.go
kernel time_wait
# 다음 netstat 로 time_wait 보면 PID/Program name 이 - 표시된 케이스가 있다.
netstat -natop | grep -i time_waitProto Recv-Q Send-Q Local Address Foreign Address State PID/Program name Timer
tcp 0 0 1.1.1.1:12345 2.2.2.2:10000 TIME_WAIT - timewait (20.69/0/0)
# - 는 해당 포트를 사용하던 /proc/$PID 가 사라져(종료) 커널이 관리하게되는 경우다.
# 커널이 잡고 있는 time_wait 포트를 없애기 위해서는 네트워크를 종료하는 방법이 있지만 서비스 중인 서버에서는 사용할 수 없다.
/etc/init.d/network restart
# 드문 경우지만 MSL(Maximum Segment Lifetime, tcp 세그먼트가 네트워크에 존재하는 최대시간으로 보통 2분)이 넘어가서 서버로 부터 fin 을 받지 못할때 발생할 수 있다.
# https://en.wikipedia.org/wiki/Maximum_segment_lifetime
# tcp_fin_timeout 확인
# 드문 경우지만 MSL(Maximum Segment Lifetime, tcp 세그먼트가 네트워크에 존재하는 최대시간으로 보통 2분)이 넘어가서 서버로 부터 fin 을 받지 못할때 발생할 수 있다.
# https://en.wikipedia.org/wiki/Maximum_segment_lifetime
# tcp_tw_reuse=1 로 재사용되지 않으면 net.ipv4.tcp_fin_timeout ~ MSL 시간이 지나면 사라진다.
# tcp_fin_timeout 확인
sysctl net.ipv4.tcp_fin_timeout
네트워크 관련 sysctl
# 연결 지향 tcp 는 데이터를 주고 받기전 우선 연결된다.
# 리슨을 위해 바인딩된 포트 열어 놓는 쪽은 passive open으로 서버가 되고,
# 연결을 요청하는 쪽은 active open으로 클라가 된다.
# tcp 종료 과정은 다음과 같다.
# 그림 출처 : 위키피디아 https://en.wikipedia.org/wiki/Transmission_Control_Protocol
# /proc/sys/net/ipv4 에 파일 수정으로 설정할 수 있다.
# https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt
# http://lxr.linux.no/linux+v3.2.8/Documentation/networking/ip-sysctl.txt
# 이중 net.ipv4 로 시작하는 tcp 제어 설정에서 중요한 몇개를 살펴 보자.
# 로컬 포트가 고갈되는 경우
# TIME_WAIT(fin을 받고 서버에 ack 보내고 일정 시간 기다리는 상태)의 소켓들을 재사용할지 여부
# 0 : 비활성화
# 1 : 활성화 (보통 1로 사용)
# 2 : loopback 에서만 활성화
net.ipv4.tcp_tw_reuse = 1
# FIN_WAIT_2(서버쪽 close 중임을 클라에게 알리는 ack 를 받았을때의 클라 상태)이후# last_ack 를 받지 못했을때 대기시간으로 디폴트 60초이다.
# 참고로 TIME_WAIT 의 타임아웃은 커널소스에 60초로 하드 코딩되어 있다.
# /usr/src/kernels/3.10.0-957.1.3.el7.x86_64.debug/include/net/tcp.h
# #define TCP_TIMEWAIT_LEN (60*HZ)
net.ipv4.tcp_fin_timeout = 60
# 로컬 포트 사용(허용) 범위
net.ipv4.ip_local_port_range = 23768 60999
# tcp_tw_use 처럼 TIME_WAIT 상태의 소켓을 재사용(recycle)할지 여부
# 디폴트는 비활성화
# 여러 문제가 발생될 소지가 있어 최근 리눅스 4.12 에서는 제거되었다고 한다.
# https://vincent.bernat.ch/en/blog/2014-tcp-time-wait-state-linux
net.ipv4.tcp_tw_recycle = 0
# 리슨을 위해 바인딩된 포트 열어 놓는 쪽은 passive open으로 서버가 되고,
# 연결을 요청하는 쪽은 active open으로 클라가 된다.
# tcp 종료 과정은 다음과 같다.
# 그림 출처 : 위키피디아 https://en.wikipedia.org/wiki/Transmission_Control_Protocol
# sysctl 은 런타임시에 커널의 파리미터를 설정하는 명령어다.
# /etc/sysctl.conf 파일로도 설정할 수 있다.# /proc/sys/net/ipv4 에 파일 수정으로 설정할 수 있다.
# https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt
# http://lxr.linux.no/linux+v3.2.8/Documentation/networking/ip-sysctl.txt
# 이중 net.ipv4 로 시작하는 tcp 제어 설정에서 중요한 몇개를 살펴 보자.
# TIME_WAIT(fin을 받고 서버에 ack 보내고 일정 시간 기다리는 상태)의 소켓들을 재사용할지 여부
# 0 : 비활성화
# 1 : 활성화 (보통 1로 사용)
# 2 : loopback 에서만 활성화
net.ipv4.tcp_tw_reuse = 1
# FIN_WAIT_2(서버쪽 close 중임을 클라에게 알리는 ack 를 받았을때의 클라 상태)이후
# 참고로 TIME_WAIT 의 타임아웃은 커널소스에 60초로 하드 코딩되어 있다.
# /usr/src/kernels/3.10.0-957.1.3.el7.x86_64.debug/include/net/tcp.h
# #define TCP_TIMEWAIT_LEN (60*HZ)
net.ipv4.tcp_fin_timeout = 60
# 로컬 포트 사용(허용) 범위
net.ipv4.ip_local_port_range = 23768 60999
# tcp_tw_use 처럼 TIME_WAIT 상태의 소켓을 재사용(recycle)할지 여부
# 디폴트는 비활성화
# 여러 문제가 발생될 소지가 있어 최근 리눅스 4.12 에서는 제거되었다고 한다.
# https://vincent.bernat.ch/en/blog/2014-tcp-time-wait-state-linux
net.ipv4.tcp_tw_recycle = 0