nginx:进程模型(代码片段)

看,未来 看,未来     2023-01-09     459

关键词:

注:由于源码太长,于是我放另一篇里去了。
《Nginx(3):进程模型》篇 配套代码


进程模型图

main入口伪代码

我来用伪代码简化一下这个入口哈,看看nginx启动的时候都干了些什么。

int ngx_cdecl main(int argc, char *const *argv)

    //1、声明一波对象,打印一些基本信息,初始化一些东西

	//2、通过 ngx_save_argv(&init_cycle, argc, argv),将 argv 参数拷贝到一份内存中
    if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) 
        return 1;
    
    /*
			argv 参数是什么?就是管理者想nginx传入的信号,如 nginx -s reload之类的
			在后面还能找到信号捕捉函数,我已经把源码也铺开了,后面再看
		*/

  	//然后继续init

	//3、呐,信号捕捉,再说
    if (ngx_signal) 
        return ngx_signal_process(cycle, ngx_signal);
    

 		//继续配置

#if !(NGX_WIN32)

    if (ngx_init_signals(cycle->log) != NGX_OK) 
        return 1;
    

    if (!ngx_inherited && ccf->daemon) 
    	// 4、创建守护进程,源码也铺开了,后面再说
        if (ngx_daemon(cycle->log) != NGX_OK) 
            return 1;
        

        ngx_daemonized = 1;
    

    if (ngx_inherited) 
        ngx_daemonized = 1;
    

#endif
	
	//继续配置呗

	//5、启动进程循环咯
    if (ngx_process == NGX_PROCESS_SINGLE) 
        ngx_single_process_cycle(cycle);
     else 
    		//源码已铺开,同上。
    		//修改进程名,启动worker并管理
        ngx_master_process_cycle(cycle);
    

    return 0;

怎么样,现在局势就很明朗了吧。要想看的那么细比方说初始化了些啥,可以自己去那篇源码里看。


ngx_signal_process 信号捕捉

ngx_save_argv 没啥好看的哈,就一波空间配置并内容拷贝。

Nginx定义ngx_signal_t,用于描述接收到信号时的行为:

typedef struct 
    //信号值
    int     signo;
    //信号名称
    char   *signame;
    //nginx对应的名称,例如reload,reopen,stop等
    char   *name;
    //nginx自定义信号处理函数
    void  (*handler)(int signo, siginfo_t *siginfo, void *ucontext);
 ngx_signal_t;

1、在main函数中调用ngx_init_signals,初始化所有需要自定义处理的信号,代码功能很直接,就不放出来了,隔壁有。

2、在master守护进程将所有信号添加到信号集里面。(ngx_master_process_cycle(ngx_cycle_t *cycle))。

3、worker进程将所有信号添加到信号集里面。(ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker))。

4、master向worker发送信号(ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo))。


ngx_daemon 创建守护进程

这里面东西就多了哈。

这个函数学着点,怎么创建一个守护进程。

这段代码不做删减,只做注释,好东西我还是认得出来的

ngx_int_t ngx_daemon(ngx_log_t *log)	

    int  fd;

		//要成为守护进程,首先要成为孤儿,进孤儿院
		/*
    	 调用fork函数创建子进程后,使父进程立即退出。产生的子进程将被init进程接管,
    	 同时,所产生的新进程将变为在后台运行。
		*/
    switch (fork()) 
    case -1:
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fork() failed");
        return NGX_ERROR;

    case 0:
        break;

    default:
        exit(0);
    

    ngx_pid = ngx_getpid();


		/*
			    孤儿调用setsid()函数脱离控制终端和进程组,使该进程成为会话组长,并与原来的登录会话和进程组脱离。
    			此时孤儿进程已经成为无终端的会话组长,但它可以重新申请打开一个控制终端。
    			为了避免这种情况,可以通过使进程不再成为会话组长来禁止进程重新打开控制终端,
    			父进程(会话组长)退出,子进程继续执行,并不再拥有打开控制终端的能力。
    			在正在执行的进程中调用INIT_DAEMON后,进程将成为守护进程,脱离控制终端进入后台执行。
		*/
    if (setsid() == -1) 
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "setsid() failed");
        return NGX_ERROR;
    

		/*
			    很多情况下,守护进程会创建一些临时文件。出于安全性的考虑,往往不希望这些文件被别的用户查看。
    			这时,可以使用umask函数修改文件权限,创建掩码的取值,以满足守护进程的要求。
		*/
    umask(0);


		/*
    			新产生的进程从父进程继承了某些打开的文件描述符,如果不使用这些文件描述符,则需要关闭它们。
    			守护进程是运行在系统后台的,不应该在终端有任何的输出信息。
    			可以使用dup函数将标准输入、输出和错误输出重定向到/dev/null设备上
    			(/dev/null是一个空设备,向其写入数据不会有任何输出)。
		*/
    fd = open("/dev/null", O_RDWR);	//难怪在好多地方有看到这么个写法,当时就不知道是干嘛的
    if (fd == -1) 
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                      "open(\\"/dev/null\\") failed");
        return NGX_ERROR;
    

    if (dup2(fd, STDIN_FILENO) == -1) 
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDIN) failed");
        return NGX_ERROR;
    

    if (dup2(fd, STDOUT_FILENO) == -1) 
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDOUT) failed");
        return NGX_ERROR;
    

