论文名称:基于动态权重的一致性哈希微服务负载均衡优化
随着互联网技术的发展,互联网服务器集群的负载能力正面临前所未有的挑战。在这样的背景下,实现合理的负载均衡策略变得尤为重要。为了达到最佳的效率,可以利用一致性哈希算法对集群负载均衡系统进行负载分配。针对微服务架构的服务器集群场景,本文分析了集群负载均衡的特性,并提出了一种基于虚拟节点的一致性哈希环设计与分割方法,以及基于动态权值的分配策略。在一致性哈希算法的基础上,实现了服务集群之间的负载转移,解决了微服务集群中服务负载增多导致负载不均衡的问题,进而防止某些服务因负载压力过大而导致崩溃的情况。实验结果表明,与传统的一致性哈希算法相比,改进后的负载均衡策略降低了负载不均衡的概率至原来的31%;并且动态分配策略具有良好的负载均衡性能,有效地解决了微服务分布式架构的负载均衡问题。
关键词:微服务;一致性哈希;负载均衡;动态权值
随着信息时代的发展,人们对系统网站的使用量越来越多,这对系统服务器的负载能力提出了考验。解决负载问题一般是采用2种方法,一种是使用具有强大硬件配置的后台服务网络,但因为各种原因这种方法很难实现;而另一种便是采用负载均衡方法来解决服务负载过大的问题。负载均衡广泛地应用于分布式环境,由于当今大数据与云计算的广泛使用,分布式服务系统也被开发人员频繁使用。其中微服务架构作为分布式架构的代表,因为其按功能来划分服务的特点,会导致各个服务的负载均衡难以控制,出现有的服务访问量过高,而有的服务基本无人访问的问题。
目前解决负载均衡的方法有很多,但是针对微服务架构的负载均衡方法还在不断地研究之中。很多企业都在构建自己的微服务服务集群,开发自己的云计算平台,因此解决微服务负载均衡问题被各大公司提上了日程。
针对微服务的负载均衡问题,本文提出一种基于动态权重的一致性哈希负载均衡优化方法。一致性哈希是一种具有良好横向扩展性的集群动态扩展技术。但是,一致性哈希自身并没有负载均衡的措施,很容易导致负载的倾斜。本文针对电商系统,将系统按功能划分微服务架构,部署在 Docker 容器中,提出一种基于虚拟机节点的一致性哈希服务划分方式,使用动态权重实现服务访问量过大时,自动增加服务和服务负载传递。通过与轮询和传统一致性哈希算法的实验对比,表明此方法相比传统一致性哈希算法在负载均衡方面有很大的性能提升。
针对微服务集群的负载均衡问题,当使用微服务时,首先要考虑一些设计上的均衡问题,例如平衡微服务的大小和数量,平衡单个微服务和整个系统之间的非功能性需求。文献[1]介绍了一种用 Hash 算法解决这些平衡问题的方案。文献[2]介绍了一种用于构建云应用程序的软件框架 Orle-ans,它运用贪婪策略处理负载平衡。它将请求随机分配给服务器,如果请求被分配给过载的服务器,服务器将拒绝请求,然后其被重新分配给另一台服务器;如果服务器未过载,但服务器上的请求激活空间过载,则到达的请求将被发送到此服务器上新创建的激活空间中,闲置足够长时间的激活空间将被关闭,此方法类似于本文的微服务方法。但是,本文添加了权重属性以更准确地测量负载。Microsoft Azure Service Fabric 的平衡管理器根据网络流量来计算哈希函数。哈希函数需要源 IP、源端口、目标 IP、目标端口和协议类型等信息,管理器确保来自同一链接的所有包都被相同的服务器接收并且平均分配。文献[3]提出了一种运用一致性哈希加强缓存来减小大型 Web 应用程序中故障的负面影响。Ringpop 是一个 Uber 开发的使用一致性哈希进行负载均衡的开源库,它为每个节点添加统一数量的副本点,这与本文的方法类似。但是,由于节点分布不均,无法保证这些点的均匀分布。文献[4]介绍了一种针对哈希环节点的遍历次数进行优化的多重查询方法;文献[5]提出了 EFAH Hashing 算法;文献[6]提出了一种更快捷、占用资源更少的一致性哈希算法,叫做跳跃性一致性哈希算法;文献[7]提出了一种基于跳跃 Hash 的对象分布算法。文献[7]研究了基于 Nginx 服务器的 Web 服务集群的负载均衡场景,提出了一种基于动态权重最小连接算法 DWLC(Dynamic Weighted Least-Connection),根据每台从机的性能来决定权重设置,并根据 Least-Connection 算法来决定最后分配结果。
容器技术近些年被广泛应用到分布式系统开发中。在所有的容器平台中,Docker 绝对是最受开发者欢迎的。2013年,Docker 的推出开启了应用程序开发的一场革命,有大量的论文使用 Docker 作为环境的解决方案。文献[8]测试了本地 Docker 环境与传统 RedHat 环境之间的性能差异。该测试表明,在性能之间只有0.4%的可忽略的差异。这意味着 Docker 容器可以在生产环境中发挥更大的作用。文献[9]提出了一种基于 Docker 和 Agave 的网关,在 Docker 的帮助下将网关更加轻量级化。
实现微服务架构的负载均衡是非常重要的,因为不知道将会有多少用户进行访问。假设一个服务同时处理用户请求的上限为1000,分配20个服务为10000名用户来提供服务。当有20000名用户发出请求时,将必须开启新的服务来处理新增加的请求,这些服务中有的服务是过载的而有的服务却是相对空闲的。
本文选择一致性哈希作为哈希函数。然而一致性哈希函数存在一些缺陷。一致性哈希在超过1000个虚拟节点的环境中效果最好,而通常很多应用程序的切片键太少,所以无法使用一致性哈希来解决负载均衡问题,因此需要改进以弥补这种缺陷。
虚拟节点是一种被广泛应用于工程场景的概念,通过网络映射的方式,在一台物理主机上搭建多个网络连接。本文运用虚拟节点,旨在缩短用户的请求映射到哈希环上后寻找目标节点所需要遍历的哈希长度,从而提升分配的效率。
一致性哈希方法的基本原理是将存储空间抽象成一个232节点的圆,将存储节点分配到这个圆上,环上的节点都有一个哈希值。采用同样的方法求出存储数据的键的哈希值,并同样映射到圆上。然后从数据映射到的位置顺时针查找,将数据存储在第一个找到的服务器上。
在本文微服务架构场景下,一致性哈希的关键步骤是将每个服务映射到圆边缘上的点,但如果服务的数量不够,会导致分布不均匀,这就会造成负载不均的问题。本文用于解决该问题的方法是在用户与服务之间增加一个虚拟层,其哈希环如图1所示,虚拟层由大量虚拟节点组成。使用一致性哈希创建用户与虚拟节点之间的映射,虚拟节点与服务之间通过简单取模操作创建映射,通过这种方法就有足够的虚拟节点来进行一致性哈希操作。虚拟节点的数量也很重要,如果虚拟节点的数量过少,将会导致原有的一致性哈希方法负载均衡效果不明显;反之,则会导致找到一个对应用户的虚拟节点所需时间过长。
本文根据用户请求的IP地址来计算用户的key,服务的key通过服务的IP地址与端口来计算。我们使用FNV(Fowler-Noll-Vo)算法[10]来Hash这些信息。FNV算法分为FNV-1,FNV-1a和FNV-03种,目前FNV-0算法已经被放弃使用了,而FNV-1a算法只是在FNV-1的基础上将相乘和异或运算进行了顺序调换,其它过程和参数与FNV-1相同,FNV-1a算法在进行小数据哈希时有更好的性能(小于4个字节),故本文采用FNV-1算法。FNV-1算法能在保持较小冲突率的情况下Hash大量的数据,因为它高度分散的特性,使其适用于Hash一些非常相近的字符串。通过求出的数据Hash值,可以尽量保证相同的用户Hash到相同的服务上去。使用FNV-1算法来Hash信息如图2所示。
因为一致性哈希算法本身并没有相应的负载均衡策略,所以本文通过一种基于动态权值分配的方法对微服务的负载进行均衡优化。分布式系统的负载均衡是复杂的,其系统资源占用因用户而异,一些活跃的用户需要更多的资源,因此需要为其开辟更多的微服务;相反,一些相对不活跃的用户很少访问服务,不需要给他们分配很多微服务。
我们根据用户的访问情况计算用户的权重,将用户权重属性定义到用户的数据表中,权重定义为:
其中,W是用户的权重值,Nu是用户发起请求的次数,Ns是请求调用微服务的数量,t是用户访问的时间。Nu,Ns和t由服务收集和更新,通过自动平衡服务进行更改。因为权重短时间内不会显著变化,所以可以间隔一段时间后进行更改。
自动平衡服务计算并保存每个服务组中用户的总权重。如果一个用户想要登录,并且给用户分配的权重超过了给他分配的服务权重的上限,自动平衡服务就会撤销之前的分配,并且将其分配给一个新的服务。如果所有的服务都达到了上限,自动平衡服务就会开辟一个新的服务,并将用户分配给这个服务。这样,负载过高的服务只能接收那些不活跃的用户,而活跃的用户会分配给负载相对较低的服务。
动态权重均衡算法如算法1所示。
如果用户超过1小时没有任何操作,自动平衡服务将从服务器组中减去此用户的权重。如果用户之后又进行操作,自动平衡服务将重复上述操作。
在分布式架构系统中,用户的迁移量对系统的负载均衡尤为重要,当某些服务中的用户访问量增多时,会导致服务的压力过大,影响系统执行效率,严重时会导致服务宕机崩溃,因此,需要将负载压力过大的服务中的用户转移到其他压力相对较小的服务中去。
当用户登录或注销时,服务的总权重将变得不平衡。可以关闭那些空闲的服务,但是有些服务还是负载过大。故需要将一些负载压力过大服务中的服务请求转移到负载相对小的服务中。因此,本文设计了一种基于动态权重的服务之间负载转移的算法。
负载转移算法如算法2所示。
通过遍历所有的服务和用户,检查哪些用户请求需要被转移,哪些服务可以用来接受这些请求。当遍历所有的服务,没有服务满足接收用户请求的条件时,系统将自动开启一个新的服务,用来接收转移的用户请求。
在该算法中,通过概率搜索来选择接收用户转移的服务,而不是通过随机选择和在符合条件的服务列表中顺序选择。这种方法是由Menon等人[11]首次提出的,该方法按固定顺序从多个处理器中选择一个处理器。本文将目标换为系统中无顺序的微服务,自动平衡服务为空闲服务列表中的每个服务分配一个概率。服务被选择的概率如下所示:
其中,Pi 是分配给服务i 的概率,Lmax是系统中服务的负载最大值,Lmin是系统中服务的负载最小值,Lavg是系统中服务的负载平均值。Z 是一个与负载最大值、最小值和平均值相关的常数。然后自动平衡服务根据概率Pi 来选择接收用户转移的服务,负载越大的服务被选择的概率越小。在应用上,其实不需要选择负载最小的服务来接收转移的负载,只需要保证相关用户负载被转移到负载较少的服务中去。结合前面举一个例子,假设一组服务的负载为{40,25,30,20,40},得出 Z 为4.1,概率为{0,0.32,0.24,0.44,0}。这意味着负载为最大负载值40的服务,不被自动平衡服务识别为可以接收转移负载的服务,剩下3个服务根据概率值来被选择为接收负载的服务。
假如上述的服务组中增加了一个用户,其负载变为{40,26,30,20,40},那么它的概率变为 {0,0.32,0.23,0.45,0}。这些服务的概率与之前的没有显著差异,所以不需要在每次增加新用户时都对服务的概率进行重新计算,只需要在服务组的Lmax和Lmin显著变化时对概率进行重新计算。
本实验在VMwareworkstation上进行,在VM上安装并运行Docker虚拟机。使用双核CPU和8GB内存,虚拟机的系统为Ubuntu16.04.2。将服务部署在Docker容器中,使用apt-get命令来安装实验中需要的软件。
为了观察本文算法的负载均衡效果,标准差是衡量负载均衡的一个流行度量,但是在有些情况下,2组负载数据的标准差σ是相同的,为了解决这一问题,将最大负载与平均负载的差除以平均负载作为衡量负载均衡的另一指标U,负载不平衡的概率为:
加入不平衡参数U 后的负载如表1所示。
这个标准由负载最大的服务来主导。假设有2个服务组,它们的平均负载都为10,并且它们的标准差也相等。很明显,负载最大值为20的服务组负载不平衡的概率大于负载最大值为15的服务组。前一个的负载不平衡率为1.0,而后一个为0.5。
使用ApacheJMeter作为本文的基准测试工具。ApacheJMeter是Apache为基准HTTP服务器提供的压力测试工具。它可以模拟多线程并发请求和测试服务器负载压力。使用Docker容器部署20个服务组来进行负载均衡测试。本文设计的实验将会通过同等时间长度内,发送1×103,5×103,10×103,50×103,100×1035个数量级的数据请求来观察在不同的负载情况下,本文算法的实际计算效率和负载均衡状况。
首先需要比较本文算法与传统一致性哈希算法和轮询算法的运行效率差异,轮询算法是一种常见的负载均衡算法,主要是将请求按顺序轮流分配到服务器上,其对比图如图3所示。
从实验的结果来看,本文基于动态权重的一致性哈希算法在各个并发量的情况下效果相对稳定,有较好的表现。因为传统一致性哈希算法没有添加虚拟节点进行优化,导致每次分配都需要遍历很长的距离,从而导致额外的开销增多,随着访问量的增加,处理的效率随之降低。而另外一组轮询算法因为是在整个微服务集群中按顺序选择服务,其在并发请求数量增加的情况下处理效果相对稳定,但如果集群中服务节点数量增加,会产生一些分配性能上的损失。
测试通过比较3种不同的算法来评估本文算法的切分服务。表2显示了3种算法的负载不平衡概率结果。
由表2所示,改进后的一致性哈希算法负载不平衡概率较低,是原有一致性哈希算法的31%。基于虚拟节点的一致性哈希算法的标准差和不平衡概率较低,明显小于传统一致性哈希算法和轮询算法的。这是因为传统一致性哈希算法中没有足够的服务来作为节点,用户的请求很可能集中访问某一节点导致负载倾斜,所以当节点数量不足时,只使用一致性哈希算法来进行节点划分,其结果是不理想的。而轮询算法是通过在服务集群的服务列表中按顺序分配请求,而微服务集群中的服务器存在性能上的差异,导致高性能的服务器负载低,而低性能的服务器负载过高。
测试由于动态加权的方法是在划分方法的基础上改进的,所以测试的方法与之前大致相同。区别是本文创建了10个虚拟用户,并设置了他们的访问时间和访问次数。使用ApacheJMeter对用户进行了多次重复实验,结果见表3,其中 Wavg为权重的平均值,σw 为权重的标准差。表3结果表明,该方法具有良好的负载均衡性能,其不仅可以均衡用户的访问数量,还可以使用户的负载水平达到一个相对的平衡。
测试首先重复上述步骤,然后通过自动平衡服务发送一个信号,使其对服务集群中的服务进行负载均衡,其结果如表4所示,其中 Before为集群中服务进行负载传递前的各项数值,After为进行负载传递后的各项数值。表4的结果表明,经过负载传递之后,服务集群中权重和用户数基本分配均等。此方法很大程度上解决了负载均衡问题。
随着大数据时代的到来,处理负载均衡问题已经成为服务集群的重要问题,一种有效的负载均衡方法决定着系统所能发挥的性能。本文针对分布式系统的负载均衡问题,对一致性哈希算法进行优化,提出一种基于动态权重的一致性哈希处理负载问题的策略。通过增加一层虚拟节点的哈希环来解决传统一致性哈希算法因为节点不足导致负载倾斜的问题;并提出了基于权重分配负载以及实现服务负载传递的方法。从实验结果来看,该方法有效地提高了系统的性能,降低了负载不平衡的概率,实现了服务集群中各服务的负载和用户访问的均衡。与传统的方法相比,负载均衡的效果得到了有效的提高。