nginx 의 worker 시작 분석
#file:ngx_process_cycle.c
static void
ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type)
{
ngx_int_t i;
ngx_channel_t ch;
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes");
ngx_memzero(&ch, sizeof(ngx_channel_t));
ch.command = NGX_CMD_OPEN_CHANNEL;
//n
for (i = 0; i < n; i++) {
ngx_spawn_process(cycle, ngx_worker_process_cycle, (void *) (intptr_t) i, "worker process", type);
ch.pid = ngx_processes[ngx_process_slot].pid;// id
ch.slot = ngx_process_slot; // ngx_spawn_process
ch.fd = ngx_processes[ngx_process_slot].channel[0];
ngx_pass_open_channel(cycle, &ch);
}
}
master 와 worker 프로 세 스 간 의 통신 을 토론 할 때 중요 한 데이터 구조 ngxchannel_t. 채널 이 라 고도 부 릅 니 다. 로 컬 소켓 으로 이 루어 집 니 다.아래 socketpair 방법 을 이용 하면 부자 프로 세 스 간 에 사용 할 소켓 을 만 들 수 있 습 니 다.
int socketpair(int d, int type, int protocol, int sv[2]);
socketpair 가 실 행 될 때 sv [2] 이 두 소켓 은 다음 과 같은 관계 가 있 습 니 다. sv [0 소켓 에 데 이 터 를 쓰 면 sv [1] 소켓 에서 데 이 터 를 읽 을 수 있 습 니 다. 마찬가지 로 sv [1] 소켓 에 데 이 터 를 쓸 수도 있 고 sv [0] 에서 데 이 터 를 쓸 수도 있 습 니 다.기 록 된 데 이 터 를 읽 을 수 있 습 니 다. 부모 프로 세 스 간 에 적용 할 때, 부모 프로 세 스에 서 socketpair 를 호출 하여 이 소켓 을 만 들 고, 이 어 fork 를 호출 하여 하위 프로 세 스 를 만 듭 니 다. 그리고 부모 프로 세 스에 서 sv [1] 소켓 을 닫 고, 하위 프로 세 스에 서 sv [0] 소켓 을 닫 습 니 다. 부모 프로 세 스 는 sv [0] 와 하위 프로 세 스 의 sv [1] 를 사용 할 수 있 습 니 다.양 방향 통신 을 자 유 롭 게 진행 합 니 다. for loop 에 서 는 ngx spawn process 를 호출 합 니 다. 이 함 수 는 주로 socketpair 를 호출 하여 스 트림 소켓 그룹 을 만 든 다음 fork 를 호출 하여 하위 프로 세 스 를 만 들 고 하위 프로 세 스 에서 프로 세 스 함수 ngx worker process cycle 을 실행 합 니 다. 새로운 worker 를 만 들 때마다 다른 worker 에 새 worker 정 보 를 동기 화 해 야 합 니 다. 이것 은 ngx pass open channel 입 니 다.완성, 두 번 째 매개 변 수 는 ngx channel t 를 가리 키 는 지침 입 니 다. ngx channel t 구 조 는 다음 과 같 습 니 다.
typedef struct {
ngx uint t command; / 전 달 된 TCP 메시지 의 명령
ngx pid t pid; / 프로 세 스 id
ngx int t; / ngx processes 프로 세 스 배열 의 번호
ngx fd t fd; / 통신 의 소켓 핸들
}ngx_channel_t;
이 간단 한 구 조 는 master 프로 세 스 와 worker 프로 세 스 간 의 상 태 를 동기 화 하 는 데 사 용 됩 니 다. 새로운 프로 세 스 를 만 들 때마다 채널 의 pid 구성원 은 새 프로 세 스 의 id 로 할당 합 니 다. slot 는 새 프로 세 스 가 ngx processes 프로 세 스 배열 의 번호 로 할당 합 니 다. fd 는 socketpair 가 만 든 프로 세 스 그룹 중의 sv [0] 입 니 다.이 프로 세 스 배열 의 정 보 는 ngx process t 구조 체 의 channel 구성원 에 저 장 됩 니 다. ngx process t 는 프로 세 스 를 설명 하 는 구조 입 니 다.
static void
ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch)
{
ngx_int_t i;
for (i = 0; i < ngx_last_process; i++) {
if (i == ngx_process_slot
|| ngx_processes[i].pid == -1
|| ngx_processes[i].channel[0] == -1)
{
continue;
}
ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0,
"pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d",
ch->slot, ch->pid, ch->fd,
i, ngx_processes[i].pid,
ngx_processes[i].channel[0]);
ngx_write_channel(ngx_processes[i].channel[0],
ch, sizeof(ngx_channel_t), cycle->log);
}
}
ngx pass open channel 함수 에서 for 순환 은 매번 새로 만 들 지 않 은 유효한 worker 프로 세 스 의 색인 을 가 져 오고 ngx write channel 함 수 를 통 해 이 worker 에 게 새 프로 세 스 정 보 를 전달 합 니 다. 그 중에서 ngx write channel 의 첫 번 째 매개 변 수 는 이 worker 와 통신 하 는 스 트림 소켓 배열 의 channel [0] 입 니 다. worker 프로 세 스 는 channel 1] 에서 전 달 된 정 보 를 받 습 니 다.워 커 프로 세 스 가 채널 [1] 에 메시지 가 도착 했다 는 것 을 어떻게 알 았 는 지 의문 입 니 다. 워 커 프로 세 스 함수 에서 채널 [1] 의 읽 기 이 벤트 를 이벤트 구동 에 추가 하고 읽 기 이벤트 리 셋 함 수 를 ngx 로 연결 하기 때 문 입 니 다.channel_handler。
static void
ngx_channel_handler(ngx_event_t *ev)
{
ngx_int_t n;
ngx_channel_t ch;
ngx_connection_t *c;
if (ev->timedout) {
ev->timedout = 0;
return;
}
c = ev->data;
ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel handler");
for ( ;; ) {
n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log); // fd
ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n);
if (n == NGX_ERROR) {
if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
ngx_del_conn(c, 0);
}
ngx_close_connection(c);
return;
}
if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) {
if (ngx_add_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) {
return;
}
}
if (n == NGX_AGAIN) {
return; //
}
ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0,
"channel command: %d", ch.command);
switch (ch.command) {
case NGX_CMD_QUIT:
ngx_quit = 1;
break;
case NGX_CMD_TERMINATE:
ngx_terminate = 1;
break;
case NGX_CMD_REOPEN:
ngx_reopen = 1;
break;
case NGX_CMD_OPEN_CHANNEL:
ngx_log_debug3(NGX_LOG_DEBUG_CORE, ev->log, 0,
"get channel s:%i pid:%P fd:%d",
ch.slot, ch.pid, ch.fd);
ngx_processes[ch.slot].pid = ch.pid;
ngx_processes[ch.slot].channel[0] = ch.fd;
break;
case NGX_CMD_CLOSE_CHANNEL:
ngx_log_debug4(NGX_LOG_DEBUG_CORE, ev->log, 0,
"close channel s:%i pid:%P our:%P fd:%d",
ch.slot, ch.pid, ngx_processes[ch.slot].pid,
ngx_processes[ch.slot].channel[0]);
if (close(ngx_processes[ch.slot].channel[0]) == -1) {
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
"close() channel failed");
}
ngx_processes[ch.slot].channel[0] = -1;
break;
}
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
centos7에서 Firewalld를 통해 게이트웨이 서버 설정사용 장면: 여러 대의 내망 서버가 있는데 그 중 한 대만 외망에 접근할 수 있지만 다른 내망 서버도 외망에 접근하기를 희망한다 가령 내부 네트워크 세그먼트가 192.168.1.0/24 외부 네트워크에 접근할 수 있...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.