#if 0
    if (dup2(fd, STDERR_FILENO) == -1) 
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDERR) failed");
        return NGX_ERROR;
    
#endif

    if (fd > STDERR_FILENO) 
        if (close(fd) == -1) 
            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "close() failed");
            return NGX_ERROR;
        
    

		/*
			    改变当前工作目录(nginx没有做)
    			使用fork函数产生的子进程将继承父进程的当前工作目录。当进程没有结束时,其工作目录是不能被卸载的。
    			为了防止这种问题发生,守护进程一般会将其工作目录更改到根目录下(/目录)。
		*/
    return NGX_OK;



ngx_master_process_cycle 启动master循环

那个孤单进程循环就不说了,人都单身了看个代码还要single吗。。。

void ngx_master_process_cycle(ngx_cycle_t *cycle)

   	//声明一大堆对象

    //设置一堆的信号

		//然后统统屏蔽了,因为员工还没来上班

    //然后给进程起个名字

    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
		//启动worker进程(再说咯)
    ngx_start_worker_processes(cycle, ccf->worker_processes,NGX_PROCESS_RESPAWN);
		//启动文件cache管理进程
    ngx_start_cache_manager_processes(cycle, 0);

   	//初始化一些变量咯
   	ngx_new_binary = 0;
    delay = 0;
    sigio = 0;
    live = 1;
   	//开始循环处理信号咯
    for ( ;; ) 
    				//delay用来设置等待worker进程退出的时间,master接受退出信号后,
				//首先发送退出信号给worker,而worker退出需要一些时间
        if (delay) 
            if (ngx_sigalrm) 
                sigio = 0;
                delay *= 2;
                ngx_sigalrm = 0;
            

             //日志

           	//设置定时器,以系统真实时间来计算,送出SIGALRM信号
            
        

        //···

		//每次处理完一个信号,master进程会被挂起,直到有新的信号到来
        sigsuspend(&set);

  	  	//···

	/*
		子进程退出后,作为父进程的master进程会收到SIGCHLD信号
		发现信号是SIGCHLD后执行ngx_process_get_status函数判断worker子进程是正常退出,还是异常退出
		如果发现worker子进程如果是正常退出的,会将exited置为1
		master进程接收到信号,从挂起状态恢复,继续执行

以上这些,在signal_handle中
	*/
		/*
			发现ngx_reap=1后,ngx_reap_children函数判断是否需要重启worker进程
			如果worker是因为收到了quit信号正常退出的,所有worker进程退出时,live=0
			live=0 并且收到了ngx_quit信号  通过ngx_master_process_exit关闭master进程
		*/
        if (ngx_reap) 
            ngx_reap = 0;
            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children");

            live = ngx_reap_children(cycle);	//顺便说一下,它会查看所有子进程,因为它也不知道是谁走了
            //在这个函数的第65行,有重启函数
        

        if (!live && (ngx_terminate || ngx_quit)) 
            ngx_master_process_exit(cycle);
        


		//如果收到SIGTERM信号或SIGINT信号退出信号,设置推出延迟时间
		//···

		/*
			如果收到SIGQUIT信号
			给所有worker进程发送SIGQUIT信号
			关闭所有监听套接字socket
		*/
     
    	 //如果收到SIGHUP信号,平滑升级就按平滑升级处理,不然就重新配置

       	//and底下一堆的信号处理方案
    



流程图收尾

nginx:入门篇,技术点铺开(代码片段)

...载均衡动静分离深入一点nginx-sreload过程Nginxepoll模型Nginx进程模型master提供服务worker提供服务master-workers的机制的好处再深入一点Nginx进程模型主进程与工作进程交互工作进程之间交互Nginx模块内存池的设计哈哈,我终于对n 查看详情

《nginx:进程模型》篇配套代码(代码片段)

解耦合哈。不然那篇字数太多,有的人不想看代码就会觉得烦,官方也不会推代码占大头的文,所以我做了个大胆的创新,我把代码分出来,并设定为转载,这样就不会占用正文版面资源了。检索请通过目... 查看详情

nginx缓存机制和性能优化(代码片段)

...加载主动清除缓存Nginx程序运行原理分析Nginx工作模式多进程处理模型多进程处理模型优点Nginx为何要采用多进程模式?Worker进程遇到的问题解决Worker与CPU的绑定linux服务器参数调整 修改 查看详情

nginx配置文件详解(代码片段)

...置文件详解.php#定义Nginx运行的用户和用户组userwwwwww;#nginx进程数,建议设置为等于CPU总核心数。worker_processes8;#全局错误日志定义类型,[debug|info|notice|warn|error|crit]error_log/var/log/nginx/error.loginfo;#进程文件pid/var/run/nginx.pid;#一个nginx... 查看详情

