>  기사  >  운영 및 유지보수  >  nginx 성능이 좋은 이유는 무엇입니까?

nginx 성능이 좋은 이유는 무엇입니까?

藏色散人
藏色散人원래의
2019-06-12 10:11:342693검색

nginx 성능이 좋은 이유는 무엇입니까?

nginx는 시작된 후 Unix 시스템에서 데몬으로 백그라운드에서 실행됩니다. 백그라운드 프로세스에는 마스터 프로세스와 여러 작업자 프로세스가 포함됩니다. 또한 수동으로 백그라운드 모드를 끄고, nginx를 포그라운드에서 실행하고, nginx가 마스터 프로세스를 취소하도록 구성하여 nginx가 단일 프로세스 모드에서 실행될 수 있도록 할 수도 있습니다.

분명히 프로덕션 환경에서는 절대 이 작업을 수행하지 않을 것이므로 일반적으로 디버깅을 위해 백그라운드 모드를 끄는 것이 사용됩니다. 다음 장에서는 nginx를 디버깅하는 방법을 자세히 설명하겠습니다.

그래서 우리는 nginx가 멀티 프로세스 방식으로 작동한다는 것을 알 수 있습니다. 물론 nginx도 멀티 스레딩을 지원하지만 우리의 주류 방식은 여전히 ​​nginx의 기본 방식이기도 한 멀티 프로세스 방식입니다. nginx에서 멀티 프로세스를 사용하면 장점이 많기 때문에 nginx의 멀티 프로세스 모드를 중심으로 설명하겠습니다.

지금 언급했듯이 nginx가 시작된 후에는 마스터 프로세스와 여러 작업자 프로세스가 있습니다. 마스터 프로세스는 외부 세계로부터 신호 수신, 각 작업자 프로세스에 신호 보내기, 작업자 프로세스의 실행 상태 모니터링, 작업자 프로세스 종료 시 자동으로 새 작업자 프로세스 다시 시작 등 작업자 프로세스를 관리하는 데 사용됩니다. 비정상적인 상황).

기본 네트워크 이벤트는 작업자 프로세스에서 처리됩니다. 여러 작업자 프로세스는 P2P 방식으로 클라이언트의 요청을 놓고 동등하게 경쟁하며 각 프로세스는 서로 독립적입니다. 요청은 하나의 작업자 프로세스에서만 처리할 수 있으며 작업자 프로세스는 다른 프로세스의 요청을 처리할 수 없습니다. 작업자 프로세스 수는 설정할 수 있으며 일반적으로 머신의 CPU 코어 수와 일치하도록 설정합니다. 그 이유는 nginx의 프로세스 모델 및 이벤트 처리 모델과 불가분의 관계입니다.

nginx가 시작된 후 nginx를 운영하려면 어떻게 해야 하나요?

위에서 보면 마스터가 작업자 프로세스를 관리한다는 것을 알 수 있으므로 마스터 프로세스와만 통신하면 됩니다. 마스터 프로세스는 외부 세계로부터 신호를 수신한 다음 신호를 기반으로 다양한 작업을 수행합니다. 따라서 nginx를 제어하려면 kill을 통해 마스터 프로세스에 신호를 보내기만 하면 됩니다. 예를 들어, kill -HUP pid는 nginx에게 nginx를 정상적으로 다시 시작하도록 지시합니다. 일반적으로 이 신호를 사용하여 nginx를 다시 시작하거나 구성을 다시 로드하므로 서비스가 중단되지 않습니다. HUP 신호를 받은 후 마스터 프로세스는 무엇을 합니까?

먼저 신호를 받은 후 마스터 프로세스는 구성 파일을 다시 로드한 다음 새 작업자 프로세스를 시작하고 모든 이전 작업자 프로세스에 신호를 보내 명예롭게 은퇴할 수 있음을 알립니다.

새 작업자가 시작된 후 새 요청을 받기 시작합니다. 이전 작업자가 마스터로부터 신호를 받은 후에는 더 이상 새 요청을 받지 않으며, 완료되면 현재 프로세스에서 처리되지 않은 모든 요청이 처리됩니다. 다시.

물론 마스터 프로세스에 직접 신호를 보내는 것은 nginx 버전 0.8 이후 관리를 용이하게 하기 위해 일련의 명령줄 매개변수를 도입한 오래된 작업 방법입니다. 예를 들어 ./nginx -s reload는 nginx를 다시 시작하는 것이고 ./nginx -s stop은 nginx 실행을 중지하는 것입니다.

