零,需求的本源第一篇《一分钟理解负载均衡》给大家分享了互联网架构中反向代理层、站点层、服务层、数据层的常用负载均衡方式。第二篇《为什么lvs不能完全取代DNS轮询》给大家分享了互联网接入层负载均衡需要解决的问题和架构的演进。这两篇文章都强调了“负载均衡是指将请求/数据[均匀]分配给多个运行单元执行,负载均衡的关键是[均匀]”。但是,后端服务可能部署在硬件条件不同的服务器上:1)如果负载“平均”分配给标准配置服务器,则高配置服务器利用率不足;2)如果标准配置不同配置的服务器“平均”分担负载,低配置的服务器可能无法处理;能否根据异构服务器的处理能力,动态自适应地进行负载均衡和过载保护,是本文要探讨的问题。1、服务层的负载均衡通常是如何工作的?《一分钟了解负载均衡》中提到,服务层的负载均衡一般是通过服务连接池来实现的,调用者连接池会与多个下游服务建立。连接,每个请求“随机”获取一个连接,保证服务访问的均衡。《RPC-client实现细节》中提到,负载均衡、故障转移、超时处理等细节也是通过调用者连接池实现的。能否实现这个调用者的连接池,动态+自适应地根据服务的处理能力进行负载调度?二、服务的处理能力由“静态权重”标识调用者通过连接池组件访问下游服务,通常采用“随机”方式返回连接,保证下游服务访问的均衡。要打破这种随机性,最容易想到的办法就是为每个下游服务设置一个“权重”,代表该服务的处理能力,来调整访问每个服务的概率,例如:假设service-ip1,service-ip2,service-ip3的处理能力是一样的,可以设置weight1=1,weight2=1,weight3=1,这样三个服务连接被获取的概率分别是1/3,1/3,1/3分别,可以保证余额接入。假设service-ip1的处理能力是service-ip2和service-ip3的2倍,可以设置weight1=2,weight2=1,weight3=1,这样三个服务连接被获取到的概率为2/4,1/4,1/4,可以保证处理能力强的服务得到均等的流量,不至于造成资源浪费。使用nginx作为反向代理和负载均衡有类似的机制。该方案的优点是简单,可以快速实现异构服务器的负载均衡。缺点也很明显:这个权重是固定的,不能动态自适应调整,很多时候服务器的处理能力很难用一个固定的值来量化。3、使用“动态权重”来标识一个服务的处理能力问题:用什么来标识一个服务的处理能力?答:其实,一个服务能不能处理好,响应好不好,应该由调用者来决定。如果服务被调用,处理速度很快,处理能力跟得上;当调用服务时,处理超时,处理能力可能跟不上。动态权重设计1.使用动态权重来标识每个服务的处理能力。默认初始处理能力相同,即分配给每个服务的概率是相等的;2.每当一个服务成功处理了一个请求,就认为服务处理能力是足够的。体重动态+13。每当服务处理请求超时,就认为服务处理能力可能跟不上。weightdynamics-10(weight会下降得更快)4.为了方便weights的处理,可以将weights的范围限制在[0,100],设置weight的初始值为60。例子:假设service-ip1、service-ip2、service-ip3的动态权重初始值为weight1=weight2=weight3=60。一开始,请求分配给这三个服务的概率分别是60/180、60/180、60/180,即负载均衡。随着时间的推移,处理能力强的服务成功处理的请求越来越多,而处理能力弱的服务偶尔会超时。随着动态权重的增减,权重可能会变化为weight1=100,weight2=60,weight3=40,那么此时请求分配给这三个服务的概率为100/200,60/200,和40/200,即处理能力强的服务会分配更多的流量。4、过载保护问:什么是过载保护?图:没有过载保护的负载和处理能力图(会掉到最下面)答:互联网软件架构设计中所说的过载保护是指当系统负载超过一个服务时,处理能力,如果服务不进行自我保护,可能导致对外处理能力为0,无法自动恢复的现象。服务的过载保护是指即使系统负载超过了某个服务的处理能力,该服务也能保证提供稳定的有损服务。图解:带过载保护的负载及处理能力图(不会掉底)问题:如何实现过载保护?答:最简单的方法是在服务器端设置一个负载阈值,超过这个阈值的请求将被淹没并丢弃。这种方法不是特别优雅。5.如何借助“动态权重”实现过载保护动态权重是用来标识每个服务的处理能力的一个值,是RPC-client客户端连接池层面的东西。服务器端处理超时,客户端RPC-客户端连接池可以知道。这里只要执行一些策略,就可以减少“疑似过载”的服务器,而不是服务器“放弃请求”来实现过载保护。应该实现什么样的策略,比如:1.如果在某个服务连接上连续3次请求超时,也就是连续3次-10点,客户端可以认为服务端慢慢处理不了,我有为了给这个服务松一口气,所以我定了一个策略:在接下来的几个小时内,比如1秒(或者接下来的几个请求),请求不再分配给这个服务;2.如果某个服务的动态权重降为0(比如连续10次请求超时,中间断了3次还是超时),客户端可以认为服务端根本处理不了,而且不得不为服务喘口气,所以设置策略:在接下来的几个小时内,比如1分钟(为什么是1分钟,根据经验,此时服务一般是fullGC,而它大约需要1分钟恢复),请求不再分配给该服务;3.可以有更复杂的保护策略...这样不仅可以借助“动态权重”实现动态自适应异构服务器负载均衡,还可以在客户端层面更优雅的实现过载保护,而一个下游服务在即将无法响应的时候给他喘息的机会。需要注意的是:为防止客户端过载保护导致服务雪崩,如果“整体负载”已经超过了“服务集群”的处理能力,无论怎样中转请求,都不能被处理,必须通过丢弃请求来实现自我保护。六、总结1.服务负载均衡、故障转移、超时处理通常在RPC-client连接池层面实现2.异构服务器负载均衡,最简单的方式是静态权重法,缺点是不能自适应调整dynamically3.动态权重方式可以根据服务的处理能力动态分配负载,这需要在连接池层面进行微小的改动。4、过载保护是一种服务保证一定的处理能力,以在负载过高时保护自身的自救方式5、动态权重法,也可以作为服务的过载保护
