nginx 소스 코드 분석의 이벤트 메커니즘
7604 단어 nginx 소스 코드 분석
본 고 는 사건 메커니즘 의 원리 와 실현 을 분석 할 것 이다.
nginx 자 체 는 poll, epoll, select, ao, kqueue 등 여러 가지 체 제 를 지원 합 니 다. 여기 서 epoll 을 분석 합 니 다. 이것 은 nginx 의 비장의 무기 이기 때 문 입 니 다.
처음 접 촉 했 을 때 우 리 는 감청, 요청, 수용, 응답 이라는 개념 만 알 고 있 었 다.우 리 는 이 사 고 를 따라 전개 하여 nginx 가 어떻게 이런 구조 체 를 설계 하 는 지 보 았 다.
1. 대체적으로 디자인
감청 이 든 요청 이 든 fd 가 생 길 수 있 는 것 은 연결 로 간주 되 며, fd 는 연결 (connection) 에 대응 합 니 다.
모든 연결 은 읽 기 (read) 와 쓰기 (write) 를 할 수 있 습 니 다. 이 두 가 지 는 이벤트 (event) 로 간주 되 고 구조 체 는 다음 과 같 습 니 다.
struct ngx_connection_s {
void *data; // ,listening, request, ...
ngx_event_t *read; //
ngx_event_t *write; //
ngx_socket_t fd; //
ngx_listening_t *listening; //
};
struct ngx_event_s {
void *data; // ,connection, ...
unsigned write:1; //
unsigned accept:1; // accept
unsigned instance:1; //
unsigned active:1; // , epoll_ctl 1
unsigned ready:1; // epoll_wait 1
unsigned timedout:1; //
unsigned timer_set:1; // , 1
ngx_event_handler_pt handler; // ,
ngx_rbtree_node_t timer; //
};
2. 감청 listen
설정 파일 분석 (listen 명령 에 대한) 을 처리 할 때 nginx 는 이 listen 을 처리 하기 시작 합 니 다.그것들 을 ngx 에 놓 아 라cycle - > listening 에서.
struct ngx_cycle_s {
...
ngx_array_t listening; // , ngx_listening_s
...
}
struct ngx_listening_s {
ngx_socket_t fd; //
struct sockaddr *sockaddr;
socklen_t socklen;
...
};
감청 은 읽 기 이벤트 가 있 고 사건 을 쓰 지 않 았 습 니 다. epoll 은 두 가지 모드 LT 와 ET 가 있 습 니 다. 감청 은 LT 를 사용 하고 감청 한 read 사건 의 처리 함 수 는 ngx 입 니 다.event_accept。 3. 수락
이 생 성 된 fd 는 읽 기와 쓰기 이벤트 가 있 고 읽 기 이벤트 에 대한 처리 함 수 는 ngx 입 니 다.http_init_request。따라서 연결 요청 이 완료 되면 이 함수 부터 실행 합 니 다.
이것 도 request 가 시작 하 는 생명 주기 입 니 다. 여기 의 구조 체 는:
struct ngx_http_request_s {
uint32_t signature; /* "HTTP" */
ngx_connection_t *connection; //
/* , , */
void **ctx;
void **main_conf;
void **srv_conf;
void **loc_conf;
/* */
u_char *uri_start;
u_char *uri_end;
u_char *uri_ext;
u_char *args_start;
u_char *request_start;
u_char *request_end;
u_char *method_end;
u_char *schema_start;
u_char *schema_end;
u_char *host_start;
u_char *host_end;
u_char *port_start;
u_char *port_end;
unsigned http_minor:16;
unsigned http_major:16;
};
4. 신기 한 시간 초과
시간 초과 처 리 를 했 기 때문에 전체 코드 의 복잡 도 는 적어도 한 단계 향상 되 었 습 니 다. libevent 와 같은 동쪽 은 신호 로 시간 을 초과 한 것 입 니 다.
nginx 작 가 는 이런 처리 방식 이 라인 이 안전 하지 않다 고 생각해 야 하기 때문에 스스로 하 나 를 실현 했다.이것 은 반복 적 으로 바퀴 를 만 드 는 것 이 아니 라 시간 초과 메커니즘 이다.
응용 프로그램의 일부 논리 로 응용 프로그램 코드 에서 크게 나 무 랄 데 가 없다.
시간 초과 기 제 는 빨 간 검 은 나 무 를 사 용 했 습 니 다. 잦 은 삽입, 검색 과 삭제 가 있 기 때문에 빨 간 검 은 나 무 를 사용 하 는 효율 이 매우 높 습 니 다.
초기 화: 전문 변수 ngxevent_timer_rbtree
ngx_event_timer_init(cycle->log);
시간 초과 검사: epoll 모든 이벤트 처리 전에 시간 초과 가 무엇 인지 확인 하고 이 벤트 를 timedout 으로 표시 하 며 이벤트 처 리 를 즉시 실행 합 니 다.
ngx_event_expire_timers(void)
{
...
for ( ;; ) {
node = ngx_rbtree_min(root, sentinel);
/* node->key <= ngx_current_time, , */
if ((ngx_msec_int_t) (node->key - ngx_current_msec) <= 0) {
ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));
ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer);
ev->timer_set = 0; // timer_set
ev->timedout = 1; //
ev->handler(ev); // , , handler
//
continue;
}
break; // ,
}
}
5. epoll 의 응용
연결 (또는 이벤트) 을 epoll 에 추가 해 야 처리 할 수 있 습 니 다. 그렇지 않 으 면 읽 을 수 있 거나 쓸 수 있 더 라 도 무시 할 수 있 습 니 다.
for ( ;; ) {
timer = ngx_event_find_timer();
events = epoll_wait(ep, event_list, (int) nevents, timer);
;
;
;
}
이벤트 동작:
ngx_epoll_add_event
ngx_epoll_del_event
빗질
만약 우리 가 스스로 업무 논 리 를 쓴다 면, 어떻게 사건 을 처리 합 니까?
fd 가 이미 있다 고 가정 하면 socket 함 수 를 통 해 생 긴 것 일 수 있 습 니 다.
연결 가 져 오기:
c = ngx_get_connection(fd);
read, write 처리:
c->read->handler = ngx_http_init_request;
c->write->handler = ngx_http_empty_handler;
타이머 처리: 타 이 머 는 이벤트 에 대한 것 입 니 다.
ngx_add_timer(c->read, c->listening->post_accept_timeout);
ngx_add_timer(c->write, ...);
등록 이벤트: 즉 epoll 가입 입 니 다. 여 기 는 보통 ET 모드 를 사용 합 니 다.
ngx_handle_read_event(c->read, 0);
ngx_handle_read_event(c->write, 0);
위의 예 는 read, write 를 모두 처 리 했 습 니 다. 실제 상황 이 꼭 그래 야 하 는 것 은 아 닙 니 다. 읽 기 나 쓰기 이 벤트 를 처리 할 지, 필요 한 것, 사용 할 것 을 보 세 요.
7. 잊 을 수 없 는 timedout.
만약 당신 이 신경 을 쓴다 면, 모든 이벤트 의 handler 함수 체 앞 에 이런 코드 가 있다 는 것 을 알 게 될 것 입 니 다.
ngx_http_init_request(ngx_event_t *rev)
{
...
if (rev->timedout) {
ngx_http_close_connection(c);
return;
}
...
}
ngx_http_process_request_line(ngx_event_t *rev)
{
...
if (rev->timedout) {
c->timedout = 1;
ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
return;
}
...
}
그래서 앞에서 언급 한 바 와 같이 시간 초과 검사 시 nginx 는 이벤트 만 timedout 으로 표시 하고 연결 을 닫 지 않 았 습 니 다. 이것 은 nginx 가 처리 할 수 있 기 때 문 입 니 다.http, mail 또는 서로 다른 연결, 모든 연결 은 자신 만 의 처리 방식 이 있 기 때문에 이 코드 는 없 는 곳 이 없습니다.
8. 이 코드 를 이해 할 수 있 습 니까?
ngx_url_t u;
ngx_peer_connection_t peer;
ngx_memzero(&u, sizeof(ngx_url_t));
ngx_memzero(&peer, sizeof(ngx_peer_connection_t));
ngx_str_set(&u.url, "127.0.0.1:8080");
ngx_parse_url(pool, &u);
peer.sockaddr = u.addrs->sockaddr;
peer.socklen = u.addrs->socklen;
peer.name = u.addrs->name;
peer.get = ngx_event_get_peer;
ngx_event_connect_peer(&peer);
peer.connection->read->handler = ngx_mail_auth_http_read_handler;
peer.connection->write->handler = ngx_mail_auth_http_write_handler;
ngx_add_timer(peer.connection->read, ahcf->timeout);
ngx_add_timer(peer.connection->write, ahcf->timeout);
메 일 부분 auth 캡 처 입 니 다.http 의 코드, nginx 가 사용 하 는 광범 위 한 하 나 는 자신 이 socket 을 만들어 다른 서버 에 연결 하 는 것 입 니 다.
fastcgi, proxy 처럼 모두 이 렇 습 니 다. 그 안의 핵심 은 바로 ngx 입 니 다.event_connect_peer, 이 주 제 는 비교적 깊 습 니 다. 남 긴 후에 전문 적 으로 분석 하고 벽돌 을 먼저 던 집 니 다.
ps: 이 글 을 쓸 때 일부 코드 는 경험 에 의 해 두 드 렸 습 니 다. 잘못된 점 이 있 으 면 지적 해 주 십시오.디자인 의 차원 에 대해 이야기 할 수 있다 면 충분 하 다.
원문 읽 기:http://nglua.com/reads/4.html
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
nginx 소스 코드 분석 - reuseport 의 사용reuseport 의 감청 소켓 을 설정 하면 모든 worker 프로 세 스 는 하나의 독립 된 fd 를 가지 고 있 으 며, worker 프로 세 스 간 에 서로 간섭 하지 않 고 커 널 차원 에서 부하 균형 을 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.