어떻게 하나요?

다시 로드를 예로 들어 보겠습니다. 명령을 실행할 때 새 nginx 프로세스가 시작되고 새 nginx 프로세스가 다시 로드 매개변수를 구문 분석한 후 우리의 목적은 구성 파일을 다시 로드하도록 nginx를 제어하는 ​​것임을 알 수 있습니다. , 마스터 프로세스에 신호를 보내고 다음 작업은 마스터 프로세스에 직접 신호를 보낸 것과 동일합니다.

이제 nginx를 운영할 때 nginx가 내부적으로 무엇을 하는지 알았습니다. 그러면 작업자는 요청을 어떻게 처리할까요? 앞서 언급했듯이 작업자 프로세스는 동일하며 각 프로세스는 요청을 처리할 수 있는 동일한 기회를 갖습니다. 포트 80에서 http 서비스를 제공하고 연결 요청이 오면 각 프로세스가 연결을 처리할 수 있습니다.

먼저 각 작업자 프로세스는 마스터 프로세스에서 분기됩니다. 마스터 프로세스에서는 수신해야 하는 소켓(listenfd)이 먼저 설정된 다음 여러 작업자 프로세스가 분기됩니다. 새 연결이 도착하면 모든 작업자 프로세스의 Listenfd를 읽을 수 있게 됩니다. 하나의 프로세스만 연결을 처리하도록 하기 위해 모든 작업자 프로세스는 Listenfd 읽기 이벤트를 등록하기 전에 accept_mutex를 가져옵니다. 뮤텍스를 가져오는 프로세스는 Listenfd 읽기 이벤트를 등록합니다. 연결을 수락하려면 읽기 이벤트를 수락하세요.

작업자 프로세스가 연결을 수락하면 요청을 읽고, 요청을 구문 분석하고, 요청을 처리하고, 데이터를 생성한 다음 이를 클라이언트에 반환하고, 마지막으로 연결을 끊습니다. 이것이 완전한 요청의 모습입니다. . 요청이 작업자 프로세스에 의해 완전히 처리되고 하나의 작업자 프로세스에서만 처리되는 것을 볼 수 있습니다.

멀티스레딩 모델 VS 멀티프로세스 모델, 질문입니다!

그렇다면 nginx가 이 프로세스 모델을 채택하면 어떤 이점이 있을까요? 물론 분명 많은 이점이 있을 것입니다. 우선, 각 작업자 프로세스는 독립적인 프로세스이며 잠금이 필요하지 않으므로 잠금으로 인한 오버헤드가 제거되는 동시에 프로그래밍 및 문제 발견 시 훨씬 편리해집니다. 둘째, 독립적인 프로세스를 사용하면 서로 영향을 미치지 않습니다. 한 프로세스가 종료된 후에도 다른 프로세스는 계속 작동하며 서비스는 중단되지 않습니다. 마스터 프로세스는 신속하게 새 작업자 프로세스를 시작합니다. 물론 작업자 프로세스가 비정상적으로 종료되면 프로그램에 버그가 있는 것이 틀림없으며 비정상적으로 종료하면 현재 작업자에 대한 모든 요청이 실패하게 되지만 모든 요청에 ​​영향을 미치지는 않으므로 위험이 줄어듭니다. 물론 장점도 많고, 누구나 천천히 경험할 수 있습니다.

위에서는 nginx의 프로세스 모델에 대해 많이 설명했습니다. 다음으로 nginx가 이벤트를 처리하는 방법을 살펴보겠습니다.

어떤 사람들은 nginx가 요청을 처리하기 위해 다중 작업자 방식을 사용한다고 요청할 수 있습니다. 각 작업자에는 하나의 메인 스레드만 있으므로 처리할 수 있는 동시 작업 수가 매우 제한됩니다. 동시성이 없는데 어떻게 동시성이 높아지나요? 아니요, 이것이 nginx의 장점입니다. nginx는 요청을 처리하기 위해 비동기식 및 비차단 방식을 사용합니다. 즉, nginx는 동시에 수천 개의 요청을 처리할 수 있습니다.

