写点什么

意犹未尽的一篇 Nginx 原理详解,面试官看了都忍不住点赞 (1)

用户头像
极客good
关注
发布于: 刚刚

而对于非阻塞模式来说,通过事件触发的方式来达到目的。我们可以认为 NIO 底层中存在一个 I/O 调度线程,它不断的扫描每个 Socket 的缓冲区,当发现写入缓冲区为空的时候,它会产生一个 Socket 可写事件,此时程序就可以把数据写入到 Socket 中。如果一次写不完,就等待下


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


一次的可写事件通知;反之,当发现缓冲区里有数据的时候,它会产生一个 Socket 可读事件,程序收到这个通知事件就可以从 Socket 读取数据了。


那么基于这些概念又引除了四个概念:?同步阻塞、同步非阻塞、异步阻塞、异步非阻塞


同步阻塞:发送方向接收方发送请求后,一直等待接收方响应;接收方在处理请求时进行的 IO 操作如果不能马上得到结果,就一直等待结果返回才响应发送方。期间一直处于阻塞状态;



同步非阻塞:发送方向接收方发送请求后,一直等待响应,接收方在进行 IO 操作的时候,可以不需要等待直接去做其他事,而因为还没有获得结果,发送方仍然处于等待状态。接收方获得 io 的操作完成后,把结果响应给发送方,接收方才进入下一次请求过程。



异步阻塞:发送方向接收方发送请求后,不用等待响应,可以接着进行其他操作。接收方处理请求时进行的 IO 操作如果不能立刻获得结果,就一直等待返回结果后向发送方响应



异步非阻塞:发送方发送请求后,不用等待响应,可以继续做其他事情。接收方处理请求时进行的 IO 操作如果不能马上得到结果,也不等待,而是去做其他事情。当 io 操作完成后,把结果通知给接收方,接收方再响应给发送方



Nginx 服务器的请求处理过程


===============


Nginx 结合了多进程机制和异步机制对外提供服务


Nginx 服务启动后,会产生一个主进程和多个工作进程。


master 进程主要用来管理 worker 进程,包含:接收来自外界的信号,向各 worker 进程发送信号,监控 worker 进程的运行状态,当 worker 进程退出后(异常情况下),会自动重新启动新的 worker 进程。


而基本的网络事件,则是放在 worker 进程中来处理了。多个 worker 进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个 worker 进程中处理,一个 worker 进程,不可能处理其它进程的求,worker 进程的个数是可以设置的,一般我们会设置与机器 cpu 核数一致。


Master 进程的作用是?



读取并验证配置文件 nginx.conf;管理 worker 进程;



Worker 进程的作用是?



每一个 Worker 进程都维护一个线程(避免线程切换),处理连接和请求;注意 Worker 进程的个数由配置文件决定,一般和 CPU 个数相关(有利于进程切换),配置几个就有几个 Worker 进程。



热部署


===


master 来管理 worker 进程,所以我们只需要与 master 进程通信就行了。master 进程会接收来自外界发来的信号,再根据信号做不同的事情,比如我们前面常用的


./sbin/nginx -c conf/nginx.conf -s reload


执行这个命令时,master 收到这个信号以后先启动一个新的 Nginx 进程,而新的 Nginx 进程在解析到 reload 参数后,就知道是要控制 Nginx 来重新加载配置文件,它会向 master 进程发送信号,然后 master 会重新加载配置文件,在启动新的 worker 进程,并向所有老的 worker 进程发送信号,告诉他们可以退休了,新的 worker 启动之后就可以以新的配置文件接收新的请求了 – 热部署的原理。



worker 进程是如何处理请求?


================


我们基本上知道了在操作 nginx 时,nginx 内部所做的事情,那么 worker 进程是如何处理请求的呢? 在 Nginx 中,所有的 worker 进程都是平等的,每个进程处理每个请求的机会是一样的。当我们提供 80 端口的 http 服务时,一个连接请求过来,每个进程都可能处理这个连接。


worker 进程是从 master 进程 fork 过来的,而在 master 进程中,会先建立好需要 listen 的 socket,然后 fork 出多个 worker 进程,当有新连接请求过来时 work 进程可以去处理,为了避免惊群效应,worker 进程在处理请求之前先要去抢占 accept_mutex,也就是互斥锁,当获得锁成功以后,就可以去解析处理这个请求。请求处理完以后再返回给客户端。




进程模型的处理方式带来的一些好处就是:进程之间是独立的,也就是一个 worker 进程出现异常退出,其他 worker 进程是不会受到影响的;此外,独立进程也会避免一些不需要的锁操作,这样子会提高处理效率,并且开发调试也更容易。


worker 进程会竞争监听客户端的连接请求:这种方式可能会带来一个问题,就是可能所有的请求都被一个 worker 进程给竞争获取了,导致其他进程都比较空闲,而某一个进程会处于忙碌的状态,这种状态可能还会导致无法及时响应连接而丢弃 discard 掉本有能力处理的请求。这种不公平的现象,是需要避免的,尤其是在高可靠 web 服务器环境下。


针对这种现象,Nginx 采用了一个是否打开 accept_mutex 选项的值,ngx_accept_disabled 标识控制一个 worker 进程是否需要去竞争获取 accept_mutex 选项,进而获取 accept 事件。ngx_accept_disabled 值:nginx 单进程的所有连接总数的八分之一,减去剩下的空闲连接数量,得到的这个 ngx_accept_disabled。


当 ngx_accept_disabled 大于 0 时,不会去尝试获取 accept_mutex 锁,并且将 ngx_accept_disabled 减 1,于是,每次执行到此处时,都会去减 1,直到小于 0。不去获取 accept_mutex 锁,就是等于让出获取连接的机会,很显然可以看出,当空闲连接越少时,ngx_accept_disable 越大,于是让出的机会就越多,这样其它进程获取锁的机会也就越大。不去 accept,自己的连接就控制下来了,其它进程的连接池就会得到利用,这样,nginx 就控制了多进程间连接的平衡了。

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
意犹未尽的一篇Nginx原理详解,面试官看了都忍不住点赞(1)