Nginx 이벤트 순환
13753 단어 nginx
/* for each listening socket */
/* connection , slot*/
ls = cycle->listening.elts; // master ,
for (i = 0; i < cycle->listening.nelts; i++) {
// connection, c connection
c = ngx_get_connection(ls[i].fd, cycle->log);
if (c == NULL) {
return NGX_ERROR;
}
c->log = &ls[i].log;
c->listening = &ls[i]; //
ls[i].connection = c; // connection
rev = c->read; //rev connection
rev->log = c->log;
rev->accept = 1; // accept , epoll accept
#if (NGX_HAVE_DEFERRED_ACCEPT)
rev->deferred_accept = ls[i].deferred_accept;
#endif
if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) {
if (ls[i].previous) {
/*
* delete the old accept events that were bound to
* the old cycle read events array
*/
old = ls[i].previous->connection;
if (ngx_del_event(old->read, NGX_READ_EVENT, NGX_CLOSE_EVENT)
== NGX_ERROR)
{
return NGX_ERROR;
}
old->fd = (ngx_socket_t) -1;
}
}
/* ngx_event_accept*/
rev->handler = ngx_event_accept; // socket
이 부분 코드 는 워 커 프로 세 스에 서 모든 listening 에 하나의 connection 을 할당 하고 이 connection 의 읽 기 이벤트 처리 함 수 를 ngx 로 설정 합 니 다.event_accept 함수, 즉 이 함수 로 listening 의 accept 를 처리 합 니 다. 자, 이제 이 함수 부터 봅 시다. (이 함 수 는 Ngx event accept. c 로 정 의 됩 니 다.)
lc = ev->data; // connection
ls = lc->listening;
ev->ready = 0;
// epoll , ,
do {
socklen = NGX_SOCKADDRLEN;
// accept socket
s = accept(lc->fd, (struct sockaddr *) sa, &socklen);
위의 코드 는 먼저 이벤트 변수 에서 이 이벤트 에 대응 하 는 connection 을 가 져 오고, 이어서 accept 함 수 를 호출 하여 감청 하 는 socket 설명 부호 에서 연결 을 가 져 올 수 있 습 니 다.
/*accept , ngx_accept_disabled
ngx_accept_disabled , 。
, “ ,
”。 ,
。 , : accept
7/8 ,ngx_accept_disabled 0 ,
。
*/
ngx_accept_disabled = ngx_cycle->connection_n / 8
- ngx_cycle->free_connection_n;
// socket connection
c = ngx_get_connection(s, ev->log);
상기 코드 는 연결 을 가 져 온 후 ngx 를 계산 하 는 데 사 용 됩 니 다.accept_disabled 의 값 은 워 커 프로 세 스 간 부하 균형 을 이 루 는 데 사 용 됩 니 다. 워 커 프로 세 스 가 너무 많은 connection 을 가지 고 있 지 않도록 합 니 다. 구체 적 인 것 은 나중에 말씀 드 리 겠 습 니 다.그 다음 에 연 결 된 socket 설명자 에 connection 을 분배 하 는 것 입 니 다. 다음 코드 는 방금 분 배 된 connection 을 초기 화 하 는 것 입 니 다. 예 를 들 어 메모리 풀 을 분배 하고 socket 설명 자 를 비 차단 으로 설정 하 는 등 입 니 다.
//
if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
if (ngx_add_conn(c) == NGX_ERROR) {
ngx_close_accepted_connection(c);
return;
}
}
log->data = NULL;
log->handler = NULL;
/* listen handler ,
accept epoll ; handler
ngx_http_init_connection( src/http/ngx_http_request.c );
http 。
*/
ls->handler(c);
위의 이 부분 코드 는 비교적 중요 합 니 다. 그것 은 처음으로 ngx 를 호출 합 니 다.add_conn 함수 가 방금 연결 한 것 을 epoll 에 넣 었 습 니 다. 우 리 는 ngx 를 볼 수 있 습 니 다.add_conn 의 정의, Ngxevent. h 중:
#define ngx_add_conn ngx_event_actions.add_conn
사실 여기 앞 글 을 보시 면 ngxadd_conn 은 솔직히 실제 이벤트 모듈 을 호출 하 는 addconn 함수, 실제 epoll 모듈 을 사용 하면 epoll 모듈 의 ngx 를 호출 합 니 다.epoll_add_connection 함수, 다음 코드 가 있 습 니 다:
ls->handler(c);
여 기 는 listening 의 handler 로 방금 분 배 된 connection 을 처리 하 는 것 입 니 다. http 부분 과 관련 된 것 이 니 나중에 다시 이야기 하 겠 습 니 다.
자, 여기까지 ngxevent_accept 함수 가 말 하 는 것 은 많 지 않다.이제 본 격 적 으로 Nginx 의 이벤트 순환 에 들 어 갈 수 있 습 니 다.이벤트 순환 의 입 구 를 먼저 봅 시다. 워 커 프로 세 스 의 실행 함수 ngxworker_process_cycle 에 서 는 순환 할 때마다 사용 되 는 코드 가 있 습 니 다.
// ,
ngx_process_events_and_timers(cycle);
응, ngxprocess_events_and_timers 함 수 는 이벤트 순환 의 입구 함수 로 Ngx 에 정의 되 어 있 습 니 다.이벤트. c 에서 이 함 수 를 분석 하 겠 습 니 다.
/*ngx_use_accept_mutex accept
,accept_mutex off; 。
accept mutex , 。
*/
if (ngx_use_accept_mutex) {
if (ngx_accept_disabled > 0) {
ngx_accept_disabled--;
} else {
/* ngx_accept_disabled 0, */
/* accept mutex, , listen
epoll 。 ,
, epoll_wait , 。
*/
// ngx_trylock_accept_mutex , , worker epoll
if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
return;
}
/* , NGX_POST_EVENTS ,
,
, 。 ,
, ,
, , accept
。
*/
if (ngx_accept_mutex_held) {
flags |= NGX_POST_EVENTS; // ,
} else {
/* , NGX_POST_EVENTS 。
, 。
*/
if (timer == NGX_TIMER_INFINITE
|| timer > ngx_accept_mutex_delay)
{
timer = ngx_accept_mutex_delay;
}
}
}
}
우선 ngx 사용 여 부 를 판단 합 니 다.use_accept_mutex 신 호 량, 이 신 호 량 은 놀 라 움 을 피 하 는 데 사용 된다.현재 worker 프로 세 스 가 이 신 호 량 을 가 져 와 야 listening 을 자신의 epoll 에 진정 으로 추가 할 수 있 습 니 다. 해당 accept 이벤트 입 니 다.여기 도 위 에서 언급 한 ngx 를 보 았 습 니 다.accept_disabled 가 사용 할 수 있 는 역할 입 니 다. 그 는 listening 을 현재 worker 프로 세 스 의 epoll 에 추가 할 지 여 부 를 판단 하 는 데 도 사 용 됩 니 다. 이렇게 하면 부하 균형 을 이 룰 수 있 고 하나의 worker 프로 세 스 가 너무 많은 connection 을 가지 고 있 는 것 을 피 할 수 있 습 니 다.
/*epoll wait ,ngx_process_events
epoll ngx_epoll_process_events 。 epoll
, 。
*/
(void) ngx_process_events(cycle, timer, flags);
이 코드 는 실제 이벤트 모듈 의 process 를 직접 호출 합 니 다.이벤트 함수, 이 벤트 를 처리 하 는 것 은 그 정 의 를 보 는 것 이 좋 습 니 다.
#define ngx_process_events ngx_event_actions.process_events
응, 딱 봐 도 알 겠 어. epoll 모듈 을 사용 하면 그 ngx 를 호출 할 거 야.epoll_process_이벤트 함수.이 따 얘 기 하 자.
if (ngx_posted_accept_events) {
/*ngx_posted_accept_events
epoll wait accept 。
NGX_POST_EVENTS ,
accept 。
accept ,
ngx_event_accept ,
epoll 。
*/
ngx_event_process_posted(cycle, &ngx_posted_accept_events);
}
/* accept , , 。
。
*/
if (ngx_accept_mutex_held) {
ngx_shmtx_unlock(&ngx_accept_mutex);
}
이 부분 코드 는 listening 감청 에서 accept 이 벤트 를 가 져 왔 는 지 판단 합 니 다. 있 으 면 빨리 처리 해 야 합 니 다. 현재 워 커 프로 세 스 가 ngx 를 차지 하고 있 음 을 설명 하기 때 문 입 니 다.accept_mutex 신 호 량, accept 사건 을 처리 한 후 이 신 호 량 을 빨리 방출 하여 다른 worker 프로 세 스 가 이 자 물 쇠 를 가 져 올 수 있 도록 한 다음 listening 에서 연결 을 가 져 옵 니 다.
/* ( ) ,
handler ,
handler 。
*/
if (ngx_posted_events) {
if (ngx_threaded) {
ngx_wakeup_worker_thread(cycle);
} else {
ngx_event_process_posted(cycle, &ngx_posted_events);
}
}
이 부분 은 일반적인 사건 을 처리 하 는 데 쓰 인 다.이렇게 ngxprocess_events_and_timers 함수 에서 사건 을 처리 하 는 부분 은 다 말 했 지만 이 함 수 는 시간 을 처리 하 는 부분 도 있 습 니 다. 이것 은 나중에 Nginx 의 시간 함수 처 리 를 말 할 때 다시 이야기 하 겠 습 니 다.
자, 이제 분석 감 이 방금 언급 한 epoll 모듈 의 ngxepoll_process_이벤트 함수.
// epoll wait, event_list , nevents
/* , timer;nginx
。 timer 。
*/
events = epoll_wait(ep, event_list, (int) nevents, timer); // , , epoll wait ,
우선 epoll 호출wait 함수 가 epoll 에서 발생 한 사건 을 가 져 온 다음 이 사건 들 을 옮 겨 다 닐 수 있 습 니 다:
//
for (i = 0; i < events; i++) {
c = event_list[i].data.ptr; // connection
//instance
instance = (uintptr_t) c & 1;
c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);
rev = c->read;
if (c->fd == -1 || rev->instance != instance) {
/*
* the stale event from a file descriptor
* that was just closed in this iteration
*/
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"epoll: stale event %p", c);
continue;
}
//
revents = event_list[i].events;
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"epoll: fd:%d ev:%04XD d:%p",
c->fd, revents, event_list[i].data.ptr);
//
if (revents & (EPOLLERR|EPOLLHUP)) {
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"epoll_wait() error on fd:%d ev:%04XD",
c->fd, revents);
}
#if 0
if (revents & ~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
"strange epoll_wait() events fd:%d ev:%04XD",
c->fd, revents);
}
#endif
if ((revents & (EPOLLERR|EPOLLHUP))
&& (revents & (EPOLLIN|EPOLLOUT)) == 0)
{
/*
* if the error events were returned without EPOLLIN or EPOLLOUT,
* then add these flags to handle the events at least in one
* active handler
*/
revents |= EPOLLIN|EPOLLOUT;
}
/* , active */
if ((revents & EPOLLIN) && rev->active) {
if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
rev->posted_ready = 1;
} else {
rev->ready = 1;
}
if (flags & NGX_POST_EVENTS) {
// NGX_POST_EVENTS, worker , , accept , accept , event accept 1 , worker
// , , worker
queue = (ngx_event_t **) (rev->accept ?
&ngx_posted_accept_events : &ngx_posted_events);
ngx_locked_post_event(rev, queue);
} else {
rev->handler(rev);
}
}
wev = c->write;
// , connection
if ((revents & EPOLLOUT) && wev->active) {
if (c->fd == -1 || wev->instance != instance) {
/*
* the stale event from a file descriptor
* that was just closed in this iteration
*/
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"epoll: stale event %p", c);
continue;
}
if (flags & NGX_POST_THREAD_EVENTS) {
wev->posted_ready = 1;
} else {
wev->ready = 1;
}
if (flags & NGX_POST_EVENTS) {
ngx_locked_post_event(wev, &ngx_posted_events);
} else {
wev->handler(wev);
}
}
}
위의 코드 는 사실 설명 이 명확 합 니 다. 모든 사건 을 반복 해서 옮 겨 다 니 며 이 사건 의 유형 을 판단 하고 이 사건 의 실제 소속 connection 을 가 져 옵 니 다. 이 벤트 를 읽 는 경우 이 connection 의 read 이 벤트 를 꺼 내 read 의 handler 로 처리 합 니 다. 이 벤트 를 쓰 는 경우 이 connection 의 write 를 가 져 옵 니 다.그리고 write 의 handler 로 처리 합 니 다.하지만 여기 서 주의해 야 할 것 은..
if (flags & NGX_POST_EVENTS) {
// NGX_POST_EVENTS, worker , , accept , accept , event accept 1 , worker
// , , worker
queue = (ngx_event_t **) (rev->accept ?
&ngx_posted_accept_events : &ngx_posted_events);
ngx_locked_post_event(rev, queue);
} else {
rev->handler(rev);
}
이 세그먼트 코드 는 신 호 량 을 가지 고 있 는 지 여 부 를 판단 합 니 다. 앞에서 말 했 듯 이 가지 고 있다 면 이 사건 들 을 대기 열 에 넣 고 잠시 후에 처리 해 야 합 니 다. 여 기 는 신 호 량 을 빨리 방출 할 수 있 도록 이 사건 의 유형 을 판단 하기 위해 accept 사건 인지 일반적인 읽 기 사건 인지 구분 하여 서로 다른 대기 열 에 넣 어야 합 니 다. 음,이벤트 의 accept 도 메 인 은 이전에 이미 말 했 듯 이 이 판단 을 위 한 것 입 니 다.
자, ngxepoll_process_이벤트 함수 도 기본적으로 끝 났 으 니 이벤트 순환 도 많 지 않 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
간단! Certbot을 사용하여 웹 사이트를 SSL(HTTPS)화하는 방법초보자가 인프라 주위를 정돈하는 것은 매우 어렵습니다. 이번은 사이트를 간단하게 SSL화(HTTP에서 HTTPS통신)로 변경하는 방법을 소개합니다! 이번에는 소프트웨어 시스템 Nginx CentOS7 의 환경에서 S...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.