Linux Kernel Network Parameter를 무작정 튜닝하면 안 되는 이유
서버에서 Connection Timeout이 발생하거나 동시접속자가 급격히 늘어나면 Linux Network Parameter부터 의심하기 쉽습니다.
검색해 보면 이런 설정이 자주 등장합니다.
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 1024 65535
하지만 Kernel Parameter는 서버 성능을 높여주는 마법의 옵션이 아닙니다. TCP Connection이 생성되고 대기하고 종료되는 과정에서 Kernel이 Queue, Port, Socket, Memory 같은 자원을 어떻게 사용할지 결정하는 설정입니다.
그래서 장애 원인을 찾지 않고 값을 크게 바꾸면 문제가 해결되는 것이 아니라 병목이 다른 위치로 이동할 수 있습니다.
핵심은 하나입니다.
Parameter를 바꾸기 전에 Connection이 어디에서 막히는지 먼저 확인해야 합니다.
TCP Connection은 하나의 Queue만 거치지 않는다
클라이언트가 서버에 접속하면 TCP Connection은 대략 다음 과정을 거칩니다.
Client
↓
SYN_RECV
↓
3-Way Handshake 완료
↓
Accept 대기
↓
Application
↓
ESTABLISHED
tcp_max_syn_backlog은 아직 Handshake가 완료되지 않은 SYN_RECV 요청과 관련되고, somaxconn은 listen() backlog의 상한에 영향을 줍니다.
외부 API나 DB로 Connection을 많이 만드는 서버에서는 ip_local_port_range가 중요할 수 있고, 종료 후에는 TIME_WAIT 같은 TCP State가 나타납니다.
즉 Connection이 많다는 증상만으로 어떤 Parameter를 조정해야 하는지 결정할 수 없습니다.
SYN_RECV가 많은 것과 Accept Queue가 밀리는 것은 원인이 다르고, TIME_WAIT이 많은 것도 별개의 문제입니다.
somaxconn을 크게 만들면 동시접속자가 늘어날까?
가장 많이 변경하는 값 중 하나가 net.core.somaxconn입니다.
sysctl net.core.somaxconn
이 값은 애플리케이션이 listen()에서 사용할 backlog의 상한에 영향을 줍니다.
예를 들어 다음처럼 값을 크게 만들 수 있습니다.
sysctl -w net.core.somaxconn=65535
그러면 더 많은 Connection이 Accept를 기다릴 수 있는 여유는 생길 수 있습니다.
하지만 서버가 초당 5,000개의 요청을 처리할 수 있는데 초당 8,000개의 요청이 계속 들어온다면 상황은 달라집니다.
신규 Connection 8,000/s
↓
Application 처리 5,000/s
↓
대기 Connection 계속 증가
Queue를 키우면 Overflow 시점은 늦출 수 있지만 Application 처리속도가 빨라지는 것은 아닙니다.
먼저 Listen 상태와 Queue 관련 Counter를 확인합니다.
ss -lnt
nstat -az | grep -E 'ListenOverflows|ListenDrops'
이 값이 트래픽 증가 시점에 계속 늘어난다면 Queue 압박을 의심할 수 있습니다.
하지만 여기서 바로 somaxconn을 올리면 안 됩니다. CPU 포화, WAS 처리 지연, DB 응답 지연 때문에 Application이 Connection을 늦게 가져가는 것일 수도 있기 때문입니다.
Queue가 찼다고 Kernel이 원인인 것은 아니다
예를 들어 DB Query가 갑자기 느려졌다고 가정해 보겠습니다.
DB Query 지연
↓
WAS 요청 처리시간 증가
↓
새 요청 처리속도 감소
↓
Accept 대기 증가
↓
Listen Queue 압박
이때 somaxconn을 크게 만들면 Connection 실패가 잠시 줄어드는 것처럼 보일 수 있습니다.
하지만 실제 장애 원인은 DB입니다. Queue가 커졌기 때문에 요청이 더 오래 기다릴 수 있게 된 것뿐입니다.
Queue는 처리능력이 아니라 대기 공간입니다.
대기실을 크게 만든다고 처리창구 속도가 빨라지는 것은 아닙니다. 오히려 즉시 실패하던 요청이 오래 기다린 뒤 Timeout되는 형태로 바뀔 수도 있습니다.
tcp_max_syn_backlog은 somaxconn과 역할이 다르다
SYN Queue와 관련된 값은 다음입니다.
sysctl net.ipv4.tcp_max_syn_backlog
구조를 단순화하면 다음처럼 볼 수 있습니다.
Client SYN
↓
SYN_RECV
↓
tcp_max_syn_backlog 관련
↓
Handshake 완료
↓
Accept 대기
↓
listen backlog / somaxconn 관련
따라서 SYN_RECV가 많다고 somaxconn을 올리는 것이 직접적인 해결은 아닐 수 있습니다.
SYN_RECV 상태는 다음처럼 확인합니다.
ss -ant state syn-recv
SYN_RECV가 많다면 정상적인 사용자 증가인지, SYN Flood처럼 비정상적인 SYN 유입인지 구분해야 합니다.
정상 트래픽이라면 Capacity 문제일 수 있지만, 비정상 트래픽이라면 공격 대응 관점이 필요합니다.
tcp_syncookies 역시 정상 부하에서 처리량을 높이는 일반적인 튜닝 값이 아니라 SYN Flood 상황에서 사용하는 보호 메커니즘에 가깝습니다.
같은 SYN_RECV 증가라도 원인에 따라 대응은 달라집니다.
TIME_WAIT이 많다고 tcp_fin_timeout을 줄이면 될까?
TIME_WAIT은 다음처럼 확인할 수 있습니다.
ss -ant state time-wait
이때 자주 나오는 잘못된 접근이 tcp_fin_timeout을 줄이는 것입니다.
net.ipv4.tcp_fin_timeout = 10
이름만 보면 TIME_WAIT 유지 시간을 줄이는 옵션처럼 보이지만, 일반적인 TIME_WAIT 시간을 직접 조절하는 값은 아닙니다.
tcp_fin_timeout은 애플리케이션이 더 이상 참조하지 않는 orphaned Connection이 FIN_WAIT_2 상태에 머무르는 시간과 관련된 설정입니다.
따라서 TIME_WAIT이 많다면 먼저 누가 Connection을 반복해서 만들고 종료하는지 확인해야 합니다.
예를 들어 Reverse Proxy가 Backend 호출마다 새 TCP Connection을 만든다면 다음 패턴이 반복됩니다.
Request
↓
새 TCP Connection
↓
Backend 호출
↓
Connection 종료
↓
다음 Request에서 다시 생성
이 경우 Kernel Parameter보다 Keep-Alive, upstream Connection 재사용, Connection Pool 설정이 더 중요한 원인일 수 있습니다.
오래된 튜닝 값을 그대로 적용하면 안 되는 이유
TIME_WAIT 관련 자료에서는 다음 설정도 자주 등장합니다.
net.ipv4.tcp_tw_reuse = 1
문제는 인터넷에 오래된 Linux 튜닝 자료가 많다는 것입니다.
Kernel Network Parameter는 버전에 따라 의미나 기본값이 달라질 수 있으므로 몇 년 전 다른 환경에서 사용한 값을 그대로 적용하면 안 됩니다.
현재 Kernel 버전과 설정값부터 확인해야 합니다.
uname -r
sysctl net.ipv4.tcp_tw_reuse
다른 서버의 권장값보다 현재 운영 중인 Kernel에서 해당 Parameter가 어떤 의미를 가지는지 확인하는 것이 우선입니다.
Ephemeral Port가 부족하면 Port Range부터 늘려야 할까?
외부 API나 DB로 새 Connection을 많이 만드는 서버에서는 Ephemeral Port가 부족해질 수 있습니다.
sysctl net.ipv4.ip_local_port_range
Port Range 확대는 실제 해결책이 될 수 있습니다.
하지만 애플리케이션이 외부 API 호출마다 새로운 TCP Connection을 만들고 있다면 먼저 Connection 사용 방식을 봐야 합니다.
요청
↓
새 Connection
↓
외부 API
↓
Connection 종료
↓
다음 요청에서 다시 생성
Keep-Alive나 Connection Pool을 사용할 수 있는데도 매번 새로운 Connection을 만든다면 Port Range를 넓혀도 근본 원인은 남습니다.
질문은 Port 범위를 얼마나 넓힐까?보다 왜 새로운 Connection이 계속 만들어지는가?가 먼저입니다.
장애가 발생하면 무엇부터 확인해야 할까?
Kernel Network 문제를 분석할 때는 Parameter를 바꾸기 전에 현재 상태를 기록해야 합니다.
ss -s
ss -lnt
ss -ant state syn-recv
ss -ant state time-wait
nstat -az | grep -E 'ListenOverflows|ListenDrops'
현재 Kernel Parameter도 함께 기록합니다.
sysctl net.core.somaxconn
sysctl net.ipv4.tcp_max_syn_backlog
sysctl net.ipv4.tcp_syncookies
sysctl net.ipv4.tcp_fin_timeout
sysctl net.ipv4.tcp_tw_reuse
sysctl net.ipv4.ip_local_port_range
여기서 끝내면 안 됩니다.
같은 시간대의 CPU, Memory, Nginx 상태, WAS 처리시간, DB 응답시간도 함께 봐야 합니다.
중요한 것은 숫자 하나가 아니라 어떤 지표가 같은 시점에 함께 변했는지입니다.
예를 들어 ListenOverflows가 증가하는 시점에 DB 응답시간과 API 처리시간도 함께 늘었다면 Queue 자체보다 Backend 지연을 먼저 의심해야 합니다.
여러 Parameter를 한 번에 바꾸지 않는다
운영 서버에서 가장 피해야 할 방식 중 하나는 인터넷에서 찾은 sysctl.conf 값을 통째로 복사해 적용하는 것입니다.
somaxconn, tcp_max_syn_backlog, tcp_tw_reuse, ip_local_port_range를 한꺼번에 바꾸면 장애가 좋아져도 어떤 설정이 효과를 냈는지 알기 어렵습니다.
반대로 새로운 문제가 생겨도 원인을 찾기 힘듭니다.
실무에서는 다음 순서가 안전합니다.
증상 확인
↓
TCP State 확인
↓
Queue 상태 확인
↓
Application / Backend 확인
↓
병목 위치 결정
↓
관련 Parameter 변경
↓
변경 전후 비교
↓
효과 없으면 원복
한 번에 하나의 가설을 검증해야 튜닝이 추측이 아니라 분석이 됩니다.
Linux Network 튜닝의 핵심은 병목 위치다
Linux 서버에 공통으로 적용할 수 있는 하나의 최적 Network Parameter 세트는 없습니다.
정적 파일을 제공하는 Nginx 서버와 Backend 응답을 기다리는 Reverse Proxy는 Connection 패턴이 다르고, 외부 API 호출이 많은 서버와 DB 서버도 Port와 Socket 사용 방식이 다릅니다.
somaxconn = 65535라는 숫자 자체가 좋은 설정도 나쁜 설정도 아닙니다.
실제 Listen Queue가 부족하고 Application 처리 여력이 있으며 순간적인 Connection Burst를 흡수해야 한다는 근거가 있다면 적절한 튜닝이 될 수 있습니다.
반대로 DB 지연 때문에 요청 처리가 막힌 상황에서 같은 값을 적용하면 근본 원인을 가릴 수 있습니다.
결국 운영자가 먼저 해야 할 질문은 이것입니다.
지금 Connection은 어디에서 기다리고 있는가?
SYN 단계인지, Accept Queue인지, Application 처리 단계인지, Backend 응답 단계인지 먼저 찾아야 합니다.
그다음에야 Kernel Parameter를 조정할 이유가 생깁니다.
좋은 서버 튜닝은 많은 값을 크게 설정하는 것이 아닙니다.
현재 서버에서 어떤 현상이 발생했고, 어떤 지표가 그 원인을 보여주며, 어떤 설정을 변경했을 때 실제로 개선되는지를 확인하는 과정입니다.
Kernel Parameter는 장애 분석의 출발점이 아니라, 원인을 찾은 뒤 사용하는 도구입니다.




댓글 0
첫 댓글을 남겨보세요.