Apache의 일반적인 작동 방식을 생각해 보세요(Apache에도 비동기식 비차단 버전이 있지만 자체 모듈 중 일부와 충돌하기 때문에 일반적으로 사용되지 않습니다). 고유한 작업 스레드를 점유합니다. 동시성 수가 수천에 도달하면 동시에 요청을 처리하는 스레드가 수천 개가 됩니다. 이는 운영 체제에 있어서 큰 과제입니다. 스레드로 인한 메모리 사용량이 매우 크고, 스레드 컨텍스트 전환으로 인한 CPU 오버헤드도 매우 크기 때문에 당연히 성능을 향상할 수 없으며 이러한 오버헤드는 전혀 의미가 없습니다.

동기 차단 VS 비동기 비차단

nginx가 비동기 비차단 방식으로 처리할 수 있는 이유 또는 비동기 비차단이 정확히 무엇인지 -차단 무슨 일이야? 시작점으로 돌아가서 요청의 전체 프로세스를 살펴보겠습니다. 먼저 요청이 들어오고 연결이 설정된 다음 데이터를 수신한 후 데이터를 전송합니다. 시스템의 하위 계층에 특정한 읽기 및 쓰기 이벤트는 읽기 및 쓰기 이벤트가 준비되지 않은 경우 필연적으로 작동하지 않게 됩니다. 통화를 차단하세요. 이벤트가 준비되지 않은 경우 기다리기만 하면 됩니다. 이벤트가 준비되면 계속할 수 있습니다. 차단 호출은 커널에 들어가서 대기하며 다른 사람이 CPU를 사용하게 됩니다. 이는 단일 스레드 작업자에게는 분명히 적합하지 않습니다. 네트워크 이벤트가 많으면 모두가 대기하고 유휴 상태에서는 아무도 CPU를 사용하지 않습니다. . CPU 활용도는 당연히 높은 동시성은 커녕 속도도 올라갈 수 없습니다.

알겠습니다. 프로세스 수를 추가한다고 하셨는데, 이것이 Apache의 스레드 모델과 다른 점은 무엇입니까? 불필요한 컨텍스트 전환이 증가하지 않도록 주의하세요. 따라서 nginx에서는 시스템 호출을 차단하는 것이 가장 금기시됩니다. 차단하지 마세요. 그러면 비차단입니다. 비차단이란 이벤트가 준비되지 않은 경우 이벤트가 아직 준비되지 않았음을 알리기 위해 즉시 EAGAIN으로 돌아가는 것을 의미합니다. 나중에 다시 오세요. 자, 잠시 후 이벤트가 준비될 때까지 다시 이벤트를 확인해 보세요. 이 기간 동안에는 다른 작업을 먼저 하신 후 이벤트가 준비되었는지 확인하시면 됩니다. 더 이상 차단되지는 않지만 수시로 이벤트 상태를 확인해야 더 많은 작업을 수행할 수 있지만 오버헤드가 적지 않습니다. 따라서 비동기식 비차단 이벤트 처리 메커니즘이 있으며 특정 시스템 호출은 select/poll/epoll/kqueue와 같은 시스템 호출입니다.

이는 동시에 여러 이벤트를 모니터링할 수 있는 메커니즘을 제공하지만 시간 제한 내에 이벤트가 준비되면 반환되도록 설정할 수 있습니다. 이 메커니즘은 위의 두 가지 문제를 해결합니다. epoll을 예로 들어보겠습니다(다음 예에서는 이러한 유형의 함수를 나타내기 위해 종종 epoll을 사용합니다). 이벤트가 준비되면 읽고 쓰기로 이동합니다. 읽기 및 쓰기가 EAGAIN을 반환하면 이를 다시 epoll에 추가합니다. 이런 식으로 이벤트가 준비되면 처리하고, 모든 이벤트가 준비되지 않은 경우에만 epoll에서 기다리게 됩니다. 이런 식으로 많은 수의 동시 요청을 처리할 수 있습니다. 물론 여기서 동시 요청은 처리되지 않은 요청을 의미하므로 동시에 처리할 수 있는 요청은 하나뿐입니다. 요청 사이를 계속 전환하면 됩니다. 비동기 이벤트가 준비되지 않았기 때문에 전환이 자발적으로 포기되었습니다. 여기서 전환하는 데는 비용이 들지 않습니다. 실제로는 루프에서 준비된 여러 이벤트를 처리하는 것으로 이해할 수 있습니다.

