NGINX 는 놀 라 운 사람들 을 어떻게 처리 합 니까?

12651 단어 nginx
앞 에 쓰다
NGINX 시리즈 의 에 세 이 를 쓰 는 것 은 첫째, 배 운 것 을 정리 하고, 둘 째 는 의 심 스 러 운 점 을 기록 해 다음 학습 과정 에서 의혹 을 해결한다.
또한 NGINX 에 관심 이 있 는 친구 들 도 제 의혹 을 풀 어 주거 나 연 구 를 함께 했 으 면 좋 겠 습 니 다.
NGINX 시리즈 전체 글 에 서 는 제 의혹 을 빨간색 으로 표시 하 며 선배 님 을 만 나 댓 글 에서 잘못된 방향 을 풀 어 줬 으 면 좋 겠 다 고 말 했다.
- nginx 기반 1.4.4
       
(비슷 한 글 블 로 그 는 이미 많 지만 배 운 것 은 기록 을 정리 하지 않 고 자신의 것 으로 변 하지 않 는 다.)
놀 라 움 이란
간단하게 예 를 들 면
TCP 서버 소켓 의 구축 은 보통 socket, bid, listen 초기 화 를 거 친 후 accept 를 호출 하여 클 라 이언 트 의 연결 을 기다 리 고 있 습 니 다.서버 는 일반적으로 listen 후 fork 여러 개의 키 프로 세 스 가 동시에 accept 클 라 이언 트 의 연결 을 합 니 다.
하위 프로 세 스 는 accept 를 호출 한 후에 잠 을 막 습 니 다. 첫 번 째 클 라 이언 트 연결 이 도착 하면 모든 하위 프로 세 스 가 깨 어 납 니 다. 그러나 하나의 하위 프로 세 스 accept 호출 에 성공 할 수 있 습 니 다. 다른 하위 프로 세 스 는 실패 로 돌아 갑 니 다. 코드 의 처 리 는 accept 가 실패 한 후에 accept 를 계속 호출 합 니 다.
기능 적 으로 는 문제 가 없 지만 성능 적 으로 는 낭비 다.부모 프로 세 스 가 accept 를 호출 한 후 하위 프로 세 스 에 연결 을 전달 하 는 처리 방식 이 있 습 니 다.(어떻게 전달 합 니까? fork 시 하위 프로 세 스 가 부모 프로 세 스 의 자원 을 복사 할 줄 은 몰 랐 습 니 다. 따라서 하위 프로 세 스 accept 는 부모 프로 세 스 가 초기 화 된 fd 입 니 다. 그러나 하위 프로 세 스 fork 이후 부모 프로 세 스 가 자식 프로 세 스에 accept 가 전달 하 는 자원 설명자 fd 를 어떻게 전달 합 니까?) 단, 하나의 프로 세 스 가 accept 를 처리 해 야 합 니 다. 사실은 CPU 에 대한 낭비 입 니 다.
(문제 보충: accept 후 fork 하위 프로 세 스 에서 새 연결 을 처리 할 수 있 습 니 다)
놀 라 운 해결
Linux 커 널 2.6 은 accept 의 놀 라 운 문 제 를 해결 하 였 습 니 다. 여러 개의 키 프로 세 스 accept 가 수면 을 막 았 을 때 연결 이 왔 습 니 다. 한 프로 세 스 의 accept 만 깨 워 서 되 돌 아 옵 니 다. 그러나 현재 하위 프로 세 스 의 실현 방식 은 직접 accept 가 아니 라 초기 화 된 fd 를 epoll 의 이벤트 대기 열 에 추가 하 였 습 니 다. epoll 이 돌아 온 후에 accept 를 호출 합 니 다. Linux 는 여러 개의 키 프로 세 스 epoll 을 해결 할 수 없습니다.하위 프로 세 스 가 스스로 처리 해 야 합 니 다.
Nginx 의 처리
Nginx 에서 epoll 을 처리 할 때 놀 라 운 문 제 를 처리 하 는 방향 은 매우 간단 합 니 다. 여러 개의 키 프로 세 스 는 자물쇠 가 있 습 니 다. 누가 자 물 쇠 를 가 져 와 야 accept 의 fd 를 epoll 대기 열 에 넣 을 수 있 습 니까? 다른 하위 프로 세 스 는 자 물 쇠 를 가 져 오지 못 하고 fd 를 epoll 에 넣 지 않 습 니 다. 연결 이 되면 모든 하위 프로 세 스 의 epoll 이 깨 어 나 지 않 습 니 다.
내일 코드 분석.
코드 분석
Nginx 실행 경로
 1 nginx.c:main()

 2     ngx_master_process_cycle()

 3         ngx_start_worker_processes()

 4             ngx_spawn_process()

 5                 ngx_worker_process_cycle() 

 6                 {

 7                     for(;;) {

 8                         ngx_process_events_and_timers()

 9                     }

10                 }
           


