nginx 프로 세 스 모델
nginx 에서 master 와 worker 의 통신 은 socketpair 를 통 해 이 루어 집 니 다. 매번 fork 가 하위 프로 세 스 를 마 친 후에 이 하위 프로 세 스 의 socketpaire 핸들 을 앞 에 존재 하 는 하위 프로 세 스 에 전달 하면 프로 세 스 간 에 도 통신 할 수 있 습 니 다.
nginx 에서 fork 하위 프로 세 스 는 ngxspawn_process 에서 진 행 된:
첫 번 째 매개 변 수 는 전역 설정 이 고 두 번 째 매개 변 수 는 하위 프로 세 스 가 실행 해 야 할 함수 이 며 세 번 째 매개 변 수 는 proc 의 매개 변수 입 니 다.네 번 째 유형.
ngx_pid_t
ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
char *name, ngx_int_t respawn)
이 함수 의 주요 임 무 는:
1 개 ngxprocesses 전역 배열 은 모든 재고 의 하위 프로 세 스 를 포함 하고 있 습 니 다. fork 에서 나 온 하위 프로 세 스 를 해당 위치 에 넣 습 니 다.이 프로 세 스 의 관련 속성 을 설정 합 니 다.
2 socketpair 를 만 들 고 관련 속성 을 설정 합 니 다.
3. 하위 프로 세 스에 서 전 달 된 함 수 를 실행 합 니 다.
상세 한 코드 를 보기 전에 우 리 는 먼저 몇 가지 주요 데이터 구 조 를 살 펴 보 자.
우선 프로 세 스 구조 입 니 다. 이 구조 체 는 프로 세 스 를 표시 합 니 다.id 상태, channel 등 이 포함 되 어 있 습 니 다.
typedef struct {
/// id
ngx_pid_t pid;
/// ( waitpid ).
int status;
/// channel( socketpair )
ngx_socket_t channel[2];
/// ( spawn, ).
ngx_spawn_proc_pt proc;
void *data;
char *name;
/// 。
unsigned respawn:1;
unsigned just_respawn:1;
unsigned detached:1;
unsigned exiting:1;
unsigned exited:1;
} ngx_process_t;
다음은 상세 한 코드 를 살 펴 보 겠 습 니 다.
첫 번 째 부분 부터 보 겠 습 니 다.
// , 。
ngx_process_t ngx_processes[NGX_MAX_PROCESSES];
...................................
u_long on;
ngx_pid_t pid;
/// fork ngx_processes ,
ngx_int_t s;
/// , 0, , slot。
if (respawn >= 0) {
s = respawn;
} else {
/// ngx_processess, slot, fork , slot。
for (s = 0; s < ngx_last_process; s++) {
if (ngx_processes[s].pid == -1) {
break;
}
}
/// 。
if (s == NGX_MAX_PROCESSES) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
"no more than %d processes can be spawned",
NGX_MAX_PROCESSES);
return NGX_INVALID_PID;
}
}
다음은 socketpair 핸들 을 새로 만 들 고 관련 속성 을 초기 화 합 니 다.
/// NGX_PROCESS_DETACHED, ( ), socketpair。
if (respawn != NGX_PROCESS_DETACHED) {
/* Solaris 9 still has no AF_LOCAL */
/// socketpair
if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"socketpair() failed while spawning \"%s\"", name);
return NGX_INVALID_PID;
}
。。。。。。。。。。。。。。。。。。。。。。。。。。。。
///
if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) {
........................................................
}
if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) {
........................................
}
///
on = 1;
if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) {
.................................................
}
/// io
if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) {
..............................................
}
/// exec 。
if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) {................................................
}
if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) {
。。。。。。。。。。。。。。。。。。。。。。。。。。
}
///
ngx_channel = ngx_processes[s].channel[1];
} else {
ngx_processes[s].channel[0] = -1;
ngx_processes[s].channel[1] = -1;
}
다음은 fork 하위 프로 세 스 이 며 프로 세 스 관련 인 자 를 설정 합 니 다.
/// slot。
ngx_process_slot = s;
pid = fork();
switch (pid) {
case -1:
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"fork() failed while spawning \"%s\"", name);
ngx_close_channel(ngx_processes[s].channel, cycle->log);
return NGX_INVALID_PID;
case 0
/// ,
ngx_pid = ngx_getpid();
proc(cycle, data);
break;
default:
break;
}
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid);
ngx_processes[s].pid = pid;
ngx_processes[s].exited = 0;
/// 0, , 。
if (respawn >= 0) {
return pid;
}
/// 。
ngx_processes[s].proc = proc;
ngx_processes[s].data = data;
ngx_processes[s].name = name;
ngx_processes[s].exiting = 0;
/// 。
switch (respawn) {
case NGX_PROCESS_RESPAWN:
ngx_processes[s].respawn = 1;
ngx_processes[s].just_respawn = 0;
ngx_processes[s].detached = 0;
break;
case NGX_PROCESS_JUST_RESPAWN:
ngx_processes[s].respawn = 1;
ngx_processes[s].just_respawn = 1;
ngx_processes[s].detached = 0;
break;
case NGX_PROCESS_DETACHED:
ngx_processes[s].respawn = 0;
ngx_processes[s].just_respawn = 0;
ngx_processes[s].detached = 1;
break;
}
if (s == ngx_last_process) {
ngx_last_process++;
}
return pid;
여기 서 문제 가 있 습 니 다. 바로 뒤에 있 는 포크 의 하위 프로 세 스 가 앞 에 있 는 포크 의 하위 프로 세 스 가 자신의 프로 세 스 와 관련 된 정 보 를 얻 을 수 있 도록 하 는 방법 입 니 다.nginx 에 서 는 새로운 하위 프로 세 스 fork 가 끝 날 때마다 부모 프로 세 스 가 이 하위 프로 세 스 id 와 스 트림 파이프 의 핸들 channel [0] 을 앞의 하위 프로 세 스 에 전달 합 니 다.이렇게 프로 세 스 간 에 도 통신 할 수 있다.
관련 데이터 구조 먼저 보기:
/// 。
typedef struct {
/// 。
ngx_uint_t command;
/// id
ngx_pid_t pid;
///
ngx_int_t slot;
/// fd
ngx_fd_t fd;
} ngx_channel_t;
다음은 코드:
static void
ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type)
{
ngx_int_t i, s;
ngx_channel_t ch;
....................................
///
ch.command = NGX_CMD_OPEN_CHANNEL;
/// n, , 。
for (i = 0; i < n; i++) {
cpu_affinity = ngx_get_cpu_affinity(i);
/// 。 fork 。
ngx_spawn_process(cycle, ngx_worker_process_cycle, NULL,
"worker process", type);
/// channel,ngx_process_slot spawn , 。
ch.pid = ngx_processes[ngx_process_slot].pid;
ch.slot = ngx_process_slot;
ch.fd = ngx_processes[ngx_process_slot].channel[0];
///
for (s = 0; s < ngx_last_process; s++) {
/// 。
if (s == ngx_process_slot
|| ngx_processes[s].pid == -1
|| ngx_processes[s].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,
s, ngx_processes[s].pid,
ngx_processes[s].channel[0]);
/* TODO: NGX_AGAIN */
/// channel ( )。
ngx_write_channel(ngx_processes[s].channel[0],
&ch, sizeof(ngx_channel_t), cycle->log);
}
}
}
하위 프로 세 스에 서 어떻게 처리 되 었 습 니까? 하위 프로 세 스 의 파이프 읽 기 이벤트 캡 처 함 수 는 ngx 입 니 다.channel_handler (ngx event t * ev) 는 이 함수 에서 mseeage 를 읽 고 해석 하 며 명령 에 따라 처리 합 니 다. 코드 세 션 을 보십시오.
/// ch channel。
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_processes 。
ngx_processes[ch.slot].pid = ch.pid;
ngx_processes[ch.slot].channel[0] = ch.fd;
break;
case NGX_CMD_CLOSE_CHANNEL:
.....................................................
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;
}
다음은 worker 와 master 가 어떻게 상호작용 을 하 는 지, 그리고 master 가 외부 와 어떻게 상호작용 을 하 는 지 상세 하 게 살 펴 보 겠 습 니 다 (예 를 들 어 열 코드 교체, reconfig 등 작업).
nginx 에서 worker 와 master 의 상호작용 은 앞에서 말 했 듯 이 스 트림 파이프 와 신 호 를 통 해 이 루어 진 것 이 고 master 와 외부의 상호작용 은 신 호 를 통 해 이 루어 진 것 입 니 다.
master 의 주 순환 을 보기 전에 우 리 는 먼저 신호 처리 와 함 수 를 봅 니 다. nginx 에서 부자 프로 세 스 의 신호 처리 함 수 는 같 습 니 다. 다만 하나의 변 수 는 master 와 worker 에서 할당 값 이 다 르 기 때문에 구분 합 니 다.
신호 처리 에서 해당 하 는 표지 변 수 를 설정 하여 주 순환 에서 이러한 변 수 를 판단 하여 해당 하 는 조작 을 한다.
/// 。
#define NGX_SHUTDOWN_SIGNAL QUIT
#define NGX_TERMINATE_SIGNAL TERM
#define NGX_NOACCEPT_SIGNAL WINCH
#define NGX_RECONFIGURE_SIGNAL HUP
#if (NGX_LINUXTHREADS)
#define NGX_REOPEN_SIGNAL INFO
#define NGX_CHANGEBIN_SIGNAL XCPU
#else
#define NGX_REOPEN_SIGNAL USR1
#define NGX_CHANGEBIN_SIGNAL USR2
#endif
void
ngx_signal_handler(int signo)
{
char *action;
ngx_int_t ignore;
ngx_err_t err;
ngx_signal_t *sig;
ignore = 0;
err = ngx_errno;
///
for (sig = signals; sig->signo != 0; sig++) {
if (sig->signo == signo) {
break;
}
}
ngx_time_update(0, 0);
action = "";
/// ngx_process master worker 。
switch (ngx_process) {
///master 。
case NGX_PROCESS_MASTER:
case NGX_PROCESS_SINGLE:
switch (signo) {
case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
/// quit , 。
ngx_quit = 1;
action = ", shutting down";
break;
case ngx_signal_value(NGX_TERMINATE_SIGNAL):
case SIGINT:
///sigint ,
ngx_terminate = 1;
action = ", exiting";
break;
case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
///winch , accept。
ngx_noaccept = 1;
action = ", stop accepting connections";
break;
case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
///sighup reconfig
ngx_reconfigure = 1;
action = ", reconfiguring";
break;
case ngx_signal_value(NGX_REOPEN_SIGNAL):
/// , reopen
ngx_reopen = 1;
action = ", reopening logs";
break;
/// .
case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
if (getppid() > 1 || ngx_new_binary > 0) {
/*
* Ignore the signal in the new binary if its parent is
* not the init process, i.e. the old binary's process
* is still running. Or ignore the signal in the old binary's
* process if the new binary's process is already running.
*/
/// , 。。
action = ", ignoring";
ignore = 1;
break;
}
/// , 。
ngx_change_binary = 1;
action = ", changing binary";
break;
case SIGALRM:
break;
case SIGIO:
ngx_sigio = 1;
break;
case SIGCHLD:
/// , 。
ngx_reap = 1;
break;
}
break;
///worker 。worker 。
case NGX_PROCESS_WORKER:
switch (signo) {
case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
ngx_debug_quit = 1;
case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
ngx_quit = 1;
action = ", shutting down";
break;
case ngx_signal_value(NGX_TERMINATE_SIGNAL):
case SIGINT:
ngx_terminate = 1;
action = ", exiting";
break;
case ngx_signal_value(NGX_REOPEN_SIGNAL):
ngx_reopen = 1;
action = ", reopening logs";
break;
...............................................
}
break;
}
................................................
/// sigchld, ( waitpid)。
if (signo == SIGCHLD) {
ngx_process_get_status();
}
ngx_set_errno(err);
}
먼저 master 의 주 순환 을 살 펴 보면 처리 가 간단 합 니 다. 바로 순환 과정 에서 해당 하 는 조건 을 판단 한 다음 에 해당 하 는 처리 에 들 어 가 는 것 입 니 다.이곳 의 관련 표지 위 치 는 기본적으로 위의 신호 처리 함수 에서 값 을 부여 합 니 다.:
for ( ;; ) {
///delay , SIGINT , , , , , sigkill ( ), 。
if (delay) {
delay *= 2;
..............................................
itv.it_interval.tv_sec = 0;
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = delay / 1000;
itv.it_value.tv_usec = (delay % 1000 ) * 1000;
/// 。
if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"setitimer() failed");
}
}
/// , 。
sigsuspend(&set);
ngx_time_update(0, 0);
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up");
///ngx_reap 1, 。
if (ngx_reap) {
ngx_reap = 0;
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children");
/// ( worker , worker ), 0.
live = ngx_reap_children(cycle);
}
/// , ngx_terminate ngx_quit , master 。
if (!live && (ngx_terminate || ngx_quit)) {
ngx_master_process_exit(cycle);
}
/// sigint 。
if (ngx_terminate) {
/// 。
if (delay == 0) {
delay = 50;
}
if (delay > 1000) {
/// , worker
ngx_signal_worker_processes(cycle, SIGKILL);
} else {
/// sigint worker, 。
ngx_signal_worker_processes(cycle,
ngx_signal_value(NGX_TERMINATE_SIGNAL));
}
continue;
}
/// quit 。
if (ngx_quit) {
/// worker quit
ngx_signal_worker_processes(cycle,
ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
ls = cycle->listening.elts;
for (n = 0; n < cycle->listening.nelts; n++) {
if (ngx_close_socket(ls[n].fd) == -1) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
ngx_close_socket_n " %V failed",
&ls[n].addr_text);
}
}
cycle->listening.nelts = 0;
continue;
}
/// reconfig
if (ngx_reconfigure) {
ngx_reconfigure = 0;
/// ( master)。 , config。
if (ngx_new_binary) {
ngx_start_worker_processes(cycle, ccf->worker_processes,
NGX_PROCESS_RESPAWN);
ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN);
ngx_noaccepting = 0;
continue;
}
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring");
/// config, worker
cycle = ngx_init_cycle(cycle);
if (cycle == NULL) {
cycle = (ngx_cycle_t *) ngx_cycle;
continue;
}
ngx_cycle = cycle;
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
ngx_core_module);
ngx_start_worker_processes(cycle, ccf->worker_processes,
NGX_PROCESS_JUST_RESPAWN);
ngx_start_cache_manager_process(cycle, NGX_PROCESS_JUST_RESPAWN);
live = 1;
ngx_signal_worker_processes(cycle,
ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
}
/// 。 , ngx_noacceptig , ( accept ?)
if (ngx_restart) {
ngx_restart = 0;
ngx_start_worker_processes(cycle, ccf->worker_processes,
NGX_PROCESS_RESPAWN);
ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN);
live = 1;
}
/// log
if (ngx_reopen) {
ngx_reopen = 0;
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
ngx_reopen_files(cycle, ccf->user);
ngx_signal_worker_processes(cycle,
ngx_signal_value(NGX_REOPEN_SIGNAL));
}
///
if (ngx_change_binary) {
ngx_change_binary = 0;
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary");
/// , execve 。
ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv);
}
/// accept , worker ( , master ).。
if (ngx_noaccept) {
ngx_noaccept = 0;
ngx_noaccepting = 1;
/// worker 。
ngx_signal_worker_processes(cycle,
ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
}
}
}
그리고 워 커 의 메 인 순환 을 살 펴 보면 워 커 의 것 은 비교적 간단 합 니 다.논리 와 master 의 유사 성:
for ( ;; ) {
///ngx_exiting master quit , 1, 。
if (ngx_exiting) {
c = cycle->connections;
.............................................
/// worker
if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel)
{
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
ngx_worker_process_exit(cycle);
}
}
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle");
ngx_process_events_and_timers(cycle);
/// shutdown worker
if (ngx_terminate) {
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
ngx_worker_process_exit(cycle);
}
/// quit
if (ngx_quit) {
ngx_quit = 0;
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,
"gracefully shutting down");
ngx_setproctitle("worker process is shutting down");
if (!ngx_exiting) {
/// socket, 。
ngx_close_listening_sockets(cycle);
ngx_exiting = 1;
}
}
/// master log 。
if (ngx_reopen) {
ngx_reopen = 0;
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
ngx_reopen_files(cycle, -1);
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
정수 반전Udemy 에서 공부 한 것을 중얼거린다 Chapter3【Integer Reversal】 (예) 문자열로 숫자를 반전 (toString, split, reverse, join) 인수의 수치 (n)가 0보다 위 또는 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.