9.8.3 如何实现负载均衡
与“惊群”问题的解决方法一样,只有打开了accept_mutex锁,才能实现worker子进程间的负载均衡。在图9-6的第2步中,初始化了一个全局变量ngx_accept_disabled,它就是负载均衡机制实现的关键阈值,实际上它就是一个整型数据。
ngx_int_t
ngx_accept_disabled;
这个阈值是与连接池中连接的使用情况密切相关的,在图9-6的第2步中它会进行赋值,如下所示。
ngx_accept_disabled=ngx_cycle->connection_n/8
-ngx_cycle->free_connection_n;
因此,在Nginx启动时,ngx_accept_disabled的值就是一个负数,其值为连接总数的7/8。其实,ngx_accept_disabled的用法很简单,当它为负数时,不会进行触发负载均衡操作;而当ngx_accept_disabled是正数时,就会触发Nginx进行负载均衡操作了。Nginx的做法也很简单,就是当ngx_accept_disabled是正数时当前进程将不再处理新连接事件,取而代之的仅仅是ngx_accept_disabled值减1,如下所示。
if(ngx_accept_disabled>0){
ngx_accept_disabled—;
}else{
if(ngx_trylock_accept_mutex(cycle)==NGX_ERROR){
return;
}
……
}
上面这段代码表明,在当前使用的连接到达总连接数的7/8时,就不会再处理新连接了,同时,在每次调用process_events时都会将ngx_accept_disabled减1,直到ngx_accept_disabled降到总连接数的7/8以下时,才会调用ngx_trylock_accept_mutex试图去处理新连接事件。
因此,Nginx各worker子进程间的负载均衡仅在某个worker进程处理的连接数达到它最大处理总数的7/8时才会触发,这时该worker进程就会减少处理新连接的机会,这样其他较空闲的worker进程就有机会去处理更多的新连接,以此达到整个Web服务的均衡处理效果。虽然这样的机制不是很完美,但在维护一定程度上的负载均衡时,很好地避免了当某个worker进程由于连接池耗尽而拒绝服务,同时,在其他worker进程上处理的连接还远未达到上限的问题。因此,Nginx将accept_mutex配置项默认设为accept_mutex on。