1前言随着网站负载的不断增加,负载均衡(loadbalance)已经不再是一个陌生的话题。负载均衡就是将流量负载分配到不同的服务单元,保证服务器的高可用,保证响应足够快,给用户良好的体验。nginx第一个公共版本于2004年发布,1.0版本于2011年发布,具有稳定性高、功能强大、资源消耗低等特点。从服务器市场份额来看,nginx有与Apache竞争的势头。其中,不得不提的特点就是它的负载均衡功能,这也成为了很多企业选择它的主要原因。我们将从源码的角度介绍nginx内置的负载均衡策略和扩展的负载均衡策略,并以实际工业生产为案例,对各种负载均衡策略进行比较,为nginx用户提供一些参考。2.源码分析nginx的负载均衡策略可以分为两大类:内置策略和扩展策略。内置策略包括加权循环和iphash。默认情况下,这两个策略会被编译到nginx内核中,你只需要在nginx配置中指定参数即可。扩展策略有很多,比如fair、generalhash、consistenthash等,默认没有编译到nginx内核中。由于nginx版本升级过程中,负载均衡代码没有本质变化,下面将以nginx1.0.15稳定版为例,从源码的角度分析各个策略。2.1.加权轮询(weightedroundrobin)轮询的原理很简单。首先介绍一下轮询的基本过程。下面是处理一个请求的流程图:图中有两点需要注意:***,如果加权循环算法可以分为先深搜索和先宽搜索,那么nginx使用的是先深搜索算法,会先把请求分发给权重高的机器,直到该机器的权重低于其他机器,然后才开始分发请求给下一个权重高的机器。二、当所有后端机器宕机时,nginx会立即清除所有机器的flags到初始状态,避免导致所有机器都处于超时状态,导致整个前端被撞。接下来看源码。nginx的目录结构非常清晰。weightedround-robin的路径为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台,则需要在内存池中申请内存进行存储。这个位图数组的使用可以参考下面的代码:***是实际的policy代码,逻辑比较简单,代码实现只有30行。让我们看一下代码。2.2.iphash策略iphash是nginx内置的另一种负载均衡策略。过程与轮询非常相似,但算法和具体策略有一些变化。如下图所示:iphash算法的核心实现请看下面代码:可以看到,hash值既与ip有关,也与后端机器数有关。经过测试,上述算法可以连续生成1045个不同的值,这是该算法的硬限制。Nginx使用保护机制。当在20个哈希后没有找到可用的机器时,该算法退化为轮询。因此,iphash算法本质上是一种变相的轮询算法。如果两个ip的初始hash值恰好相同,那么这两个ip的请求总是会登陆同一台服务器,这为平衡性埋下了很深的隐患。2.3.fairfair策略是一个扩展策略,默认没有编译进nginx内核。它根据后端服务器的响应时间判断负载情况,选择负载最轻的机器进行分发。这种策略具有很强的适应性,但实际的网络环境往往不是那么简单,因此必须谨慎使用。2.4.Generalhash,consistenthashGeneralhash和consistenthash也是扩展策略。一般hash可以用nginx内置的变量作为key进行hash,consistenthash使用nginx内置的consistenthashring,可以支持memcache。3对比测试了解了上面的负载均衡策略之后,接下来我们来做一些测试。主要是比较各个策略的平衡性、一致性、容灾性,从而分析出它们之间的差异,并根据数据给出各自的适用场景。为了全面客观地测试nginx的负载均衡策略,我们使用两种测试工具在不同的场景下进行测试,以减少环境对测试结果的影响。首先介绍测试工具、测试网络拓扑和基本测试流程。3.1测试工具3.1.1easyABCEasyABC是百度内部开发的一款性能测试工具。训练是使用epool模型实现的。它易于使用,可以模拟GET/POST请求。在极端情况下,它可以提供数以万计的压力,在团队内部被广泛使用。由于被测对象是一个反向代理服务器,需要在其后端搭建一个存根服务器。这里使用nginx作为stubWebServer,提供最基本的静态文件服务。3.1.2polygraphpolygraph是一款免费的性能测试工具,擅长测试缓存服务、代理、交换机等。它拥有标准化的配置语言PGL(PolygraphLanguage),为软件提供了强大的灵活性。其工作原理如下图所示:polygraph提供Client和Server,测试目标nginx放在两者之间。三者之间的网络交互使用http协议,只需要配置ip+port即可。客户端可以配置虚拟机器人的数量和每个机器人的请求速率,向代理服务器发起随机静态文件请求,服务器端根据请求的url生成随机大小的静态文件响应。选择这个测试软件的主要原因之一是生成随机url作为nginx各种哈希策略的key。此外,polygraph还提供了功能丰富的日志分析工具。有兴趣的同学可以参考附件资料。3.2.测试环境本次测试运行在5台物理机上。其中:被测对象单独搭建在一台8核机器上,另外四台4核机器分别用easyABC、webserverpile和polygraph搭建。如下图所示:3.3.测试计划先介绍一下关键的测试指标:平衡性:请求是否能均匀的发到后端一致性:相同key的请求是否能落在同一台机器上容灾:当部分后端机器挂掉时,是否可以正常工作在以上指标的指导下,我们使用easyABC和polygraph对以下四种测试场景进行了测试:场景1server_*正常提供服务;场景2server_4挂了,其他正常;场景3,server_3和server_4挂了,其他正常;在场景4中,server_*恢复正常服务。以上四个场景将按时间顺序进行,每个场景都以前一个场景为基础,测试对象不需要做任何事情,最大程度地模拟实际情况。另外考虑到测试工具本身的特点,easyabc上的测试压力在17000左右,polygraph上的测试压力在4000左右。以上测试均保证被测对象可以正常工作,注意上面没有日志级别(警报/错误/警告)出现。每个场景都记录server_*的qps,用于***策略分析。3.4.结果对比两种测试工具下的测试结果会发现结果是完全一致的,所以可以排除测试工具的影响。表1和图1是两种测试工具下轮询策略的负载情况。从图中可以看出轮询策略可以同时满足平衡和容灾。表2和图2是公平策略在两种测试工具下的负载情况。公平策略受环境的影响很大。排除测试工具的干扰后,结果仍然有很大的抖动。直觉上,这是完全不平衡的。但从另一个角度来看,也正是因为这种适应性,才能在复杂的网络环境中物尽其用。因此,在应用于工业生产之前,需要先做好特定环境下的测试工作。下面的图表展示了各种哈希策略,唯一不同的是哈希键或者具体的算法实现,所以我们一起来比较一下。在实际测试中,发现generalhash和consistencyhash都存在问题:当某台后端机器挂掉时,原本落在这台机器上的流量会丢失,而ip却没有这个问题哈希。就像上面分析iphash源码一样,当iphash失败时,会退化为轮询策略,所以不会有流量丢失。从这个层面来说,iphash也可以看成是polling的升级版。图5是iphash策略,它是nginx的内置策略,可以看作是前两种策略的特例:以源IP为key。由于测试工具不太擅长模拟大量IP下的请求,这里截取网上的实际情况进行分析。如下图所示:图5IPHashStrategyDiagram前1/3使用roundrobin策略,中间部分使用iphash策略,最后1/3仍然是roundrobin策略。可以很明显的看出iphash的balance存在很大的问题。原因不难分析。在实际网络环境中,存在大量的大学出口路由器ip、企业出口路由器ip等网络节点。这些节点带来的流量往往是普通用户的几百上千倍,而iphash策略恰恰是按照IP来划分流量,自然会造成上述后果。4小结通过实际对比测试,我们验证了nginx的各个负载均衡策略。下面从平衡性、一致性、容灾性、适用场景等角度对各种策略进行对比。如下图所示:我们从源码和实际测试数据的角度对nginx负载均衡策略进行了分析和讲解,并给出了各种策略适用的应用场景。通过分析不难发现,没有一种策略是万能的,具体场景选择哪种策略在一定程度上取决于用户对策略的熟悉程度。以上分析和测试数据可以对大家有所帮助,期待更多更好的负载均衡策略不断涌现,造福更多运维开发同学。
