TCP/IP sysctl 파라미터 튜닝으로 Linux 네트워크 처리량 최적화
처리량, 버퍼, 혼잡 제어 및 안전한 테스트를 위한 실용적인 Linux TCP sysctl 튜닝 가이드
TCP/IP sysctl 파라미터 튜닝으로 Linux 네트워크 처리량 최적화
Linux 네트워크 처리량 튜닝은 지루한 질문에서 시작합니다: 실제로 무엇이 느린가? 10Gbps 링크에서 300Mbps에 그치는 서버는 TCP 윈도우 문제, 디스크 문제, CPU 인터럽트 문제, 잘못된 가상 NIC 설정, 패킷 손실 문제, 또는 데이터를 작은 조각으로 보내는 애플리케이션 문제일 수 있습니다. sysctl 튜닝은 그중 일부에만 도움이 됩니다.
그렇기 때문에 저는 TCP/IP sysctl 변경을 통제된 실험으로 취급하며, 마법 같은 성능 레시피가 아닙니다. 기준을 설정하고, 소규모 설정 그룹을 변경하고, 다시 테스트하고, 기록을 남기세요. 인터넷에서 거대한 튜닝 블록을 복사하여 /etc/sysctl.conf에 붙여넣으면 한 워크로드는 개선되지만 다른 워크로드는 조용히 손상될 수 있습니다.
아래 설정은 고처리량 서비스(아티팩트 저장소, 백업 서버, 객체 스토리지 게이트웨이, 바쁜 리버스 프록시, 대규모 로그를 전송하는 데이터베이스 복제본, 또는 장거리 링크를 통해 트래픽을 이동하는 Linux 호스트)를 실행할 때 유용합니다. 병목이 TLS 암호화 CPU, 느린 스토리지, 애플리케이션 잠금, 클라우드 제공자 제한, 또는 호스트 외부의 패킷 손실인 경우에는 도움이 되지 않을 가능성이 높습니다.
변경하기 전에 빠른 기준을 수집하세요:
ip -s link
ss -s
nstat -az | egrep 'TcpRetransSegs|TcpExtTCPLoss|TcpExtTCPTimeouts|TcpExtListenOverflows'
sar -n DEV,TCP,ETCP 1 10
iperf3 -c test-host -P 4 -t 30
재전송이 증가하면 버퍼를 늘리기 전에 손실을 먼저 해결하세요. CPU가 이미 top, mpstat, 또는 perf에서 고정되어 있다면 sysctl이 증상을 숨길 수는 있지만 병목을 제거하지는 않습니다. iperf3는 빠르지만 애플리케이션이 느리다면 커널을 튜닝하기 전에 애플리케이션 경로를 살펴보세요.
sysctl이 네트워크 튜닝에 어떻게 적용되는가
sysctl은 시스템이 실행 중인 동안 커널 파라미터를 노출합니다. 네트워크 설정은 일반적으로 net.ipv4, net.ipv6, net.core 아래에 있습니다. 다음과 같이 값을 읽을 수 있습니다:
sysctl net.ipv4.tcp_congestion_control
sysctl net.ipv4.tcp_rmem
sysctl net.core.rmem_max
임시 변경은 다음과 같이 테스트할 수 있습니다:
sudo sysctl -w net.ipv4.tcp_congestion_control=bbr
임시 변경은 재부팅 후 사라집니다. 영구 변경은 설명 없이 /etc/sysctl.conf에 흩어지지 않고 /etc/sysctl.d/90-network-throughput.conf와 같은 전용 파일에 있어야 합니다.
sudo install -m 0644 /dev/null /etc/sysctl.d/90-network-throughput.conf
sudo editor /etc/sysctl.d/90-network-throughput.conf
sudo sysctl --system
별도의 파일을 사용하는 이유는 롤백이 간단하기 때문입니다: 파일을 이동시키고 sudo sysctl --system을 다시 실행하면 됩니다. 이는 설정이 프로덕션 트래픽에서 잘못 작동할 때 중요합니다.
TCP 버퍼: 긴 연결에 숨 쉴 공간 제공
사람들이 가장 먼저 보는 곳은 버퍼 크기 조정입니다. TCP는 네트워크를 통해 확인 응답이 이동하는 동안 데이터를 전송 중으로 유지하기 위해 충분한 송수신 윈도우 공간이 필요합니다. 유용한 개념 모델은 대역폭-지연 곱입니다: 고대역폭, 고지연 연결은 저지연 LAN 연결보다 더 많은 전송 중 데이터가 필요합니다.
예를 들어, 1ms 데이터 센터 경로를 통한 1Gbps 전송은 70ms WAN 경로를 통한 1Gbps 전송보다 훨씬 적은 전송 중 데이터가 필요합니다. 수신 윈도우가 너무 작으면 링크에 여유가 있어도 송신자가 일시 중지됩니다.
Linux는 TCP 메모리 튜닝에 세 값 배열을 사용합니다:
net.ipv4.tcp_rmem = 4096 131072 33554432
net.ipv4.tcp_wmem = 4096 131072 33554432
세 숫자는 소켓당 최소, 기본, 최대 버퍼 크기(바이트)입니다. 정확한 값은 워크로드, 메모리 예산, 커널 동작과 일치해야 합니다. 위 예제는 최대값을 32MiB로 높이며, 이는 무모하지 않으면서도 바쁜 서버에 충분한 경우가 많습니다. 일부 장거리 또는 스토리지 중심 시스템은 더 큰 값을 사용하지만, 실제 트래픽으로 테스트해야 합니다.
net.core 제한은 소켓 버퍼를 제한합니다:
net.core.rmem_max = 33554432
net.core.wmem_max = 33554432
tcp_rmem이 TCP가 32MiB까지 성장할 수 있다고 말하지만 net.core.rmem_max가 훨씬 낮으면 실제로는 낮은 제한이 적용됩니다. 특별한 이유가 없다면 제한을 TCP 최대값과 일치시키세요.
동시 연결이 많은 시스템에서 맹목적으로 버퍼를 높이지 마세요. 대규모 흐름이 몇 개 있는 파일 서버는 흐름당 더 큰 버퍼를 감당할 수 있습니다. 수십만 개의 연결을 처리하는 프록시는 모든 소켓이 거대한 버퍼를 사용할 수 있게 하면 메모리를 빠르게 소모할 수 있습니다.
자동 튜닝이 이미 일부 작업을 수행하고 있음
최신 Linux 커널은 이미 TCP 버퍼를 자동 튜닝합니다. 즉, 일반적으로 애플리케이션에서 거대한 고정 소켓 버퍼를 설정할 필요가 없습니다. 커널은 연결이 더 많은 공간을 필요로 할 때 버퍼를 증가시킵니다.
여러분의 작업은 주로 상한선이 너무 낮지 않은지 확인하는 것입니다. 긴 지연 네트워크에서 처리량이 낮고 ss -tin이 작은 수신 윈도우 또는 수신자에 의해 차단된 송신자를 보여준다면 tcp_rmem, tcp_wmem, rmem_max, wmem_max를 높이는 것이 도움이 될 수 있습니다.
활성 연결을 확인하세요:
ss -tin dst <피어-ip>
cwnd, rtt, rto, bytes_acked, bytes_received, 재전송 카운터와 같은 필드를 찾으세요. 이들은 단일 속도 테스트보다 더 나은 이야기를 들려줍니다.
혼잡 제어: CUBIC, BBR, 그리고 현실
혼잡 제어 알고리즘은 TCP가 전송 속도를 어떻게 증가시키거나 감소시킬지 결정합니다. 많은 Linux 시스템에서 CUBIC이 기본값이며 일반 인터넷 및 데이터 센터 트래픽에 잘 작동합니다. BBR은 패킷 손실에만 반응하는 대신 병목 대역폭과 왕복 시간을 모델링하기 때문에 일부 손실이 있거나 장거리 경로에서 처리량과 지연 시간을 개선할 수 있습니다.
사용 가능한 알고리즘 확인:
sysctl net.ipv4.tcp_available_congestion_control
sysctl net.ipv4.tcp_congestion_control
커널에서 사용 가능한 경우에만 BBR을 활성화하세요:
sudo sysctl -w net.ipv4.tcp_congestion_control=bbr
영구 설정:
net.ipv4.tcp_congestion_control = bbr
일부 시스템은 BBR의 좋은 동작을 위해 공정 큐잉 패킷 스케줄러도 필요로 합니다:
net.core.default_qdisc = fq
BBR이 항상 더 빠르다고 가정하지 마세요. 다른 흐름과의 공정성을 변경할 수 있으며, BBR 버전에 따라 커널 간 동작이 다릅니다. 관심 있는 트래픽 패턴(많은 소규모 API 호출, 몇 개의 대량 전송, 복제된 데이터베이스 트래픽, 또는 혼합 프로덕션 유사 부하)으로 테스트하세요.
수신 큐: 드롭을 미스터리가 되기 전에 수정
처리량 문제는 트래픽 급증 중 연결 실패로 나타나기도 합니다. 서비스가 클라이언트가 생성하는 것보다 느리게 새 TCP 연결을 수락하면 커널 큐가 가득 찹니다.
관련 설정:
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 8192
somaxconn은 애플리케이션이 listen(2)을 통해 요청한 완료된 연결 백로그를 제한합니다. tcp_max_syn_backlog는 반개방 SYN 큐 용량에 영향을 줍니다. 이를 높이면 바쁜 웹 서버, 프록시, 로드 밸런서에 도움이 될 수 있지만, 애플리케이션도 충분히 큰 백로그를 요청해야 합니다. Nginx, HAProxy, Envoy, 애플리케이션 서버는 자체 백로그 설정이 있습니다.
오버플로우 확인:
nstat -az | egrep 'ListenOverflows|ListenDrops|Syncookies'
ss -ltn
ListenOverflows가 증가하면 커널 큐가 따라잡지 못하는 것입니다. CPU가 포화 상태이거나 앱이 다운스트림 서비스에 의해 차단된 경우 큐 크기를 늘리면 클라이언트 오류가 일시적으로 줄어들 수 있지만 서비스가 해결되지는 않습니다.
백로그 및 패킷 처리
net.core.netdev_max_backlog는 커널이 패킷을 처리할 수 있는 속도보다 빠르게 수신할 때 입력 큐에서 대기할 수 있는 패킷 수를 제어합니다.
net.core.netdev_max_backlog = 250000
이는 특히 가상화된 네트워킹을 사용하는 고속 인터페이스에서 버스트 중에 도움이 될 수 있습니다. 또한 호스트를 큰 패킷 대기실로 만들면 지연 시간이 추가될 수 있습니다. 먼저 인터페이스 드롭을 확인하세요:
ip -s link show dev eth0
ethtool -S eth0 | egrep 'drop|err|timeout|miss|fifo'
드라이버 수준 드롭이 증가하면 NIC 링 크기, 인터럽트 분산, RSS 큐, CPU 선호도도 검사하세요. 이는 sysctl 외부에 있지만, 10Gbps 이상 호스트에서는 TCP 버퍼보다 더 중요한 경우가 많습니다.
TIME_WAIT 및 포트 고갈
고처리량 클라이언트, 프록시, 작업 실행기는 임시 포트가 부족하거나 TIME_WAIT 상태의 소켓이 많이 누적될 수 있습니다. 오래된 튜닝 조언이 해로울 수 있으므로 주의하세요.
현재 범위 확인:
sysctl net.ipv4.ip_local_port_range
ss -tan state time-wait | wc -l
합리적인 클라이언트 측 조정은 임시 포트 범위를 넓히는 것입니다:
net.ipv4.ip_local_port_range = 10240 60999
tcp_tw_recycle을 권장하는 오래된 조언은 피하세요; NAT 뒤에서 유효한 트래픽을 손상시켜 Linux에서 제거되었습니다. tcp_tw_reuse는 많은 커널에 존재하지만, 시간이 지남에 따라 동작이 변경되었습니다. 기본 처리량 설정으로 활성화하지 마세요. 필요하다고 생각되면 정확한 커널과 트래픽 패턴을 신중히 테스트하세요.
서버의 경우 TIME_WAIT 소켓이 많이 쌓이는 것은 종종 정상입니다. 클라이언트의 경우 포트 고갈은 일반적으로 연결 풀링, keep-alive, HTTP/2, 더 적은 단기 아웃바운드 연결, 또는 더 많은 소스 IP가 필요함을 의미합니다.
보수적인 시작 파일
다음은 고처리량 서버를 위한 실용적인 시작점입니다. 의도적으로 극단적이지 않습니다:
# /etc/sysctl.d/90-network-throughput.conf
# 고대역폭 또는 고지연 경로를 위한 더 큰 TCP 자동 튜닝 상한선.
net.core.rmem_max = 33554432
net.core.wmem_max = 33554432
net.ipv4.tcp_rmem = 4096 131072 33554432
net.ipv4.tcp_wmem = 4096 131072 33554432
# 버스트 인바운드 트래픽을 위한 더 큰 큐.
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 8192
net.core.netdev_max_backlog = 250000
# 선택 사항: 전역 활성화 전에 테스트.
# net.core.default_qdisc = fq
# net.ipv4.tcp_congestion_control = bbr
적용:
sudo sysctl --system
그런 다음 다시 측정하세요. 동일한 테스트 크기, 시간 창, 병렬 스트림 수, 네트워크 경로를 사용하세요. 다섯 개의 변수를 변경하는 전후 테스트는 증거가 아닙니다.
일반적인 실수
첫 번째 실수는 손실이 있는 경로에서 튜닝하는 것입니다. TCP는 손실을 혼잡으로 봅니다. 더 큰 버퍼는 처리량을 약간 높일 수 있지만 지연 시간을 증가시키고 실제 문제를 숨길 수 있습니다. 먼저 불량 케이블, 과부하된 가상 스위치, 패킷 폴리싱, MTU 불일치, 불안정한 VPN 경로를 수정하세요.
두 번째 실수는 iperf3 -P 8이 애플리케이션 성능을 증명한다고 가정하는 것입니다. 병렬 스트림은 하나의 실제 애플리케이션 연결이 할 수 없을 때도 링크를 채울 수 있습니다. 이는 유용한 정보이지만 전체 이야기는 아닙니다.
세 번째 실수는 공유 호스트에 거대한 버퍼를 설정하는 것입니다. 커널이 필요할 때만 버퍼를 증가시키면 더 큰 상한선은 괜찮지만, 메모리 압박이 모든 것을 바꿉니다. 변경 후 free, slabtop, TCP 메모리, 애플리케이션 메모리를 모니터링하세요.
네 번째 실수는 롤백을 잊는 것입니다. 변경 티켓이나 runbook에 이전 값을 보관하세요:
sysctl -a | egrep 'net.core.rmem_max|net.core.wmem_max|net.ipv4.tcp_rmem|net.ipv4.tcp_wmem|net.ipv4.tcp_congestion_control'
sysctl이 해결책이 아닌 경우
하나의 CPU 코어가 고정되어 있고 다른 코어는 유휴 상태라면 인터럽트 처리, RSS, RPS/XPS, 애플리케이션 스레딩을 살펴보세요. 디스크 대기가 높다면 네트워크가 스토리지를 기다리고 있을 수 있습니다. TLS가 CPU를 소모한다면 암호화 유무를 테스트하고 하드웨어, 암호 선택, 연결 재사용을 고려하세요. Kubernetes나 클라우드 로드 밸런서가 경로에 있다면 서비스 수준 제한과 conntrack 테이블을 확인하세요.
NAT 중심 호스트의 경우 conntrack도 검사하세요:
sysctl net.netfilter.nf_conntrack_count
sysctl net.netfilter.nf_conntrack_max
이는 TCP 처리량 튜닝이 아니지만, conntrack 고갈은 무작위 네트워크 지연이나 연결 끊김처럼 보일 수 있습니다.
자신을 속이지 않고 테스트하기
iperf3를 네트워크 도구로 사용하되, 애플리케이션이 수정되었다는 증거로 사용하지 마세요. 단일 스트림 테스트는 하나의 TCP 연결이 무엇을 할 수 있는지 보여주기 때문에 유용합니다:
iperf3 -c test-host -t 30
병렬 테스트는 여러 흐름으로 링크를 채울 수 있는지 보여줍니다:
iperf3 -c test-host -P 8 -t 30
병렬 스트림이 빠르지만 단일 스트림이 느리다면 혼잡 제어, TCP 윈도우 성장, RTT, 패킷 손실을 살펴보세요. 둘 다 느리다면 더 낮은 수준(인터페이스 오류, 클라우드 대역폭 제한, CPU 포화, MTU, 방화벽 검사, 송수신자 뒤의 스토리지)을 확인하세요.
테스트 경로를 현실적으로 유지하세요. 동일한 랙에 있는 두 호스트를 테스트하는 것은 지역 간 백업 작업에 대해 많은 것을 알려주지 않습니다. 작은 파일로 테스트하는 것은 정상 상태 처리량을 드러내지 않습니다. VPN을 통해 테스트하는 것은 Linux TCP보다 VPN 어플라이언스를 더 많이 측정할 수 있습니다.
각 변경 후 동일한 카운터를 캡처하세요:
nstat -az > /tmp/nstat-after.txt
ss -s
sar -n DEV,TCP,ETCP 1 10
유용한 결과는 단순히 "숫자가 올라갔다"가 아닙니다. 재전송이 줄었는지, 큐가 넘치지 않았는지, CPU가 합리적으로 유지되었는지, 작은 요청에 대한 지연 시간이 악화되지 않았는지 알고 싶습니다.
좋은 Linux 네트워크 튜닝은 측정 가능하고 되돌릴 수 있습니다. 경로가 더 큰 윈도우를 필요로 할 때 TCP 버퍼 상한선을 높이세요. 하나의 알고리즘이 모든 곳에서 승리한다고 가정하지 말고 혼잡 제어를 테스트하세요. 큐 드롭이 보일 때 수신 큐를 늘리고, 애플리케이션이 충분히 빨리 수락할 수 없으면 수정하세요. sysctl은 유용하지만 더 큰 시스템의 한 계층일 뿐입니다.