Nginx source Code Analysis-Main process-multi-process implementation

Source: Internet
Author: User
Tags thread

By default, Nginx is a multi-process run mode. Nginx and memcached are not the same, is a multi-process mode. Maximum benefits of using multi-process mode:

1. Resource independence for each process

2. No need to add a variety of cumbersome locks


Flowchart of Nginx Multi-process implementation


Nginx Multi-process specific implementation 1. ngx_master_process_cycle into multi-process mode

The Ngx_master_process_cycle method mainly does two things:

1. The main process for signal monitoring and processing

2. Turn on sub-processes

/** * Nginx Multi-process operation mode */void Ngx_master_process_cycle (ngx_cycle_t *cycle) {char *title;
	U_char *p;
	size_t size;
	ngx_int_t i;
	ngx_uint_t N, Sigio;
	sigset_t set;
	struct Itimerval ITV;
	ngx_uint_t live;
	ngx_msec_t delay;
	ngx_listening_t *ls;

	ngx_core_conf_t *CCF;
	/* Set the signal to be received */Sigemptyset (&set);
	Sigaddset (&set, SIGCHLD);
	Sigaddset (&set, SIGALRM);
	Sigaddset (&set, SIGIO);
	Sigaddset (&set, SIGINT);
	Sigaddset (&set, Ngx_signal_value (ngx_reconfigure_signal));
	Sigaddset (&set, Ngx_signal_value (ngx_reopen_signal));
	Sigaddset (&set, Ngx_signal_value (ngx_noaccept_signal));
	Sigaddset (&set, Ngx_signal_value (ngx_terminate_signal));
	Sigaddset (&set, Ngx_signal_value (ngx_shutdown_signal));

	Sigaddset (&set, Ngx_signal_value (ngx_changebin_signal)); if (Sigprocmask (Sig_block, &set, NULL) = =-1) {Ngx_log_error (Ngx_log_alert, Cycle->log, Ngx_errno, "sigprocm
	Ask () failed ");

	} sigemptyset (&set); size = sizeof (Master_procESS);
	for (i = 0; i < NGX_ARGC; i++) {size + Ngx_strlen (Ngx_argv[i]) + 1;
	}/* Save the process title */title = Ngx_pnalloc (cycle->pool, size);
	if (title = = NULL) {/* fatal */exit (2);
	} p = Ngx_cpymem (title, master_process, sizeof (master_process)-1);
		for (i = 0; i < NGX_ARGC; i++) {*p++ = ";
	p = ngx_cpystrn (p, (U_char *) ngx_argv[i], size);

	} ngx_setproctitle (title);

	/* Get Core configuration ngx_core_conf_t */CCF = (ngx_core_conf_t *) ngx_get_conf (cycle->conf_ctx, ngx_core_module);
	/* Start worker process-core function of multi-process start */ngx_start_worker_processes (cycle, ccf->worker_processes, ngx_process_respawn);

	Ngx_start_cache_manager_processes (cycle, 0);
	ngx_new_binary = 0;
	Delay = 0;
	Sigio = 0;

	Live = 1; /* Main thread loop */for (;;) 
				{/* delay is used to set the time to wait for the worker to eject, after master accepts the exit signal, * First sends the exit signal to the worker, and the worker exits takes some time */if (delay) {if (NGX_SIGALRM) {
				Sigio = 0;
				Delay *= 2;
			NGX_SIGALRM = 0; } ngx_log_debug1 (Ngx_log_debug_event, Cycle->log, 0, "TerminatiOn cycle:%M ", delay);
			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, &AMP;ITV, NULL) = =-1) {Ngx_log_error (Ngx_log_alert, Cycle->log, Ngx_errno, "Seti
			Timer () failed ");

		}} ngx_log_debug0 (Ngx_log_debug_event, Cycle->log, 0, "sigsuspend");

		/* Wait for the signal to arrive, blocking function */sigsuspend (&set);

		Ngx_time_update ();

		NGX_LOG_DEBUG1 (ngx_log_debug_event, Cycle->log, 0, "Wake Up, Sigio%i", Sigio);
			/* received the SIGCHLD signal, a worker exited (ngx_reap = = 1) */if (ngx_reap) {ngx_reap = 0;

			Ngx_log_debug0 (ngx_log_debug_event, Cycle->log, 0, "reap children");
		Live = Ngx_reap_children (cycle);
		} if (!live && (ngx_terminate | | ngx_quit)) {ngx_master_process_exit (cycle);
			}/* Abort process */if (ngx_terminate) {if (delay = = 0) {delay = 50;
				} if (Sigio) {sigio--;
			Continue } Sigio = Ccf->wOrker_processes + 2 */cache processes */;
			if (Delay >) {ngx_signal_worker_processes (cycle, SIGKILL);
			} else {ngx_signal_worker_processes (cycle, Ngx_signal_value (ngx_terminate_signal));
		} continue;

			}/* Exit process */if (ngx_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_lo
				G_emerg, Cycle->log, Ngx_socket_errno, Ngx_close_socket_n "%V failed", &ls[n].addr_text);

			}} cycle->listening.nelts = 0;
		Continue

			}/* Receive SIGHUP signal reinitialization configuration */if (ngx_reconfigure) {ngx_reconfigure = 0;
				if (ngx_new_binary) {ngx_start_worker_processes (cycle, ccf->worker_processes, ngx_process_respawn);
				Ngx_start_cache_manager_processes (cycle, 0);

				ngx_noaccepting = 0;
			Continue } ngx_log_error (Ngx_log_noTICE, Cycle->log, 0, "reconfiguring");
			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_processes (cycle, 1);

			/* Allow new processes to start */ngx_msleep (100);
			Live = 1;
		Ngx_signal_worker_processes (cycle, Ngx_signal_value (ngx_shutdown_signal));
			}/* When Ngx_noaccepting==1, Ngx_restart is set to 1, restart worker */if (ngx_restart) {ngx_restart = 0;
			Ngx_start_worker_processes (cycle, ccf->worker_processes, ngx_process_respawn);
			Ngx_start_cache_manager_processes (cycle, 0);
		Live = 1;
			}/* Receive SIGUSR1 signal, reopen log file */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));
			}/* SIGUSER2, Hot code Replacement */if (ngx_change_binary) {ngx_change_binary = 0;
			Ngx_log_error (Ngx_log_notice, Cycle->log, 0, "changing binary");
		Ngx_new_binary = Ngx_exec_new_binary (cycle, NGX_ARGV);
			*/* received Sigwinch signal not accepting request, worker exits, Master does not exit */if (ngx_noaccept) {ngx_noaccept = 0;
			ngx_noaccepting = 1;
		Ngx_signal_worker_processes (cycle, Ngx_signal_value (ngx_shutdown_signal)); }
	}
}
2. Ngx_start_worker_processes Create a worker process

