内容: 记录nginx解决负载均衡的方法
Nginx事件循环框架中需要解决的问题:
惊群与负载不均:
1、Nginx出于充分发挥多核CPU架构性能的考虑,使用了多个worker子进程监听相同端口的设计,这样多个子进程在
accept建立新连接时会有争抢,这会带来著名的“惊群”问题,子进程数量越多问题越明显,这会造成系统性能下降。
2、另外,建立连接时还会涉及负载均衡问题。在多个子进程争抢处理一个新连接事件时, 一定只有一个worker子进程
最终会成功建立连接,随后,它会一直处理这个连接直到连接关闭。那么,如果有的子进程很“勤奋”,它们抢着建立并
处理了大部分连接,而有的子进程则“运气不好”,只处理了少量连接,这对多核CPU架构下的应用是很不利的,因为子进
程间应该是平等的,每个子进程应该尽量地独占一个CPU核心。子进程间负载不均衡,必然影响整个服务的性能
那么Nginx解决负载均衡的思路是什么呢?
就是:设置负载均衡阈值
注意:与“惊群”问题的解决方法一样,只有打开了accept_mutex锁,才能实现worker子进程间的负载均衡
Nginx初始化了一个全局变量ngx_accept_disabled,它就是负载均衡机制实现的关键阈值;
实际上它就是一个整型数据: ngx_int_t ngx_accept_disabled;
这个阈值是与连接池中连接的使用情况密切相关的,在图中第2步中它会进行赋值,如下所示:
ngx_accept_disabled = ngx_cycle->connection_n/8 - ngx_cycle->free_connection_n;
在Nginx启动时,ngx_accept_disabled的值就是一个负数,其值为连接总数的7/8。
1、当ngx_accept_disabled为负数时,不会进行触发负载均衡操作;
2、当ngx_accept_disabled为正数时,就会触发Nginx进行负载均衡操作:当前进程将不再处理新连接事件,而是
使ngx_accept_disabled值减1
代码描述:
if (ngx_accept_disabled > 0)
{
ngx_accept_disabled--;
} else {
if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR)
{
return;
}…
}
Nginx各worker子进程间的负载均衡仅在某个worker进程处理的连接数达到它最大处理总数的7/8时才会触发,
这时该worker进程就会减少处理新连接的机会,这样其它较空闲的worker进程就有机会去处理更多的新连接,
以此达到整个Web服务的均衡处理效果。虽然 这样的机制不是很完美,但在维护一定程度上的负载均衡时,很好
地避免了当某个worker进程由于连接池耗尽而拒绝服务,同时,在其它worker进程上处理的连接还远未达到上限
的问题。因此,Nginx将accept_mutex配置项默认设为accept_mutex on。
accept_mutex的开启和关闭:
新连接到达时:
1、如果激活了accept_mutex,那么多个Worker将以串行方式来处理,其中有一个Worker会被唤醒,其它的
Worker继续保持休眠状态;
2、如果没有激活accept_mutex,那么所有的Worker都会被唤醒,不过只有一个Worker能获取新连接,其它的
Worker会重新进入休眠状态
新旧版本在Nginx缺省时,是否激活accept_mutex有不同的处理方法。
对于Mutex的开关与惊群问题:Apache与Nginx的影响是不一样的:
1、因为Apache动辄就会启动成百上千的进程,如果发生惊群问题的话,影响相对较大;
2、Nginx一般将worker_processes会设置成CPU个数,所以数量并不多,发生惊群问题时,影响相对也较小。
注意:最新版本的Nginx不一定是这样子了,比如:当Nginx有了新版本Linux下的reuseport支持时,处理政策
可能发生改变,因为框架设计总是随机时间在更新的