nginx架构初探

nginx是多进程的架构,由master进程和多个worker进程组成。master进程和worker进程之间

用信号进行通信。nginx默认是以后台进程的形式运行的。系统管理员通过信号与master进程通信

进而与worker进程通信。同一个请求只会在一个worker进程之间进行处理。worker进程的数目是

可以通过配置文件改变的。一般worker进程的数目设置为cpu的核数。进程越多并不代表性能越高,

因为操作系统在管理多进程的时候还需要进程的上下文切换,这个也是有时间消耗的。

 

nginx进程模型

 

1、nginx的信号处理

kill -HUP pid用于告诉nginx,从容地重启nginx,我们一般用这个信号来重启nginx,或重新加载配置,因为是从容地重启,因此服务是不中断的。master进程在接收到HUP信号后是怎么做的呢?首先master进程在接到信号后,会先重新加载配置文件,然后再启动新的进程,并向所有老的进程发送信号,告诉他们可以光荣退休了。新的进程在启动后,就开始接收新的请求,而老的进程在收到来自master的信号后,就不再接收新的请求,并且在当前进程中的所有未处理完的请求处理完成后,再退出。当然,直接给master进程发送信号,这是比较老的操作方式,nginx在0.8版本之后,引入了一系列命令行参数,来方便我们管理。比如,./nginx -s reload,就是来重启nginx,./nginx -s stop,就是来停止nginx的运行。如何做到的呢?我们还是拿reload来说,我们看到,执行命令时,我们是启动一个新的nginx进程,而新的nginx进程在解析到reload参数后,就知道我们的目的是控制nginx来重新加载配置文件了,它会向master进程发送信号,然后接下来的动作,就和我们直接向master进程发送信号一样了。

2.nginx如何处理请求

每一个nginx的worker进程都是平等的,都有同样的机会获得处理一个client请求的机会,

nginx启动之后,master进程会去监听80端口,worker进程从master进程fork出来之后,

子进程继承了父进程打开的文件句柄,则子进程同样监听了80端口,每个请求来了之后

所有在accept在这个socket上面的进程,都会收到通知,而只有一个进程可以accept这个

连接,其它的则accept失败,这是所谓的惊群现象。当然,nginx也不会视而不见,所以

nginx提供了一个accept_mutex这个东西,从名字上,我们可以看这是一个加在accept上

的一把共享锁。有了这把锁之后,同一时刻,就只会有一个进程在accpet连接,这样就

不会有惊群问题了。accept_mutex是一个可控选项,我们可以显示地关掉,默认是打开

的。当一个worker进程在accept这个连接之后,就开始读取请求,解析请求,处理请求

,产生数据后,再返回给客户端,最后才断开连接,这样一个完整的请求就是这样的了。

我们可以看到,一个请求,完全由worker进程来处理,而且只在一个worker进程中处理。

nginx采用了异步非阻塞的方式来处理请求。nginx为了更好的利用多核特性,提供了cpu

亲缘性的绑定选项,我们可以将某一个进程绑定在某一个核上,这样就不会因为进程的

切换带来cache的失效。

nginx在做4个字节的字符串比较时,会将4个字符转换成一个int型,再作比较,以减少

cpu的指令数等等。

3. nginx的事件处理模型

对于一个基本的web服务器来说,事件通常有三种类型,网络事件、信号、定时器。

 

while (true) {
    for t in run_tasks:
        t.handler();
    update_time(&now);
    timeout = ETERNITY;
    for t in wait_tasks: /* sorted already */
        if (t.time <= now) {
            t.timeout_handler();
        } else {
            timeout = t.time - now;
            break;
        }
    nevents = poll_function(events, timeout);
    for i in nevents:
        task t;
    if (events[i].type == READ) {
        t.handler = read_handler;
    } else (events[i].type == WRITE) {
        t.handler = write_handler;
    }
    run_tasks_add(t);
}

 

 

 

posted on 2013-04-06 18:20  flowly  阅读(523)  评论(0编辑  收藏  举报

导航