Creates n sub-processes by looping. Each child process has a separate memory space.

The number of child processes is determined by Nginx configuration: ccf->worker_processes

/**
 * Create worker process
 *
/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;

	/* Loop Create worker process  default ccf->worker_processes=8 process, depending on number of CPUs   */For
	(i = 0; i < n; i++) {/

		* Open worker process  (Ngx_worker_process_cycle callback function, mainly used to process each worker thread) *
		/Ngx_spawn_process (cycle, ngx_worker_process_cycle,
				(void *) (intptr_t) I, "worker process", type);

		Ch.pid = Ngx_processes[ngx_process_slot].pid;
		Ch.slot = Ngx_process_slot;
		CH.FD = ngx_processes[ngx_process_slot].channel[0];

		Ngx_pass_open_channel (cycle, &ch);
	}
}

3. ngx_spawn_process Fork Work Process

The Ngx_spawn_process method is mainly used to fork out each work process. The main view is the code of the fork process.

    /* Fork a sub-process *
    /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:/
    	* If the PID fork succeeds, call the Ngx_worker_process_cycle method *
        /Ngx_pid = Ngx_getpid ();
        Proc (cycle, data);
        break;

    Default: Break
        ;
    }

4. Callback function for ngx_worker_process_cycle child process

Ngx_worker_process_cycle is the callback function for the child process, and the work of all child processes begins with this method.

Nginx's process is ultimately event-driven, and all of this will eventually invoke the ngx_process_events_and_timers event-driven core function.

/** * Child Process callback function * The logical processing of each process starts with this method */static void Ngx_worker_process_cycle (ngx_cycle_t *cycle, void *data) {ngx_int_t

	Worker = (intptr_t) data;
	ngx_process = Ngx_process_worker;

	Ngx_worker = worker;

	/* Worker Process Initialization */ngx_worker_process_init (cycle, worker);

	Ngx_setproctitle ("worker process"); /* Process loop */for (;;)

			{/* Determines if the status is exited, and if exiting, the socket handle must be emptied */if (ngx_exiting) {ngx_event_cancel_timers (); 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");

		/* Event-driven core function */ngx_process_events_and_timers (cycle);

			if (ngx_terminate) {ngx_log_error (ngx_log_notice, Cycle->log, 0, "exiting");
		Ngx_worker_process_exit (cycle);
			}/* If it is exited */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) {ngx_exiting = 1;
				Ngx_close_listening_sockets (cycle);
			Ngx_close_idle_connections (cycle);
			}}//If it is restart */if (ngx_reopen) {ngx_reopen = 0;
			Ngx_log_error (Ngx_log_notice, Cycle->log, 0, "reopening logs");
		Ngx_reopen_files (cycle,-1); }
	}
}
5. Ngx_worker_process_init initialization of work processes