이 이벤트 처리 방법은 멀티 스레딩과 비교하여 스레드를 생성할 필요가 없고 각 요청이 메모리를 거의 차지하지 않으며 컨텍스트 전환이 없으며 이벤트 처리가 매우 빠르다는 장점이 있습니다. .경량. 동시성이 아무리 많아도 불필요한 리소스 낭비(컨텍스트 전환)가 발생하지 않습니다. 더 많은 동시성은 더 많은 메모리를 차지할 뿐입니다. 이전에 연결 수를 테스트한 적이 있습니다. 24G 메모리가 있는 시스템에서 처리된 동시 요청 수가 200만 개를 초과했습니다. 오늘날의 네트워크 서버는 기본적으로 이 방식을 사용하는데, 이는 nginx가 높은 성능을 발휘하는 주된 이유이기도 합니다.

앞서 작업자 수를 CPU 코어 수로 설정하는 것이 권장된다고 말한 바 있습니다. 작업자가 많아지면 프로세스가 CPU 리소스를 두고 경쟁하게 되어 불필요한 컨텍스트 전환이 발생한다는 것을 이해하기 쉽습니다.

게다가, nginx는 멀티 코어 기능을 더 잘 활용하기 위해 특정 프로세스를 특정 코어에 바인딩할 수 있는 CPU 선호도 바인딩 옵션을 제공하므로 걱정할 필요가 없습니다. 전환하면 캐시 오류가 발생합니다. 이와 같은 작은 최적화는 nginx에서 매우 일반적이며 nginx 작성자의 고된 노력을 보여줍니다. 예를 들어 nginx는 4바이트 문자열을 비교할 때 4자를 int 유형으로 변환한 다음 이를 비교하여 CPU 명령어 수를 줄이는 등의 작업을 수행합니다.

이제 nginx가 왜 이런 프로세스 모델과 이벤트 모델을 선택하는지 알겠습니다. 기본 웹 서버의 경우 일반적으로 네트워크 이벤트, 신호 및 타이머의 세 가지 유형의 이벤트가 있습니다. 위의 설명을 통해 우리는 네트워크 이벤트가 비동기 비차단을 통해 잘 해결될 수 있다는 것을 알고 있습니다. 신호와 타이머를 어떻게 처리하나요?

첫 번째, 신호 처리입니다.

nginx에는 특정 의미를 나타내는 특정 신호가 있습니다. 신호는 프로그램의 현재 실행을 중단하고 상태를 변경한 후에도 실행을 계속합니다. 시스템 호출인 경우 시스템 호출이 실패하고 재진입이 필요할 수 있습니다. 신호 처리에 관해서는 전문적인 서적을 공부할 수 있으므로 여기서는 자세히 다루지 않겠습니다. nginx의 경우 nginx가 이벤트를 기다리고 있는 경우(epoll_wait 동안) 프로그램이 신호를 수신하면 신호 처리 함수가 처리된 후 epoll_wait가 오류를 반환하고 프로그램은 다시 epoll_wait 호출에 들어갈 수 있습니다.

그리고 타이머도 살펴볼까요? epoll_wait 및 기타 함수는 호출 시 시간 초과를 설정할 수 있으므로 nginx는 이 시간 초과를 사용하여 타이머를 구현합니다. nginx의 타이머 이벤트는 타이머를 유지하는 레드-블랙 트리에 배치됩니다. epoll_wait를 입력하기 전에 매번 모든 타이머 이벤트의 최소 시간은 레드-블랙 트리에서 얻어지고 epoll_wait의 시간 초과가 계산됩니다. 시간.

따라서 이벤트가 생성되지 않고 인터럽트 신호도 없으면 epoll_wait는 시간 초과됩니다. 즉, 타이머 이벤트가 도착했습니다. 이때 nginx는 모든 타임아웃 이벤트를 확인하고 상태를 타임아웃으로 설정한 후 네트워크 이벤트를 처리합니다. 이를 통해 우리가 nginx 코드를 작성할 때 네트워크 이벤트의 콜백 함수를 처리할 때 일반적으로 가장 먼저 하는 일은 타임아웃을 결정한 다음 네트워크 이벤트를 처리하는 것임을 알 수 있습니다.

더 많은 Nginx 관련 지식을 보려면 Nginx 사용 튜토리얼 컬럼을 방문하세요!

위 내용은 nginx 성능이 좋은 이유는 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.