nginx相关基础知识

1.“惊群”问题及其解决方案

“惊群”问题:

在建立连接的时候,Nginx处于充分发挥多核CPU架构性能的考虑,使用了多个worker子进程监听相同端口的设计,这样多个子进程在accept建立新连接时会有争抢,这会带来“惊群”问题,子进程数量越多越明显,这会造成系统性能的下降。

一般情况下,有多少CPU核心就有配置多少个worker子进程。假设现在没有用户连入服务器,某一时刻恰好所有的子进程都休眠且等待新连接的系统调用(如epoll_wait),这时有一个用户向服务器发起了连接,内核在收到TCP的SYN包时,会激活所有的休眠worker子进程。最终只有最先开始执行accept的子进程可以成功建立新连接,而其他worker子进程都将accept失败。这些accept失败的子进程被内核唤醒是不必要的,他们被唤醒会的执行很可能是多余的,那么这一时刻他们占用了本不需要占用的资源,引发了不必要的进程切换,增加了系统开销。

如何解决“惊群问题”

题外话:Linux内核2.6已经解决了accept时的惊群问题,多个子进程accept堵塞睡眠时,连接到来,只有一个进程的accept会被唤醒返回。但现在子进程的实现方式不是直接accept,而是将初始化好的fd加入到epoll 的事件队列中,epoll返回后再调用accept。Linux无法解决多个子进程epoll返回的情况。这需要子进程自己处理。 所以我们就需要在应用层面解决“惊群”问题。

解决“惊群问题”的关键:ngx_accept_mutex锁和post事件队列

在打开accept_mutex锁的情况下,当前进程只有调用ngx_trylock_accept_mutex方法并获取到accept_mutex后,当前的worker进程才会去监听web端口。如果没有获取到accept_mutex锁则不会监听web端口,当前进程就不会处理新连接事件,就只能处理已有连接上的事件。

那么接下来就会考虑什么时候释放ngx_accept_mutex锁,因为进程获取accept_mutex锁之后就会调用ngx_process_events方法处理网络事件了,这些事件除了新连接事件之外,还包括已有连接上的事件,显然不能等到这批事件全部执行完。因为这个worker进程上可能有已有的许多活跃的连接,处理这些连接上的事件会占用很长时间,其他worker进程很难得到处理新连接的机会,并且这时也不能监听到web端口。所以就要依靠post事件处理机制,Nginx设计了两个队列:ngx_posted_accept_events队列(存放新连接事件的队列)和ngx_posted_events队列(存放普通事件的队列)。

如果进程获取到了accept_mutex锁,它就会设置一个变量为1,那么在后续进行的ngx_process_events方法处理网络事件的时候,就不会立即调用这些事件的handler方法,而是将他们分类放入post队列中,新连接事件全部放在ngx_posted_accept_events队列(存放新连接事件的队列)中,普通事件全部放在ngx_posted_events队列(存放普通事件的队列)中。这样接下来就会处理ngx_posted_accept_events队列(存放新连接事件的队列)中的事件,处理完之后就会释放ngx_accept_mutex锁,然后再处理ngx_posted_events队列(存放普通事件的队列)中的事件。这样就大大减少了ngx_accept_mutex锁被占用的时间。

2.负载均衡问题及其解决方案

“负载均衡”问题:

在多个子进程争抢处理一个新连接事件的时候,一定只有一个worker子进程最终会成功建立连接,随后,这个进程会一直处理这个连接直到连接关闭。那么,如果有的子进程很“勤奋”,抢到建立并处理了大部分连接,然而有的进程“运气不好”,只抢到建立了少量的连接。那么这对多核CPU架构下的应用是很不利的,因为子进程之间应该是平等的,子进程负载不均衡必然会影响整个服务的性能。

如何解决“负载均衡”

只有打开了accept_mutex锁,才能实现worker进程之间的负载均衡。初始化一个全局变量ngx_accept_disabled,初始化值为连接池总的连接数的八分之一减去空闲连接数,所以在nginx启动的时候,ngx_accept_disabled变量就是一个负数,值为负的连接总数的八分之七,当ngx_accept_disabled为负数时,不会触发负载均衡操作,当ngx_accept_disabled为正数时,就会触发负载均衡操作了,当ngx_accept_disabled是正数时,当前进程将不再处理新连接事件,取而代之的是ngx_accept_disabled值减一。

也就是说当前使用的连接数达到连接总数的八分之七时,就不会处理新连接了,每次调用事件循环时,不会调用ngx_trylock_accept_mutex去尝试获得accept_mutex锁,而是会将ngx_accept_disabled减一然后直接调用ngx_process_events方法。直到ngx_accept_disabled降到总连接数的八分之七以下时,才会调用ngx_trylock_accept_mutex试图去处理新的连接。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值