/** * Worker Process initialization */static void Ngx_worker_process_init (ngx_cycle_t *cycle, ngx_int_t worker) {sigset_t set;
	ngx_int_t N;
	ngx_uint_t i;
	ngx_cpuset_t *cpu_affinity;
	struct Rlimit rlmt;
	ngx_core_conf_t *CCF;

	ngx_listening_t *ls;
	/* Configure environment variable */if (Ngx_set_environment (cycle, NULL) = = NULL) {/* fatal */exit (2);

	}/* Get core configuration */CCF = (ngx_core_conf_t *) ngx_get_conf (cycle->conf_ctx, ngx_core_module); if (worker >= 0 && ccf->priority! = 0) {if (setpriority (prio_process, 0, ccf->priority) = =-1) {ng
		X_log_error (Ngx_log_alert, Cycle->log, Ngx_errno, "setpriority (%d) failed", ccf->priority);
		}} if (Ccf->rlimit_nofile! = ngx_conf_unset) {rlmt.rlim_cur = (rlim_t) ccf->rlimit_nofile;

		Rlmt.rlim_max = (rlim_t) ccf->rlimit_nofile; if (Setrlimit (rlimit_nofile, &AMP;RLMT) = =-1) {Ngx_log_error (Ngx_log_alert, Cycle->log, Ngx_errno, "Setrlimit
		(Rlimit_nofile,%i) failed ", Ccf->rlimit_nofile); }} if (Ccf-> Rlimit_core! = ngx_conf_unset) {rlmt.rlim_cur = (rlim_t) ccf->rlimit_core;

		Rlmt.rlim_max = (rlim_t) ccf->rlimit_core; if (Setrlimit (Rlimit_core, &AMP;RLMT) = =-1) {Ngx_log_error (Ngx_log_alert, Cycle->log, Ngx_errno, "Setrlimit (R
		Limit_core,%O) failed ", Ccf->rlimit_core); }}//Set UID Groupuid */if (geteuid () = = 0) {if (Setgid (ccf->group) = =-1) {Ngx_log_error (Ngx_log_emerg, CY
			Cle->log, Ngx_errno, "Setgid (%d) failed", Ccf->group);
		/* Fatal */exit (2);
					} if (Initgroups (ccf->username, ccf->group) = =-1) {Ngx_log_error (Ngx_log_emerg, Cycle->log, Ngx_errno,
		"Initgroups (%s,%d) failed", Ccf->username, Ccf->group);  } if (setuid (ccf->user) = =-1) {Ngx_log_error (Ngx_log_emerg, Cycle->log, Ngx_errno, "setuid (%d) failed",
			Ccf->user);
		/* Fatal */exit (2);

		}}/* Set CPU affinity */if (worker >= 0) {cpu_affinity = ngx_get_cpu_affinity (worker); if (cpu_affinity) {ngx_Setaffinity (cpu_affinity, Cycle->log); }} #if (ngx_have_pr_set_dumpable)/* Allow coredump after setuid () in Linux 2.4.x */if (Prctl (pr_set_dumpable, 1,
	0, 0, 0) = =-1) {Ngx_log_error (Ngx_log_alert, Cycle->log, Ngx_errno, "Prctl (pr_set_dumpable) failed");  } #endif/* Switch working directory */if (Ccf->working_directory.len) {if (ChDir (char *) ccf->working_directory.data) = =-1) 
			{Ngx_log_error (Ngx_log_alert, Cycle->log, Ngx_errno, "chdir (\"%s\ ") failed", Ccf->working_directory.data);
		/* Fatal */exit (2);

	}} sigemptyset (&set); /* Clear All signals */if (Sigprocmask (Sig_setmask, &set, NULL) = =-1) {Ngx_log_error (Ngx_log_alert, Cycle->log, Ngx_errn
	O, "Sigprocmask () failed");

	} srandom ((ngx_pid <<) ^ ngx_time ()); /* * Disable deleting previous events for the listening sockets because * in the worker processes there is no events
	At all at the this point */* clears SOKCET's listener */ls = cycle->listening.elts; for (i = 0; I < cycle->listening.nelts;
	i++) {ls[i].previous = NULL; }/* Initializes the module */for (i = 0; cycle->modules[i]; i++) {if (cycle->modules[i]->init_process) {if (CYCLE-&G
			T;modules[i]->init_process (cycle) = = Ngx_error) {/* fatal */exit (2); }}}/** * channel[1 of other processes] off, own channel[0] off */for (n = 0; n < ngx_last_process; n++) {if (Ngx_processe
		S[n].pid = =-1) {continue;
		} if (n = = Ngx_process_slot) {continue;
		} if (ngx_processes[n].channel[1] = =-1) {continue; } if (Close (ngx_processes[n].channel[1]) = =-1) {Ngx_log_error (Ngx_log_alert, Cycle->log, Ngx_errno, "close
		() channel failed "); }} if (Close (ngx_processes[ngx_process_slot].channel[0]) = =-1) {Ngx_log_error (Ngx_log_alert, Cycle->log, Ngx_er
	Rno, "Close () channel failed");
} #if 0 ngx_last_process = 0; #endif/** * Register A read event handler function for Ngx_channel */if (Ngx_add_channel_event (cycle, Ngx_channel, Ngx_read_event, Ngx_channEl_handler) = = Ngx_error) {/* fatal */exit (2); }
}

In the next section, we will explain the Nginx cluster and the load balancing process between processes.



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.