nginx多进程+io多路复用实现高并发(代码片段)

一、nginx高并发原理简单介绍:nginx采用的是多进程(单线程)+io多路复用(epoll)模型实现高并发二、nginx多进程启动nginx解析初始化配置文件后会创建(fork)一个master进程之后这个进程会退出master进程会变为孤儿进程由init进程托... 查看详情

nginx基础配置篇(代码片段)

...蛮必要的,本篇记录nginx的一些基本配置。调整工作进程数nginx启动会创建主进程和工作进程,默认只会创建一个工作进程用于处理连接(底层使用epoll等事件处理模型),如 查看详情

c10k问题和多进程模型(代码片段)

内核空间的相关程序在调度用户空间里的进程的时候,也占用了cpu资源......nginx可以作为两种类型的反向代理http和smtp(mail)C10K问题,当一个主机的连接数过多的时候,单独一片网卡,响应在一个套接字上的请求,如何通过一个进... 查看详情

nginx之热部署(代码片段)

...其并发模型有着密不可分的关系。说白了,就是因为master进程的关系。当通知ngnix重读配置文件的时候,master进程会进行语法错误的判断。如果存在语法错误的话,返回错误,不进行装载;如果配置文件没有语法错误,那么ngnix... 查看详情

重识nginx-14nginx多进程结构(代码片段)

文章目录Nginx的请求处理流程Nginx的多进程结构Nginx进程结构演示关键配置查看ng进程信号说明reload观察worker进程的pid向Master进程发送SIGHUB向worker进程发送SIGTERMNginx的请求处理流程Nginx的多进程结构Worker进程处理请求,Master进程... 查看详情

重识nginx-14nginx多进程结构(代码片段)

文章目录Nginx的请求处理流程Nginx的多进程结构Nginx进程结构演示关键配置查看ng进程信号说明reload观察worker进程的pid向Master进程发送SIGHUB向worker进程发送SIGTERMNginx的请求处理流程Nginx的多进程结构Worker进程处理请求,Master进程... 查看详情

nginx(代码片段)

文章目录一、目录结构二、多进程模型和请求基本流程三、基础配置3.1最小配置文件3.2servername的多种匹配方式3.2.1完整匹配3.2.2通配符匹配3.2.3通配符结束匹配3.2.4正则匹配四、反向代理4.1反向代理到外网与内网主机的配置4.2负载... 查看详情

nginx架构模型及常用配置(代码片段)

...一、Nginx简介二、Nginx架构设计2.1Nginx模块化设计2.2Nginx多进程模型2.3Nginx的epoll模式三、Nginx配置文件四、Nginx日志4.1访问日志4.2错误日志五、Nginx使用5.1location5.2rewrite5.3upstream5.4跨域处理5.5防盗链5.6压缩5.7缓存5.8https一、Nginx简介 ... 查看详情

深入源码分析进程模型(代码片段)

1.操作系统是怎么组织进程的structtask_struct....../*进程状态*/volatilelongstate;/*指向内核栈*/void*stack;/*用于加入进程链表*/structlist_headtasks;....../*指向该进程的内存区描述符*/structmm_struct*mm,*active_mm;......../*进程ID,每个进程(线程)的PID都... 查看详情

nginx之进程间的通信机制(nginx频道)(代码片段)

1.Nginx频道ngx_channel_t频道是Nginxmaster进程与worker进程之间通信的常用工具,它是使用本机套接字实现的,即socketpair方法,它用于创建父子进程间使用的套接字。#include<sys/types.h>/*SeeNOTES*/#include<sys/socket.h>intsocketpair(intdomain,... 查看详情

nginx信号控制(代码片段)

...inx信号含义TERM,INTquickshutdown一般用于快速的,紧急的杀掉进程,一般不建议使用。相当于./nginx-sstop命令,强制退出QUITGracefullyshutdown优雅的关闭进程,请求结束后再关闭进程。相当于./nginx-squit命令,优雅退出HUPConfigurationreload,Star... 查看详情

nginx性能优化(代码片段)

nginx性能优化1.worker_processesn;  nginx进程数,一般为cpu的倍数2.worker_cpu_affinity0000000100000010..  为每个进程分配cpu,可多写几个,也可将一个进程分配到多个cpu3.worker_rlimit_nofile65535;  nginx进程打开的最多文件描述符数目,查看... 查看详情

简明入门讲义——nginx为何这么快(代码片段)

概览NGINX进程角色Worker如何做到单线程以一敌百热修改配置是如何实现的参考文档NGINX是战斗民族主导的一个服务端软件,主要充当负载均衡器和反向代理。NGINX进程角色一个NGINX主要由Master进程和一系列子进程组成,主进... 查看详情

第一次作业:深入源码分析进程模型(代码片段)

...   挑选一个开源的操作系统,深入源码分析其进程模型,具体包含如下内容:操作系统是怎么组织进程的进程状态如何转换(给出进程状态转换图)进程是如何调度的谈谈自己对该操作系统进程模型的看法2.进程描述&... 查看详情