스 릴 러 코드
ngx process events and timers () 는 사건 을 처리 합 니 다. 이 함수 의 다음 코드 는 놀 라 운 문 제 를 처리 하 는 동시에 부하 균형 을 실현 합 니 다. 놀 라 운 문제 와 부하 균형 문 제 를 처리 하 는 코드 가 함께 있 기 때문에 아래 와 같이 분석 하 겠 습 니 다.
 1     if (ngx_use_accept_mutex) {

 2         if (ngx_accept_disabled > 0) {

 3             ngx_accept_disabled--;

 4 

 5         } else {

 6             if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {

 7                 return;

 8             }

 9 

10             if (ngx_accept_mutex_held) {

11                 flags |= NGX_POST_EVENTS;

12 

13             } else {

14                 if (timer == NGX_TIMER_INFINITE

15                     || timer > ngx_accept_mutex_delay)

16                 {

17                     timer = ngx_accept_mutex_delay;

18                 }

19             }

20         }

21     }

ngx_use_accept_mutex nginx ngx_accept_mutex (nginx , , ), 。

ngx accept disable 는 부하 균형 을 처리 하 는 데 사 용 됩 니 다.
ngx accept mutex 자 물 쇠 를 사용 한 상황 에서 하나의 프로 세 스 가 accept 사건 을 처리 하려 면 두 가지 조건 을 만족 시 켜 야 한 다 는 것 을 알 수 있 습 니 다.
  • 부하 균형 조건 만족 (부하 압력 이 낮 음, 잠시 후 nginx 가 압력 의 높 고 낮 음 을 어떻게 판단 하 는 지 소개)
  • ngx accept mutex 자물쇠 가 져 오기
  • 부하 균형 조건
    Ngx accept disable 은 accept 이벤트 가 올 바 르 게 처 리 될 때마다 값 을 업데이트 합 니 다.
    ngx_accept_disabled = ngx_cycle->connection_n / 8 - ngx_cycle->free_connection_n;
    connection n 은 설정 파일 에 설 정 된 이 프로 세 스 처리 의 최대 연결 수 입 니 다. free connection n 의 초기 값 은 connection n 입 니 다. 연결 + 를 새로 만 들 고 연결 을 닫 습 니 다.
    (나 는 ngx accept disabled 의 초기 값 이 어디 에 있 는 지 보지 못 했다. 시간 이 있 으 면 디 버 깅 을 해서 초기 값 이 얼마 인지 보 자.)
    free connection n 이 connection n 의 1 / 8 (연결 수가 총수 의 7 / 8 보다 적 음) 보다 클 때 ngx accept disable 은 마이너스 입 니 다. 이 때 프로 세 스 는 잠 금 쟁탈 에 참여 합 니 다. 잠 금 을 얻 으 면 accept 이벤트, 다른 프로 세 스 는 accept 이 벤트 를 처리 하지 않 습 니 다.
    이 프로 세 스 가 accept 사건 을 처리 하 는 것 이 증가 하면 처리 하 는 연결 도 증가 합 니 다. free connection n 이 connection n 의 1 / 8 보다 작 을 때 (연결 수가 총수 의 7 / 8 보다 많 을 때)이 프로 세 스 는 ngx accept disabled 가 옳 습 니 다. 이 프로 세 스 는 간단하게 ngx accept disabled - 를 잠 금 경쟁 에서 종료 하고 기 회 를 다른 프로 세 스에 양보 합 니 다. 이렇게 부하 균형 을 맞 춰 프로 세 스 부하 가 너무 높 지 않도록 합 니 다.
    프로 세 스 의 연결 이 많 을 수록 쟁탈 을 포기 하 는 횟수 가 많 습 니 다. ngx accept disabled - - - 프로 세 스 가 잠 금 쟁탈 에서 계속 종료 되 는 것 을 피하 고 새로운 연결 을 받 아들 이지 않도록 합 니 다.
    모든 프로 세 스 의 연결 수가 비교적 적 을 때, 누가 ngx accept disable 를 빼 앗 았 는 지, 누가 연결 을 처리 하 는 지, 한 프로 세 스 가 비교적 많이 빼 앗 았 을 때, 연결 수가 7 / 8 에 이 르 렀 을 때, 잠 금 의 쟁탈 을 종료 하고, 기 회 를 다른 프로 세 스에 양보 합 니 다. 그렇지 않 을 때, ngx accept disable - 는 일정 시간 후에 도 잠 금 의 쟁탈 에 계속 참가 할 것 을 보장 합 니 다. 모든 프로 세 스 의 연결 수가 7 / 8 보다 많 을 때이 때 새로운 연결 이 오 면 처리 지연 이 비교적 클 것 입 니 다. 모든 프로 세 스 가 쟁탈 을 포 기 했 기 때문에 ngx accept disable - 0 보다 작 을 때 까지 다시 쟁탈 합 니 다.
    ngx accept mutex 자물쇠 가 져 오기
    부하 균형 조건 이 충족 되면 프로 세 스 는 ngx accept mutex 자물쇠 쟁탈 에 참여 합 니 다. ngx trylock accept mutex (cycle)
    Ngx trylock accept mutex 에 오류 가 발생 하여 바로 return 되 었 습 니 다.
    잘못된 상황 은 없습니다.
    ngx accept mutex held = 1 은 자 물 쇠 를 가 져 왔 음 을 나타 낸다.
          flags |= NGX_POST_EVENTS;        ,epoll             ,       post   ,                    ,                        ,  accept       (     )    。 

    ngx accept mutex held = 0 은 자 물 쇠 를 받 지 못 했 음 을 나 타 냅 니 다.
    잠 금 을 가 져 오지 못 하 는 프로 세 스 는 epoll 의 시간 초과 시간 을 수정 하여 epoll 을 가능 한 한 빨리 되 돌려 줍 니 다. 다음 잠 금 쟁탈 에 일찍 참여 하면 새로운 accept 연결 이 벤트 를 신속하게 처리 할 수 있 습 니 다.
    (여기까지 쓴 작가 님 께 감 탄 스 러 울 수 밖 에 없 었 습 니 다. 여러 가지 상황 을 고려 했 습 니 다. 소 야)
     
    이제 자물쇠 에 관 한 전쟁 을 보 겠 습 니 다.
     
     1 ngx_int_t
    
     2 ngx_trylock_accept_mutex(ngx_cycle_t *cycle)
    
     3 {
    
     4     if (ngx_shmtx_trylock(&ngx_accept_mutex)) {
    
     5         if (ngx_accept_mutex_held
    
     6             && ngx_accept_events == 0
    
     7             && !(ngx_event_flags & NGX_USE_RTSIG_EVENT))
    
     8         {
    
     9             return NGX_OK;
    
    10         }
    
    11         if (ngx_enable_accept_events(cycle) == NGX_ERROR) {
    
    12             ngx_shmtx_unlock(&ngx_accept_mutex);
    
    13             return NGX_ERROR;
    
    14         }
    
    15         ngx_accept_events = 0;
    
    16         ngx_accept_mutex_held = 1;
    
    17 
    
    18         return NGX_OK;
    
    19     }
    
    20     if (ngx_accept_mutex_held) {
    
    21         if (ngx_disable_accept_events(cycle) == NGX_ERROR) {
    
    22             return NGX_ERROR;
    
    23         }
    
    24         ngx_accept_mutex_held = 0;
    
    25     }
    
    26     return NGX_OK;
    
    27 }

     
    line4       자물쇠 가 져 오기
    line20     자 물 쇠 를 가 져 오지 않 았 지만, ngx accept mutex held 는 1 로 이상 합 니 다. 현재 프로 세 스 가 accept 이 벤트 를 처리 하 는 것 을 금지 합 니 다. (accept fd 를 epoll 대기 열 에서 제거 합 니 다.) ngx accept mutex held = 0 리 셋 합 니 다.
    line5-10   자 물 쇠 를 성공 적 으로 가 져 왔 습 니 다. 자신 이 이미 이 자 물 쇠 를 얻 었 다 는 것 을 알 게 되 었 습 니 다. 다만 accept 사건 이 발생 하지 않 았 을 뿐 다시 한 번 순환 하여 이 자 물 쇠 를 계속 얻 었 습 니 다. (첫 번 째 는 사건 이 발생 하지 않 았 습 니 다. 자 물 쇠 를 풀 고 두 번 째 쟁탈 에 들 어가 야 합 니까?)
    line 11 - 16 잠 금 에 성공 한 후 acceptfd 를 epoll 대기 열 에 추가 하여 accept 이 벤트 를 감청 할 준 비 를 하고 ngx accept mutex head = 1 은 잠 금 을 가 져 왔 음 을 표시 합 니 다 (ngx accept events 는 구체 적 으로 언제 사용 할 것 인지).

    좋은 웹페이지 즐겨찾기