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。