내 눈 에 보 이 는 Nginx (4): 무엇이 당신 의 Nginx 서 비 스 를 이렇게 느리게 종료 시 켰 습 니까?
필 자 는 현재 Nginx 서 비 스 를 업데이트 하 는 과정 에서 오래된 Nginx worker 프로 세 스 의 종료 가 매우 느 린 것 을 발견 했다. (오래된 worker 프로 세 스 는 항상 'is shutting down' 상태 에 있 음) 이에 대해 매우 궁금 하고 이에 대해 연 구 를 실시 했다. 본 고 는 Nginx worker 프로 세 스 가 종료 할 때의 준비 절 차 를 소개 하고 탈퇴 를 늦 추 는 원인 을 소개 하 며 해당 하 는 해결 방법 을 소개 한다.
탈퇴 준비
워 커 프로 세 스 가 master 프로 세 스 가 종료 하 라 는 명령 을 받 은 후에 (필자 의 다른 글: Nginx 신호 집합 을 참조) 종료 준 비 를 시작 합 니 다.
우선 워 커 프로 세 스 는 감청 중인 소켓 을 이벤트 배포 기 (epoll, kqueue 등) 에서 삭제 하고 닫 은 다음 연결 이 벤트 를 처리 하지 않 습 니 다.
이 어 모든 남 은 연결 을 닫 습 니 다. 남 은 연결 이란 현재 사용 중인 연결 을 요청 하지 않 은 것 을 말 합 니 다. 예 를 들 어 Nginx 와 백 엔 드 서버 가 유지 하 는 긴 연결 이나 ngxlua Cosocket 대상 저층 의 긴 연결.
이 어 워 커 프로 세 스 는 모든 타이머 가 만 료 되 기 를 기다 리 고 있 습 니 다 (ngx lua 가 사용자 에 게 제공 하 는 타이머 가 특수 합 니 다. 종료 단계 에 서 는 만 료 되 고 다른 Nginx 내부 의 타이머 가 만 료 되 지 않 습 니 다). 완료 되 지 않 은 이 벤트 를 처리 합 니 다.이벤트 처리 가 완료 되면 워 커 프로 세 스 는 모든 모듈 에 등 록 된 exit 를 호출 합 니 다.process 갈고리, 마지막 으로 종료 합 니 다.
종료 가 지연 됨
워 커 프로 세 스 가 종료 되 었 을 때의 준비 과정 을 알 게 된 후에 우 리 는 왜 이렇게 느리게 종료 되 었 는 지 깊이 분석 할 수 있다.
필자 의 현재 분석 에 따 르 면 현재 다음 과 같은 두 가지 상황 이 worker 프로 세 스 의 탈퇴 를 늦 출 것 이다.
예 를 들 어 issue 의 예제 코드:
ngx.timer.at(100, function ()
-- This blocks Nginx worker from exiting
local timer_sock = ngx.socket.tcp()
timer_sock:connect("127.0.0.1", 8080)
timer_sock:setkeepalive()
end)
물론 이 코드 는 오류 처 리 를 생략 했 지만 문 제 를 설명 하 는 것 만으로 도 충분 하 다.이 코드 는 타이머 에 등록 되 어 있 습 니 다. 이 타이머 가 실행 되면 Cosocket 대상 을 만 들 고 이 컴퓨터 의 8080 포트 를 연결 한 다음 에 바로 이 대상 의 아래쪽 연결 을 keep alive 상태 로 설정 합 니 다.
먼저 connect 함 수 를 말 하고, 만약 대 단 과 의 연결 이 한꺼번에 완성 되 지 않 는 다 면, ngxlua 는 이번 연결 작업 에 타이머 하 나 를 추가 하여 연결 시간 초 과 를 판단 합 니 다. 물론 여 기 는 이 기 계 를 연결 하 는 포트 이기 때문에 연결 시간 초과 (엔 드 이상 제외) 가 거의 발생 하지 않 습 니 다.
만약 에 여기 서 연결 하고 자 하 는 쌍 단 이 공공 네트워크 에 있 고 네트워크 상황 이 이상 적 이지 않 으 면 연결 시간 이 초과 되면 발생 할 수 있 습 니 다. ngxlua 의 기본 Cosocket 연결 시간 초 과 는 60s (lua socket connect timeout) 입 니 다. 이 는 이 worker 프로 세 스 가 최소 60s 를 기다 린 다음 종료 하 는 것 을 의미 합 니 다.
마찬가지 로 setkeepalive 도 이 연결 에 시간 초과 시간 을 설정 합 니 다. 기본 값 도 60s (lua socket keepalive timeout) 이기 때문에 워 커 프로 세 스 도 이 타이머 가 만 료 되 거나 어느 순간 엔 드 가 자발적으로 연결 을 닫 거나 이상 하 게 닫 아야 만 종료 할 수 있 습 니 다.
독자 들 은 이전에 워 커 프로 세 스 가 종 료 될 때 이 남 은 긴 연결 을 자발적으로 닫 는 것 에 대해 의문 을 가 질 수 있 습 니 다. 그런데 왜 이 예제 가 워 커 프로 세 스 의 종료 가 그렇게 느 립 니까?이 컴퓨터 가 연결 되 더 라 도 연결 (EAGAIN) 을 한 번 에 완료 할 수 없 는 상황 이 발생 할 수 있 습 니 다. 이 경우 현재 타이머 의 Lua 협 정 이 걸 립 니 다. 따라서 워 커 프로 세 스 가 모든 남 은 연결 을 닫 을 때 이 예제 에서 setkeepalive 는 아직 실행 되 지 않 았 습 니 다 (연결 이 완료 되 지 않 았 을 수도 있 습 니 다).그래서 이 연결 은 당시 에 한가 하지 않 았 다.나중에 어느 순간 연결 이 완료 되 거나 시간 을 초과 할 때 까지 그 당시 의 Lua 협 정 은 다시 실행 기 회 를 얻 었 기 때문에 이 연결 에 타 이 머 를 추가 하여 빈 상태 로 설정 할 수 있 습 니 다.
워 커 프로 세 스 의 종 료 를 방해 하 는 또 다른 이 유 는 Nginx HTTP / 2 모듈 구현 상의 결함 (Stale workers not exiting after reload (with HTTP / 2 long poll requests 참조) [2] 에서 비롯 됩 니 다.이 문 제 는 Nginx / 1.11.6 이 발 표 된 후에 복구 되 었 습 니 다.
Nginx 는 투명 에이전트 웹 소켓 연결 을 지원 합 니 다.Nginx / 1.13.7 버 전 이전에 워 커 프로 세 스 에 웹 소켓 연결 이 존재 하고 연결 에 데이터 전송 이 자주 있어 서 연결 이 정상적으로 작 동 되 었 다 면 워 커 프로 세 스 가 master 에서 종료 명령 을 받 더 라 도 바로 종료 할 수 없습니다. 이 연결 이 이상 하거나 시간 이 초과 되 거나 특정한 부분 이 자발적으로 끊 어 질 때 까지 기 다 려 야 합 니 다.정상적으로 물 러 날 수 있 습 니 다.
shutdown timeout
오래된 worker 프로 세 스 가 제때에 종료 되 지 않 으 면 시스템 자원 (CPU, 메모리, 파일 설명자 등) 을 계속 사용 합 니 다. 이것 은 시스템 자원 에 낭비 입 니 다. 따라서 Nginx / 1.11.11 은 새로운 명령 (즉, worker shutdown timeout, Core functional 참조) [4] 을 추가 하여 사용자 가 shutdown 시간 초과 시간 을 사용자 정의 할 수 있 도록 합 니 다.워 커 가 종료 명령 을 받 은 후 워 커shutdown_timeout 시간 이 지나 도 물 러 나 지 못 하면 강제로 물 러 납 니 다.
그것 의 실현 원리 (Nginx: 97c99bb 43737) [5] 도 타이머 생 성 을 통 해 이 루어 집 니 다. 타이머 가 만 료 되면 모든 연결 이 close 와 error 상태 (c - > error = 1, c - > close = 1) 로 설 정 됩 니 다. 이 플래그 위 치 는 사실상 TCP 연결 이 이상 하 다 는 것 을 의미 합 니 다. Nginx 디자인 에 서 는 이러한 상태 에 대한 연결 이 즉시 모든 요청 을 끝 냅 니 다.사건이러한 플래그 비트 설정 을 통 해 모든 연결 을 강제로 닫 고 모든 타 이 머 를 삭제 하 는 목적 을 달성 하고 마지막 으로 오래된 워 커 프로 세 스 를 종료 하고 시스템 자원 을 방출 합 니 다.
이 기능 은 Nginx / 1.11.11 에 이미 가 입 했 지만 모든 상황 에 완전히 덮어 쓰 지 않 았 습 니 다. 예 를 들 어 앞에서 말 한 websocket 연결 처리, 그 부분 코드 는 c - > close 와 c - > error 의 상 태 를 판단 하지 않 았 습 니 다.그래서 이 웹 소켓 연결 을 빨리 종료 할 수 없습니다.Nginx / 1.13.7 에 이 르 러 서 야 이 문 제 는 복구 되 었 다.따라서 독자 들 이 비슷 한 문제 에 부 딪 히 면 Nginx 를 최소 1.13.7 버 전 으로 업그레이드 하 는 것 도 고려 할 수 있다.
[1]
문제 페이지: https://github.com/openresty/lua-nginx-module/issues/1279 [2]
결함: https://trac.nginx.org/nginx/ticket/1106 [3]
복구: http://hg.nginx.org/nginx/rev/5e95b9fb33b7 [4]
명령: http://nginx.org/en/docs/ngx_core_module.html#worker_shutdown_timeout [5]
원리: http://hg.nginx.org/nginx/rev/97c99bb43737 '내 눈 에 보 이 는 Nginx' 시리즈:
내 눈 에 보 이 는 Nginx (3): Nginx 변수 와 변수 삽입 값 내 눈 에 보 이 는 Nginx (2): HTTP / 2 dynamic table size update 내 눈 에 보 이 는 Nginx (1): Nginx 와 비트 연산
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.