>  기사  >  백엔드 개발  >  nginx 소스 코드 연구 노트(21) - 이벤트 모듈 2 - 이벤트 기반 코어 ngx_process_events_and_timers

nginx 소스 코드 연구 노트(21) - 이벤트 모듈 2 - 이벤트 기반 코어 ngx_process_events_and_timers

WBOY
WBOY원래의
2016-07-29 09:11:021718검색

우선, 이전 서브스레드 실행 연산에 관련되지 않은 내용인 ngx_process_events_and_timers가 있다는 점을 계속해서 상기해 보겠습니다. 오늘은 이 함수에 대해 공부하겠습니다.

이 기사의 출처: http://blog.csdn.net/lengzijian/article/details/7601730

섹션 19의 일부 스크린샷을 살펴보겠습니다.

nginx 源码学习笔记(二十一)—— event 模块二 ——事件驱动核心ngx_process_events_and_timers

오늘은 이벤트 중심 기능을 주로 설명하겠습니다. 사진에서 빨간색 부분:

[cpp] view 일반 카피프린트?

  1. src/event/ngx_event.c  
  2.   
  3. void   
  4. ngx_process_events_and_timers(ngx_cycle_t *cycle)  
  5. {  
  6.     ngx_uint_t  플래그;  
  7.     ngx_msec_t  타이머, 델타;  
  8.   
  9.     if (ngx_timer_solution) {  
  10.         타이머 = NGX_TIMER_INFINITE;  
  11.         플래그 = 0;  
  12.   
  13.     } 그 외 {  
  14.         타이머 = ngx_event_find_timer();  
  15.         플래그 = NGX_UPDATE_TIME;  
  16.     }  
  17.       
  18.     /* 
  19.     ngx_use_accept_mutex变weight代表是否使用accept互斥体 
  20.     默认是使用,可通过accept_mutex off;指令关闭; 
  21.     뮤텍스 수락 적작용就是避免惊群,同时实现负载均衡 
  22.     */   
  23.      (ngx_use_accept_mutex) {  
  24.         /* 
  25.         ngx_accept_disabled变weight 에서ngx_event_accept函数中计算。 
  26.         如果ngx_accept_disabled大于0,就表示该进程接受的链接过多, 
  27.         因此放弃一次争抢수락 mutex의 机会,同时将自己减一。 
  28.         然后 继续处理已有连接上的事件。 
  29.         nginx就利用这一点实现了继承关于连接的基本负载均衡。 
  30.         */  
  31.         인 경우 (ngx_accept_disabled > 0) {  
  32.             ngx_accept_ 장애인--;  
  33.   
  34.         } 그밖에 {  
  35.             /* 
  36.            尝试锁accept mutex,只有成功获取锁的进程,才会将들어보세요套接字放到epoll中。 
  37.            因此,这就保证了只有一个进程拥有监听套接口,故所有进程阻塞在epoll_wait时, 
  38.             才不会惊群现象。
  39. */
  40. 🎜 > (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {                                  🎜>                           >
  41. 프로세스가 잠금을 획득하면 NGX_POST_EVENTS 플래그가 추가됩니다.
  42. 이 플래그의 기능은 생성된 모든 이벤트를
  43. 대기열에 넣은 다음 이벤트가 해제된 후 천천히 이벤트를 처리하는 것입니다. .
  44. 처리 시간이 매우 오래 걸릴 수 있으므로 잠금을 먼저 해제하고 처리하지 않으면 프로세스가 오랫동안 잠금을 차지하게 됩니다. ,
  45. 결과적으로 다른 프로세스가 잠금을 얻을 수 없으므로 ACCEPT의 효율성이 낮습니다.
  46. _POST_EVENTS
  47.                                                                   
  48. /*
  49. 획득된 프로세스가 없으며 물론 NGX_POST_EVENTS 플래그도 필요하지 않습니다.
  50. 하지만 잠금을 위해 싸우기 전에 지연 시간을 설정해야 합니다.> == NGX_TIMER_INFINITE
  51. || 타이머 > )                                                                       타이머 = cept_mutex_delay;
  52. }
  53.                                             🎜>
  54.  델타 = ngx_current_msec;
  55.  
  56. /*다음으로 epoll은 대기 이벤트를 시작합니다.
  57. ngx_process_events의 구체적인 구현은 epoll 모듈의 ngx_epoll_process_events 함수에 해당합니다.
  58. 자세한 내용은 나중에 설명하겠습니다
  59. * /
  60. (void) ngx_process_events(주기, 타이머, 플래그) ;
  61. //이 대기 이벤트의 시간 소비 통계
  62. delta = ngx_current_msec - 델타
  63. ngx_log_debug1(NGX_LOG_DEBUG_EVENT, 사이클->log, 0,       " 타이머 델타: %M", 델타);
  64. >
  65. ngx_posted_accept_events는 epoll이 청취 소켓에서 기다리는 수락 이벤트를 임시로 저장하는 이벤트 queue입니다.
  66. 위에서 언급한 NGX_POST_EVENTS 플래그가 사용된 후 모든 수락 이벤트는 이 대기열
  67. */
  68. ngx_event_process_posted (cycle, &ngx_posted_accept_events) 🎜>  //모든 승인 이벤트 처리 후 잠금이 유지되면 해제합니다.
  69. if (ngx_accept_mutex_held) { ngx_shmtx_unlock(&ngx_accept_mutex)                                      🎜>
  70. delta는 이전에 계산된 시간 소모입니다. 밀리초 수준의 시간 소모가 있는 경우
  71. 경우입니다. timeout을 사용하는 경우, time rbtree에서 만료된 타이머를 삭제하고 해당 이벤트의 핸들러 함수를 호출하여 처리
  72. */
  73. if
  74. (델타) {
  75. ngx_event_expire_timers( );
  76. }
  77.                                                > /*
  78. 일반 이벤트 처리(연결에서 얻은 이벤트 읽기 및 쓰기),
  79. 이벤트마다 고유한 핸들러 메소드가 있으므로
  80. */
  81.  if (ngx_posted_events) {
  82.  
  83. if
  84. (ngx_threaded) {
  85. ngx _wakeup_worker_thread(주기)
  86. } else
  87. {
  88. ngx_event_process_posted(cycle, &ngx_posted_events)
  89. }
  90. }  
  91. 앞서 말한 accept 이벤트는 실제로 소켓에서 새 이벤트를 수신합니다. 승인 시간 방법은 아래와 같습니다:
  92. ngx_event_accept:
  93. [cpp] 보기 일반 카피프린트?
    1. src/event/ngx_event_accept.c  
    2.   
    3. void   
    4. ngx_event_accept(ngx_event_t *ev)  
    5. {  
    6.     socklen_t          socklen;  
    7.     ngx_err_t          오류;  
    8.     ngx_log_t         *log;  
    9.     ngx_socket_t       s;  
    10.     ngx_event_t       *rev, *wev;  
    11.     ngx_listening_t   *ls;  
    12.     ngx_connection_t  *c, *lc;  
    13.     ngx_event_conf_t  *ecf;  
    14.     u_char             sa[NGX_SOCKADDRLEN];  
    15.       
    16.     //省略part代码  
    17.   
    18.     lc = ev->data;  
    19.     ls = lc->듣기;  
    20.     ev->준비 = 0;  
    21.   
    22.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,  
    23.                    "%V에서 수락, 준비: %d", &ls->addr_text, ev->사용 가능);  
    24.   
    25.     하세요 {  
    26.         socklen = NGX_SOCKADDRLEN;  
    27.         //accept 一个 new连接  
    28.         s = accept(lc-> ;fd, (struct sockaddr *) sa, &socklen);  
    29.         //省略part代码  
    30.           
    31.         /* 
    32.         accept到一个新的连接后,就重新计算ngx_accept_disabled的值, 
    33.         它主要是用来做负载均衡,之前有提过。 
    34.          
    35.         这里,我们可以看到他的就只方式 
    36.         “总连接数的八分之一-   剩余的连接数“ 
    37.         总连接指每个进程设数,这个数字可以再配置文件中指정입니다.
    38.                                                                                                ngx_accept_disabled가 0보다 크고 연결이 과부하되었습니다
    39. 🎜>
    40. ngx_accept_disabled = ngx_cycle->connection_n / 8
    41. - ngx_cycle- >free_connection_n;
    42. >
    43. c = ngx_get_connection(s, ev->log)
    44. //새 링크에 대한 메모리 풀 생성
    45. >
    46. c->pool = ngx_create_pool(ls->pool_size, ev->log); 🎜>
    47.                                                                                     이온(c );
    48. c->sockaddr = ngx_palloc(c->pool, socklen); > if (c->sockaddr == NULL) {
    49. ngx_close_accepted_connection(c); > return; c->sockaddr, sa, socklen) 🎜>(ngx_log_t));
    50. >
    51. ngx_close_accepted_connection(c)
    52. 🎜> }  
    53.   
    54.         /* aio에 대한 차단 모드 및 기타에 대한 비차단 모드 설정*/
    55.   
    56.         if (ngx_inherited_nonblocking) {  
    57.            인 경우 (ngx_event_flags & NGX_USE_AIO_EVENT) {  
    58.                if (ngx_blocking( s) == -1) {  
    59.                  ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,  
    60.                                 ngx_blocking_n " 실패했습니다");  
    61.                    ngx_close_accepted_connection(c);  
    62.                   반품;  
    63.                }  
    64.            }  
    65.   
    66.         } else {  
    67.            //我们使用epoll模型 ,这里我们设置连接为논블로킹  
    68.             (!(ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT))) {  
    69.                if (ngx_nonblocking(s) == -1) {  
    70.                    ngx_log _error(NGX_LOG_ALERT, ev->log , ngx_socket_errno,  
    71.                              ngx_nonblocking_n " 실패했습니다");  
    72.                    ngx_close_accepted_connection(c);  
    73.                   반품;  
    74.                }  
    75.            }  
    76.         }  
  94.   
  95.         *log = ls->log;  
  96.         //初始化新的连接  
  97.         c->recv = ngx_rec v;  
  98.         c->send = ngx_send;  
  99.         c->recv_chain = ngx_recv_chain;  
  100.         c->send_chain = ngx_send_chain;  
  101.   
  102.         c->log = log;  
  103.         c->풀->log = log;  
  104.   
  105.         c->socklen = socklen;  
  106.         c->듣기 = ls;  
  107.         c->local_sockaddr = ls->sockaddr;  
  108.   
  109.         c->unexpected_eof = 1;  
  110.   
  111. #if (NGX_HAVE_UNIX_DOMAIN)  
  112.         if (c->sockaddr->sa_family == AF_UNIX) {  
  113.             c->tcp_nopush = NGX_ TCP_NOPUSH_DISABLED ;  
  114.             c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;  
  115. #if (NGX_SOLARIS)  
  116.            /* Solaris의 sendfilev() AF_NCA, AF_INET 및 AF_INET6 지원*/  
  117.            c->sendfile = 0;  
  118. #endif  
  119.        }  
  120. #endif  
  121.   
  122.         rev = c->read;  
  123.         wev = c->write;  
  124.   
  125.         wev->ready = 1;  
  126.   
  127.          (ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT)) {  
  128.            /* rtsig, aio, iocp */  
  129.             rev->ready = 1;  
  130.         }  
  131.   
  132.         (ev- >deferred_accept) {  
  133.             rev->준비 = 1;  
  134. #if (NGX_HAVE_KQUEUE)  
  135.             rev->사용 가능 = 1;  
  136. #endif  
  137.         }  
  138.   
  139.         rev->log = log;  
  140.         wev->log = log;  
  141.   
  142.         /* 
  143.          * TODO: MT: - ngx_atomic_fetch_add() 
  144.          *           또는 중요한 섹션 또는 가벼운 뮤텍스에 의한 보호
  145.         * 
  146.          * TODO: MP: - 공유 메모리에 할당됨 
  147.          * - ngx_atomic_fetch_add() 
  148.          *          또는 중요한 섹션이나 가벼운 뮤텍스에 의한 보호
  149.          * /  
  150.   
  151.         c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);  
  152.           
  153.         인 경우 (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {  
  154.             인 경우 (ngx_add_conn(c) == NGX_ERROR) {  
  155.                 ngx_close_accepted_connection(c );  
  156.                반품;  
  157.             }  
  158.        }  
  159.   
  160.         로그->데이터 = NULL;  
  161.         로그->핸들러 = NULL;  
  162.           
  163.         /* 
  164.         这里듣기 핸들러很重要,它将完成新连接的最后初始化工事, 
  165.         동종挂에는 핸들러가 있습니다.函数, 
  166.         就是ngx_http_init_connection 지금 지后http模块中재详细介绍 
  167.         */   
  168.         ls->handler(c);  
  169.   
  170.         if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {  
  171.             ev->사용 가능--;  
  172.         }  
  173.   
  174.     } 동안 (ev ->사용 가능);  
  175. }  

accpt事件的handler방식也就是如此了。지后就是每个连接的读写事件handler방식,这一part分会直接将我们引入http模块,我们还不急,还要school习下nginx经典模块epoll。

위 내용은 nginx 소스 코드 연구 노트(21) - 이벤트 모듈 2 - 대기열 콘텐츠를 포함한 이벤트 중심 코어 ngx_process_events_and_timers를 소개합니다. PHP 튜토리얼에 관심이 있는 친구들에게 도움이 되기를 바랍니다.

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