NGINX 와 NGINX Plus는 매우 강력한 HTTP , TCP , UDP 로드 밸런서입니다. 그들은 대량의 요청을 프록시하고 많은 수의 동시 연결을 유지하는 데 매우 효율적입니다. 하지만 이러한 특성으로 인해 NGINX 및 NGINX Plus는 일시적 포트 고갈 에 특히 취약합니다. 일시적 포트 고갈이란 OS가 새 로컬 소켓을 설정하는 데 할당된 포트 번호를 모두 소진하여 새 연결을 생성할 수 없는 상황을 말합니다. (일시적 포트 소진은 두 제품 모두에 적용되지만, 간결함을 위해 이 블로그의 나머지 부분에서는 NGINX Plus만 언급하겠습니다.)
이 블로그에서는 TCP 연결의 구성 요소를 살펴보고 연결이 설정되기 전에 연결 내용이 어떻게 결정되는지 알아보겠습니다. 그런 다음 NGINX Plus가 일시적 포트 고갈의 영향을 받는 경우를 확인하는 방법을 보여드립니다. 마지막으로 Linux 커널 조정과 NGINX Plus 지침을 모두 사용하여 이러한 제한에 대처하는 전략을 논의합니다.
TCP를 통해 연결이 설정되면 로컬 호스트와 원격 호스트에 모두 소켓이 생성됩니다. 그런 다음 이러한 소켓을 연결하여 소켓 쌍을 만듭니다. 소켓 쌍은 로컬 IP 주소와 포트, 원격 IP 주소와 포트로 구성된 고유한 4튜플로 설명됩니다.
원격 IP 주소와 포트는 연결의 서버 측에 속하며, 연결을 시작하기 전에 클라이언트가 이를 결정해야 합니다. 대부분의 경우 클라이언트는 연결에 사용할 로컬 IP 주소를 자동으로 선택하지만, 때로는 연결을 설정하는 소프트웨어가 IP 주소를 선택하기도 합니다. 마지막으로, 로컬 포트는 운영 체제에서 정의된 범위에서 무작위로 선택됩니다. 포트는 연결 기간 동안만 클라이언트와 연결되므로 임시 포트라고 합니다. 연결이 종료되면 임시 포트를 재사용할 수 있습니다.
소개에서 언급했듯이 NGINX Plus는 본질적으로 일시적인 포트 고갈과 이로 인한 문제의 영향을 받을 수 있습니다. NGINX Plus가 업스트림 서버에 요청을 프록시하는 경우, 위에서 설명한 소켓 생성 프로세스에서는 클라이언트가 되고, 기본 동작은 프록시된 요청에 대한 소켓을 자동으로 로컬 IP 주소와 해당 소켓을 실행 중인 호스트에서 사용 가능한 임시 포트에 바인딩하는 것입니다. 연결 속도가 높아서 설정 중인 소켓이 기존에 열려 있는 소켓이 닫히는 것보다 더 빠르게 대기 상태로 전환되면 결국 사용 가능한 포트가 고갈되고 새로운 소켓을 만들 수 없게 됩니다. 이로 인해 운영 체제와 NGINX Plus 모두에서 오류가 발생합니다. 다음은 NGINX Plus 오류 로그에 표시된 오류의 예입니다.
2016/03/18 09:08:37 [crit] 1888#1888: *13 10.2.2.77:8081에 대한 connect()가 실패했습니다(99: 요청한 주소를 할당할 수 없습니다) 업스트림에 연결하는 동안 클라이언트: 10.2.2.42, 서버: , 요청: "GET / HTTP/1.1", 업스트림: "http://10.2.2.77:8081/", 호스트: "10.2.2.77"
포트 고갈로 인해 스파이크도 발생합니다.500
오류는 업스트림 서버가 아닌 NGINX Plus에서 발생했습니다. 다음은 NGINX Plus 액세스 로그의 샘플 항목입니다.
10.2.2.42 - - [2016년 3월 18일:09:14:20 -0700] "GET / HTTP/1.1"500 192 "-" "컬/7.35.0"
NGINX Plus 서버에서 TIME-WAIT
상태에 있는 소켓의 수를 확인하려면 Linux 셸에서 다음 ss
명령을 실행하세요. 이 예에서는 TIME-WAIT
상태로 143개의 소켓이 열려 있음을 보여줍니다. 이 예제에서는 wc
명령을 사용하여 명령 출력에서 줄의 개수를 나열하여 개수를 구합니다.
# ss -a | grep TIME-WAIT | wc -l143
일시적 포트 고갈을 줄이는 한 가지 방법은 Linux 커널 net.ipv4.ip_local_port_range
설정을 사용하는 것입니다. 기본 범위는 대개 32768~61000입니다.
임시 포트가 부족하다는 것을 알게 되면 기본값에서 1024~65000으로 범위를 변경하는 것이 사용 가능한 임시 포트 수를 두 배로 늘리는 실용적인 방법입니다. 커널 설정을 변경하는 방법에 대한 자세한 내용은 성능을 위한 NGINX 튜닝 블로그 게시물을 참조하세요.
일시적 포트 고갈을 줄이는 또 다른 방법은 NGINX Plus와 업스트림 서버 간에 keepalive 연결을 활성화하는 것입니다. HTTP의 가장 간단한 구현은 클라이언트가 새로운 연결을 열고, 요청을 작성하고, 응답을 읽은 다음, 연결을 닫아서 연관된 리소스를 해제하는 것입니다.
Keepalive 연결은 클라이언트가 응답을 읽은 후에도 계속 열려 있으므로 후속 요청에 재사용할 수 있습니다.
keepalive
지시어를 사용하여 NGINX Plus에서 업스트림 서버로의 keepalive 연결을 활성화하고, 각 작업자 프로세스의 캐시에 보존되는 업스트림 서버에 대한 유휴 keepalive 연결의 최대 수를 정의합니다. 이 숫자를 초과하면 가장 최근에 사용되지 않은 연결이 닫힙니다. Keepalives가 없으면 오버헤드가 늘어나고 연결과 임시 포트 모두에서 비효율적이 됩니다.
다음 샘플 구성은 NGINX Plus에게 백엔드 라는 업스트림
블록에 정의된 서버에 대해 최소 128개의 keepalive 연결을 유지하도록 지시합니다.
업스트림 백엔드 { 서버 10.0.0.100:1234;
서버 10.0.0.101:1234;
keepalive 128;
}
업스트림 서버에 keepalive 연결을 활성화하는 경우 proxy_http_version
지시문을 사용하여 NGINX Plus에서 HTTP 버전 1.1을 사용하도록 지정하고 proxy_set_header
지시문을 사용하여 Connection
이라는 이름의 모든 헤더를 제거해야 합니다. 두 지시어 모두 http
, server
, 또는 location
구성 블록에 배치할 수 있습니다.
proxy_http_버전 1.1; proxy_set_header 연결 "";
커널을 최적화하고 keepalive 연결을 활성화하면 임시 포트의 가용성과 사용을 훨씬 더 효과적으로 제어할 수 있지만, 이러한 변경 사항만으로는 임시 포트의 과도한 사용을 억제하기에 충분하지 않은 경우가 있습니다. 이 경우 NGINX Plus 지침과 매개변수를 사용하여 연결의 일정 비율을 정적 로컬 IP 주소에 바인딩할 수 있습니다. 이렇게 하면 구성에 정의된 IP 주소 수만큼 사용 가능한 임시 포트 수가 효과적으로 곱해집니다. 이를 달성하려면 proxy_bind
및 split_clients
지시어를 사용합니다.
아래 예시 구성에서 location
블록의 proxy_bind
지시문은 $split_ip
변수의 값에 따라 각 요청 동안 로컬 IP 주소를 설정합니다. 이 변수를 split_clients
블록에서 생성된 값으로 동적으로 설정합니다. 이 블록에서는 해시 함수를 사용하여 해당 값을 결정합니다.
split_clients
지시문의 첫 번째 매개변수는 문자열( "$remote_addr$remote_port"
)이며 각 요청 중에 MurmurHash2 함수를 사용하여 해시됩니다. 두 번째 매개변수( $split_ip
)는 첫 번째 매개변수의 해시에 따라 동적으로 설정하는 변수입니다.
중괄호 안의 문장은 해시 테이블을 "버킷"으로 나눕니다. 각 버킷에는 해시의 일정 비율이 들어 있습니다. 여기에서는 테이블을 같은 크기의 버킷 10개로 나누었지만, 버킷은 원하는 개수만큼 만들 수 있으며, 모두 같은 크기일 필요는 없습니다. (마지막 버킷의 백분율은 해시 수가 지정된 백분율로 균등하게 나누어지지 않을 수 있으므로 특정 숫자가 아닌 별표 [ * ]로 항상 표시됩니다.)
가능한 해시 값의 범위는 0~4294967295이므로 우리의 경우 각 버킷에는 약 429496700개의 값(전체의 10%)이 포함됩니다. 첫 번째 버킷은 0~429496700의 값, 두 번째 버킷은 429496701~858993400의 값 등이 포함됩니다. $split_ip
변수는 $remote_addr$remote_port
문자열의 해시가 포함된 버킷과 연관된 IP 주소로 설정됩니다. 구체적인 예로, 해시 값 150000000은 네 번째 버킷에 속하므로 이 경우 변수 $split_ip
는 동적으로 10.0.0.213으로 설정됩니다.
http { 업스트림 백엔드 { 서버 10.0.0.100:1234; 서버 10.0.0.101:1234; } 서버 { # ... 위치 / { # ... 프록시_패스 http://백엔드; 프록시_바인드 $split_ip; 프록시_설정_헤더 X-Forwarded-For $remote_addr; } } split_clients "$remote_addr$remote_port" $split_ip { 10% 10.0.0.210; 10% 10.0.0.211; 10% 10.0.0.212; 10% 10.0.0.213; 10% 10.0.0.214; 10% 10.0.0.215; 10% 10.0.0.216; 10% 10.0.0.217; 10% 10.0.0.218; * 10.0.0.219; } }
Linux 커널에서 임시 포트 수에 대한 설정을 조정하면 가용성과 사용 효율성이 더 높아집니다. NGINX Plus에서 업스트림 서버로 keepalive 연결을 활성화하면 해당 서버에서 임시 포트를 더 효율적으로 사용할 수 있습니다. 마지막으로, NGINX Plus 구성에서 split_clients
및 proxy_bind
지침을 사용하면 정의된 로컬 IP 주소 목록에 나가는 연결을 동적으로 바인딩하여 NGINX Plus에서 사용할 수 있는 임시 포트 수를 크게 늘릴 수 있습니다.
NGINX Plus를 사용해보려면 오늘 무료 30일 체험판을 시작하거나 저희에게 연락해 사용 사례에 대해 논의해 보세요.
"이 블로그 게시물에는 더 이상 사용할 수 없거나 더 이상 지원되지 않는 제품이 참조될 수 있습니다. 사용 가능한 F5 NGINX 제품과 솔루션에 대한 최신 정보를 보려면 NGINX 제품군을 살펴보세요. NGINX는 이제 F5의 일부가 되었습니다. 이전의 모든 NGINX.com 링크는 F5.com의 유사한 NGINX 콘텐츠로 리디렉션됩니다."