nginx

Nginx

首先要明白,Nginx 采用的是多进程(单线程) & 多路IO复用模型。使用了 I/O 多路复用技术的 Nginx,就成了”并发事件驱动“的服务器。

这里写图片描述

 1、概念:

       NGINX采用了异步、事件驱动的方法来处理连接。这种处理方式无需(像使用传统架构的服务器一样)为每个请求创建额外的专用进程或者线程,而是在一个工作进程中处理多个连接和请求。为此,NGINX工作在非阻塞的socket模式下,并使用了epoll 和 kqueue这样有效的方法。

   2、什么是epoll

       特性:epoll的最大好处在于他不会随着被监控描述符的数目的增长而导致效率极致下降。epoll监控的描述符的数目很大,并且epoll对描述符的响应是触发的,即当有描述符有时间发生会有触发。

       epoll通过在Linux内核中申请一个简易的文件系统(文件系统一般用什么数据结构实现?B+树),其工作流程分为三部分:

1)、调用 int epoll_create(int size)建立一个epoll对象,内核会创建一个eventpoll结构体,用于存放通过epoll_ctl()向epoll对象中

添加进来的事件,这些事件都会挂载在红黑树中。

2)、调用 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) 在 epoll 对象中为 fd 注册事件,所有添加

到epoll中的事件都会与设备驱动程序建立回调关系,也就是说,当相应的事件发生时会调用这个sockfd的回调方法,将sockfd添加到eventpoll

中的双链表。

3)、调用 int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout) 来等待事件的发生,timeout

为 -1 时,该调用会阻塞知道有事件发生

这样,注册好事件之后,只要有 fd 上事件发生,epoll_wait() 就能检测到并返回给用户,用户就能”非阻塞“地进行 I/O 了。

epoll() 中内核则维护一个链表,epoll_wait 直接检查链表是不是空就知道是否有文件描述符准备好了。能达到这种效果,是因为在内核实现中

epoll 是根据每个 sockfd 上面的与设备驱动程序建立起来的回调函数实现的。

可以看出,因为一个进程里只有一个线程,所以一个进程同时只能做一件事,但是可以通过不断地切换来“同时”处理多个请求。


例子:Nginx 会注册一个事件:“如果来自一个新客户端的连接请求到来了,再通知我”,此后只有连接请求到来,服务器才会执行 accept()

来接收请求。又比如向上游服务器(比如 PHP-FPM)转发请求,并等待请求返回时,这个处理的 worker 不会在这阻塞,它会在发送完请求

后,注册一个事件:“如果缓冲区接收到数据了,告诉我一声,我再将它读进来”,于是进程就空闲下来等待事件发生。

Nginx 与 多进程模式 Apache 的比较:

事件驱动适合于I/O密集型服务,多进程或线程适合于CPU密集型服务: 
1、Nginx 更主要是作为反向代理,而非Web服务器使用。其模式是事件驱动。 

2、事件驱动服务器,最适合做的就是这种 I/O 密集型工作,如反向代理,它在客户端与WEB服务器之间起一个数据中转作用,

纯粹是 I/O 操作,自身并不涉及到复杂计算。因为进程在一个地方进行计算时,那么这个进程就不能处理其他事件了。 

3、Nginx 只需要少量进程配合事件驱动,几个进程跑 libevent,不像 Apache 多进程模型那样动辄数百的进程数。 
5、Nginx 处理静态文件效果也很好,那是因为读写文件和网络通信其实都是 I/O操作,处理过程一样。

   3、什么是文件描述符

      文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。

   4、epoll的工作

          检测四类事件:

             # 处理新事件

             # 定时处理事件

             # 处理普通读写

             # 处理从磁盘读事件

(1)nginx的处理连接事件和处理其他事件都是在同一个I/O复用下,那么它是如何保证连接事件对响应的要求的呢?niginx是通过将获取的事件先不调用其回调,而是把他们先放入俩个post队列,这俩个队列分别为

.ngx_posted_accept_events
.ngx_posted_events

第一个队列用来保存连接事件,而第二个队列用来保存普通读写事件,之后在执行时我们可以先保证ngx_posted_accept_events中的事件先处理,就可以保证连接对响应速度的敏感性

         (2)如何防止串话 
    串话问题可以说是服务器程序中都需要处理的一个问题。串话问题是指刚刚关闭了一个套接字,又来了一个新连接,而新连接刚好系统给分配的就是刚关闭的那个套接字,那么如果方才哪个套接字还有事件未处理完成,接下来它给对应的套接字发送数据很有可能就会发到新建立的用户那。那么nginx如何来解决这个问题呢?很简单,nginx在每次获得新连接后都会将连接中的一个标志为置反,这样本个连接和上个连接的instance就会不同,而每个事件都包含了连接,所以每次处理事件时只需要比较事件中的instance是否相同就OK了

        (3)如何处理”惊群问题” 
    所谓惊群问题就是说多个进程在同时监听同一个端口,当有连接到来时,系统会把多个进程都唤醒,但是当然任然只有一个进程能处理到新连接,所以本来其他进程是不需要被唤醒的,但是被唤醒了,这就是注明的惊群问题。nginx解决它的方法也很简单,只需要保证同一时间点只有一个进程在监听端口就可避免惊群问题了。但是问题的关键是如何能保证同一时间点只有一个进程来监听端口。nginx采用了尝试加锁,根据加锁的返回值确定本进程是否要接下来处理新连接事件,从而解决了”惊群问题”

      (4)如何解决负载均衡

    nginx解决个进程间的负载均衡问题并没有均衡分配,而是当每个进程处理的额连接数超过了规定其处理的最大连接数的7/8时,就会本次不处理连接,而是将其处理的连接数-1,这样相当于就把机会让给了其他线程,从而实现了负载均衡了。

nginx 进程模型

  1、master进程

   主要用来管理worker进程,包含:接收来自外界的信号,向各worker进程发送信号,监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新启动新的worker进程。master进程充当整个进程组与用户的交互接口,同时对进程进行监护。它不需要处理网络事件,不负责业务的执行,只会通过管理worker进程来实现重启服务、平滑升级、更换日志文件、配置文件实时生效等功能

     2、worker进程之间是平等的,每个进程,处理请求的机会也是一样的。当我们提供80端口的http服务时,一个连接请求过来,每个进程都有可能处理这个连接,怎么做到的呢?首先,每个worker进程都是从master进程fork过来,在master进程里面,先建立好需要listen的socket(listenfd)之后,然后再fork出多个worker进程。所有worker进程的listenfd会在新连接到来时变得可读,为保证只有一个进程处理该连接,所有worker进程在注册listenfd读事件前抢accept_mutex,抢到互斥锁的那个进程注册listenfd读事件,在读事件里调用accept接受该连接。当一个worker进程在accept这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,这样一个完整的请求就是这样的了。  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值