nginx(4)-负载均衡的5种策略及原理nginx的upstream⽬前⽀持的5种⽅式的分配
1、轮询(默认)
每个请求按时间顺序逐⼀分配到不同的后端服务器,如果后端服务器down掉,能⾃动剔除。
upstream backserver {
server 192.168.0.14;
server 192.168.0.15;
}
2、指定权重
指定轮询⼏率,weight和访问⽐率成正⽐,⽤于后端服务器性能不均的情况。
upstream backserver {
server 192.168.0.14 weight=8;
server 192.168.0.15 weight=10;
}
3、IP绑定 ip_hash
每个请求按访问ip的hash结果分配,这样每个访客固定访问⼀个后端服务器,可以解决session的问题。upstream backserver {
ip_hash;
server 192.168.0.14:88;
server 192.168.0.15:80;
}
4、fair(第三⽅)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream backserver {
server server1;
server server2;
fair;
}
5、url_hash(第三⽅)
按访问url的hash结果来分配请求,使每个url定向到同⼀个后端服务器,后端服务器为缓存时⽐较有效。upstream backserver {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}
在需要使⽤负载均衡的server中增加
proxy_pass backserver/;
upstream backserver{
ip_hash;
server 127.0.0.1:9090 down; (down 表⽰当前的server暂时不参与负载)
server 127.0.0.1:8080 weight=2; (weight 默认为1.weight越⼤,负载的权重就越⼤)
server 127.0.0.1:6060;
server 127.0.0.1:7070 backup; (其它所有的⾮backup机器down或者忙的时候,请求backup机器)
}
max_fails :允许请求失败的次数默认为1.当超过最⼤次数时,返回proxy_next_upstream 模块定义的错误
fail_timeout:max_fails次失败后,暂停的时间
深⼊解析:
1 前⾔
随着⽹站负载的不断增加,负载均衡(load balance)已不是陌⽣话题。负载均衡是将流量负载分摊到不同的服务单元,保证服务器的⾼可⽤,保证响应⾜够快,给⽤户良好的体验。
nginx第⼀个公开版发布于2004年。2011年发布了1.0版。它的特点是稳定性⾼、功能强⼤、资源消耗低。从服务器市场占有率来看,nginx 已有与Apache分庭抗礼势头。其中,不得不提到的特性就是其负载均衡功能,这也成了很多公司选择它的主要原因。
我们将从源码的⾓度介绍nginx的内置负载均衡策略和扩展负载均衡策略,以实际的⼯业⽣产为案例,对⽐各负载均衡策略,为nginx使⽤者提供⼀些参考。
2. 源码剖析
nginx的负载均衡策略可以划分为两⼤类:内置策略和扩展策略
内置策略包含加权轮询和ip hash,在默认情况下这两种策略会编译进nginx内核,只需在nginx配置中指明参数即可。扩展策略有很多,如fair、通⽤hash、consistent hash等,默认不编译进nginx内核。
由于在nginx版本升级中负载均衡的代码没有本质性的变化,因此下⾯将以nginx1.0.15稳定版为例,从源码⾓度分析各个策略。
2.1. 加权轮询(weighted round robin)
轮询的原理很简单,⾸先我们介绍⼀下轮询的基本流程。如下是处理⼀次请求的流程图:
图中有两点需要注意:
第⼀,如果可以把加权轮询算法分为先深搜索和先⼴搜索,那么nginx采⽤的是先深搜索算法,即将⾸先将请求都分给⾼权重的机器,直到该机器的权值降到了⽐其他机器低,才开始将请求分给下⼀个⾼权重的机器。
第⼆,当所有后端机器都down掉时,nginx会⽴即将所有机器的标志位清成初始状态,以避免造成所有的机器都处在timeout的状态,从⽽导致整个前端被夯住。
接下来看下源码。nginx的⽬录结构很清晰,加权轮询所在路径为nginx-1.0.15/src/http/ngx_http_upstream_round_robin.[c|h],在源码的基础上,针对重要的、不易理解的地⽅我加了注释。⾸先看下ngx_http_upstream_round_robin.h中的重要声明:
从变量命名中就可以⼤致猜出其作⽤。解释⼀下current_weight和weight的区别,前者为权重排序的值,随着处理请求会动态的变化,后者
则是配置值,⽤来恢复初始状态。
接下我们来看下轮询的创建过程。代码如下图:
这⾥有个tried变量需要做些说明:tried中记录了服务器当前是否被尝试连接过。他是⼀个位图。如果服务器数量⼩于32,则只需在⼀个int中即可记录下所有服务器状态。如果服务器数量⼤于32,则需在内存池中申请内存来存储。
对该位图数组的使⽤可参考如下代码:
最后是实际的策略代码,逻辑较简单,代码实现也只有30⾏。来看代码。
2.2. ip hash策略
ip hash是nginx内置的另⼀个负载均衡策略,流程和轮询很类似,只是其中的算法和具体的策略有些变化。如下图所⽰:
ip hash算法的核⼼实现请看如下代码:
可以看到,hash值既与ip有关⼜与后端机器的数量有关。经测试,上述算法可以连续产⽣1045个互异的value,这是此算法硬限制。nginx使⽤了保护机制,当经过20次hash仍然不到可⽤的机器时,算法退化成轮询。
因此,从本质上说,ip hash算法是⼀种变相的轮询算法,如果两个ip的初始hash值恰好相同,那么来⾃这两个ip的请求将永远落在同⼀台服务器上,这为均衡性埋下了较深隐患。
2.3. fair
fair策略是扩展策略,默认不被编译进nginx内核。它根据后端服务器的响应时间判断负载情况,从中选出负载最轻的机器进⾏分流。
这种策略具有很强的⾃适应性,但是实际的⽹络环境往往不是那么简单,因此须慎⽤。
2.4.通⽤hash、⼀致性hash
通⽤hash和⼀致性hash也是种扩展策略。通⽤hash可以以nginx内置的变量为key进⾏hash,⼀致性hash采⽤了nginx内置的⼀致性hash 环,可⽀持memcache。
3 对⽐测试
了解了以上负载均衡策略,接下来我们来做⼀些测试。
主要是对⽐各个策略的均衡性、⼀致性、容灾性等,从⽽分析出其中的差异性,根据数据给出各⾃的适⽤场景。
为了能够全⾯、客观的测试nginx的负载均衡策略,我们采⽤两个测试⼯具、在不同场景下做测试,以此来降低环境对测试结果造成的影响。
⾸先给⼤家介绍测试⼯具、测试⽹络拓扑和基本之测试流程。
前端测试和后端测试的区别
3.1 测试⼯具
3.1.1  easyABC
easyABC是百度内部开发的性能测试⼯具,培训采⽤epool模型实现,简单易上⼿,可以模拟GET/POST请求,极限情况下可以提供上万的压⼒,在团队内部得到⼴泛使⽤。
由于被测试对象为反向代理服务器,因此需要在其后端搭建桩服务器,这⾥⽤nginx作为桩Web Server,提供最基本的静态⽂件服务。
3.1.2  polygraph
polygraph是⼀款免费的性能测试⼯具,以对缓存服务、代理、交换机等⽅⾯的测试见长。它有规范的配置语⾔PGL(Polygraph Language),为软件提供了强⼤的灵活性。其⼯作原理如下图所⽰:
polygraph提供Client端和Server端,将测试⽬标nginx放在⼆者之间,三者之间的⽹络交互均⾛http协议,只需配置ip+port即可。
Client端可以配置虚拟robot的个数以及每个robot发请求的速率,并向代理服务器发起随机的静态⽂件请求,Server端将按照请求的url⽣成随机⼤⼩的静态⽂件做响应。
选⽤这个测试软件的⼀个主要原因:可以产⽣随机的url作为nginx各种hash策略key。
另外polygraph还提供了⽇志分析⼯具,功能⽐较丰富,感兴趣的同学可以参考附录材料。
3.2. 测试环境
本次测试运⾏在5台物理机。其中:被测对象单独搭在⼀台8核机器上,另外四台4核机器分别搭建了easyABC、webserver桩和polygraph。如下图所⽰:
3.3. 测试⽅案
给各位介绍⼀下关键的测试指标:
均衡性:是否能够将请求均匀的发送给后端
⼀致性:同⼀个key的请求,是否能落到同⼀台机器
容灾性:当部分后端机器挂掉时,是否能够正常⼯作
以上述指标为指导,我们针对如下4个测试场景分别⽤easyABC和polygraph测试:
场景1      server_*均正常提供服务;
场景2      server_4挂掉,其他正常;
场景3      server_3、server_4挂掉,其他正常;
场景4      server_*均恢复正常服务。
上述四个场景将按照时间顺序进⾏,每个场景将建⽴在上⼀个场景基础上,被测试对象⽆需做任何操作,以最⼤程度模拟实际情况。
另外,考虑到测试⼯具⾃⾝的特点,在easyabc上的测试压⼒在17000左右,polygraph上的测试压⼒在4000左右。以上测试均保证被测试对象可以正常⼯作,且⽆任何notice级别以上(alert/error/warn)的⽇志出现,在每个场景中记录下server_*的qps⽤于最后的策略分析。
3.4.  结果
对⽐在两种测试⼯具下的测试结果会发现,结果完全⼀致,因此可以排除测试⼯具的影响。表1和图1是轮询策略在两种测试⼯具下的负载情况。
从图表中可以看出,轮询策略对于均衡性和容灾性都可以做到较好的满⾜。