nginx高性能原因

Nginx 是如何实现高性能高并发:

1 异步非阻塞:

epoll设置了超时,通过epoll监控的所有socket文件描述符也都设置为非阻塞、ET边缘触发模式(ET模式在大多数情况,ET因为触发系统调用的次数比LT少,效率比LT要高),有请求或者超时epoll_wait函数都会返回,然后去处理网络请求(每进来一个request,会有一个worker进程去处理。但不是全程的处理,处理到什么程度呢?处理到可能发生阻塞的地方,比如静态大文件分块响应、向上游(后端)服务器转发request、http状态机阻塞处,并等待请求返回。那么,这个处理的worker很聪明,他会在发送完请求后,注册一个事件:“如果upstream返回了,告诉我一声,我再接着干”。于是他就休息去了。此时,如果再有request 进来,他就可以很快再按这种方式处理。而一旦上游服务器返回了,就会触发这个事件,worker才会来接手,这个request才会接着往下走。),也就是我们所说的异步非阻塞,异步非阻塞工作方式正把当中的等待时间利用起来了,并且避免了因为大调用导致阻塞。

 

2 带负载均衡的多进程模型:

<1>nginx采用一个master进程,多个woker进程的模式,并且每个进程都会绑定指定的cpu,充分利用cpu的亲和性,降低cpu上下文切换的性能损耗(cpu亲和性 就是进程要在某个给定的 cpu上尽量长时间地运行而不被迁移到其他处理器的倾向性。Linux 内核进程调度器天生就具有被称为 软cpu亲和性(affinity) 的特性,这意味着进程通常不会在处理器之间频繁迁移。这种状态正是我们希望的,因为进程迁移的频率小就意味着产生的负载小。具体参考sched_setaffinity函数。

<3>在实际线上环境中,经常出现这样的情况:某个多线程服务跑几个月后,因为未知原因进程挂了,最终造成整个服务都会不可用。

这时候,master+多worker的多进程模型就体现了它的优势,如果代码有隐藏的并且不容易触发的bug,某个时候如果某个请求触发了这个bug,则处理这个请求的worker进程会段错误退出。但是其他worker进程不会收到任何的影响,也就是说如果一个改造后的twemproxy起了20个worker进程,某个时候一个隐藏bug被某个请求触发,则只有处理该请求的进程段错误异常,其他19个进程不会受到任何影响,该隐藏bug触发后影响面仅为5%。如果是多线程模型,则影响面会是100%。

如果某个worker进程挂了,master父进程会感知到这个信号,然后重新拉起一个worker进程,实现瞬间无感知”拉起”恢复。以下为模拟触发异常段错误流程:

如上图所示,杀掉31420 worker进程后,master进程会立马在拉起一个31451工作进程,实现了快速恢复。

多进程异常,自动”拉起”功能源码,可以参考如下demo:

<2>通过每个worker进程统计自己获取到accept_mutex的计数,保证各个worker进程之间获取到的练技术基本平衡,防止部分进程撑死、另一部分进程饿死的负载失衡的情况(利用一个负载均衡阈值ngx_accept_disabled来管理。这个阈值是进程允许的总连接数的1/8减去空闲连接数。就是当阈值为正整数时当前进程将不再处理新连接事件,取而代之的仅仅是阈值值减1。因为阈值的初始值为负值:N(总连接数)/8 - N(初始时,空闲值等于进程总允许连接数) = -(7/8)N。所以当Nginx各worker子进程间的负载均衡仅在某个worker子进程处理的连接数达到它最大处理总数的7/8时才会触发,这时该worker进程就会减少处理新连接的机会,其他空闲的worker进程就有机会去处理更多的新连接。要利用锁机制来做互斥与同步,既避免监听套接口被同时加入到多个进程的事件监控机制里,又避免监听套接口在某一时刻没有被任何一个进程监控。如果进程并没有处于过载状态,那么就会去争用锁,争锁成功就会把所有监听套接口加入到自身的事件监控机制里;争锁失败就会把监听套接口从自身的事件监控机制里删除

 

3 Master进程和worker进程如何通信?

由于master进程需要实时获取worker进程的工作状态,并实时汇总worker进程的各种统计信息,所以选择一种可靠的进程间通信方式必不可少。

在twemproxy改造过程中,直接参考nginx的信号量机制和channel机制(依靠socketpair)来实现父子进程见通信。Master进程通过信号量机制来检测子进程是否异常,从而快速直接的反应出来;此外,借助socketpair,封装出channel接口来完成父子进程见异步通信,master进程依靠该机制来统计子进程的各种统计信息并汇总,通过获取来自master的汇总信息来判断整个twemproxy中间件的稳定性、可靠性。

配置下发过程:主进程接收实时配置信息,然后通过channel机制发送给所有的worker进程,各个worker进程收到配置信息后应答给工作进程。流程如下:

获取监控信息流程和配置下发流程基本相同,master进程收到各个工作进程的应答后,由master进程做统一汇总,然后发送给客户端。

 

3  nginx通过内存池进行内存管理

模块开发者只需要关心内存的分配,而释放则交给内存池来负责,降低各模块开发的复杂度。
Nginx为每一个TCP连接都分配了一个内存池,HTTP框架为每一个HTTP请求都分配了一个内存池,在请求结束时销毁整个内存池,把曾经分配的内存一次性归还给操作系统,尽量避免出现内存碎片,减少向操作系统申请内存的次数(把需要多次向系统申请内存的操作整合成一次,大大减少了CPU资源的消耗【系统调用是非常耗资源的】)

2. 为什么 Nginx 不使用多线程?

Apache: 创建多个进程或线程,而每个进程或线程都会为其分配 cpu 和内存(线程要比进程小的多,所以worker支持比perfork高的并发),并发过大会耗光服务器资源。

Nginx: 采用单线程来异步非阻塞处理请求(管理员可以配置Nginx主进程的工作进程的数量)(epoll),不会为每个请求分配cpu和内存资源,节省了大量资源,同时也减少了大量的CPU的上下文切换。所以才使得Nginx支持更高的并发。

参考:http://blog.itpub.net/69908606/viewspace-2565161/

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值