作者:刘泉禄
全体介绍
本文所说的“柔性服务”主要是指 consumer 端的负载均衡和 provider 端的限流两个功用。在之前的 Dubbo 版别中,负载均衡部分更多的考虑的是公平性原则,即 consumer 端尽或许相等的从 provider 中作出挑选,在某些情况下体现并不行理想。而限流部分只提供了静态的限流计划,需求用户对 provider 端设置静态的最大并发值,可是该值的合理选取对用户来讲并不容易。咱们针对这些存在的问题进行了改善。
负载均衡
在本来的 Dubbo 版别中,有五种负载均衡的计划供挑选,他们分别是 “Random” , “ShortestResponse” , “RoundRobin”,”LeastActive” 和 “ConsistentHash”。
其间除 “ShortestResponse” 和 “LeastActive” 外,其他的几种计划主要是考虑挑选时的公平性和安稳性。关于 “ShortestResponse” 来说,其规划目的是从一切备选的 provider 中挑选 response 时刻最短的以进步体系全体的吞吐量。可是存在两个问题:
-
在大多数的场景下,不同 provider 的 response 时长没有非常显着的区别,此时该算法会退化为随机挑选。
-
response 的时刻长短有时也并不能代表机器的吞吐才能。关于 “LeastActive” 来说,其以为应该将流量尽或许分配到当时并发处理使命较少的机器上。可是其相同存在和 “ShortestResponse” 相似的问题,即这并不能单独代表机器的吞吐才能。
根据以上分析,咱们提出了两种新的负载均衡算法。一种是相同根据公平性考虑的单纯 “P2C” 算法,另一种是根据自适应的办法 “adaptive”,其试图自适应的衡量 provider 端机器的吞吐才能,然后将流量尽或许分配到吞吐才能高的机器上,以进步体系全体的性能。
作用介绍
关于负载均衡部分的有效性试验在两个不同的情况下进行的,分别是提供端机器配置比较均衡和提供端机器配置差距较大的情况。
运用办法
运用办法与本来的负载均衡办法相同。只需求在 consumer 端将 “loadbalance” 设置为 “p2c” 或许 “adaptive” 即可。
代码结构
负载均衡部分的算法完成只需求在本来负载均衡结构内承继 LoadBalance 接口即可。
原理介绍
P2C 算法
Power of Two Choice 算法简单可是经典,主要思路如下:
-
关于每次调用,从可用的 provider 列表中做两次随机挑选,选出两个节点 providerA 和 providerB。
-
比较 providerA 和 providerB 两个节点,挑选其“当时正在处理的连接数”较小的那个节点。
adaptive 算法
代码的 github 地址 [ 1]
相关目标
- cpuLoad
cpuLoad = cpu一分钟平均负载 * 100 / 可用cpu数量。该目标在 provider 端机器取得,并经过 invocation 的 attachment 传递给 consumer 端。
- rt
rt 为一次 rpc 调用所用的时刻,单位为毫秒。
- timeout
timeout 为本次 rpc 调用超时剩下的时刻,单位为毫秒。
- weight
weight 是设置的服务权重。
- currentProviderTime
provider 端在核算 cpuLoad 时的时刻,单位是毫秒
- currentTime
currentTime 为最后一次核算 load 时的时刻,初始化为 currentProviderTime,单位是毫秒。
- multiple
multiple=(当时时刻 – currentTime)/timeout + 1
- lastLatency
- beta
滑润参数,默以为0.5
- ewma
lastLatency 的滑润值
lastLatency=beta*lastLatency+(1 – beta)*lastLatency
- inflight
inflight 为 consumer 端还未返回的恳求的数量。
inflight=consumerReq – consumerSuccess – errorReq
- load
关于备选后端机器x来说,若间隔上次被调用的时刻大于 2*timeout,则其 load 值为 0。
不然
load=CpuLoad*(sqrt(ewma) + 1)*(inflight + 1)/(((consumerSuccess / (consumerReq +1) )*weight)+1)
算法完成
依然是根据 P2C 算法。
-
从备选列表中做两次随机挑选,得到 providerA 和 providerB
-
比较 providerA 和 providerB 的 load 值,挑选较小的那个。
自适应限流
与负载均衡运行在 consumer 端不同的是,限流功用运行在 provider 端。其作用是约束 provider 端处理并发使命时的最大数量。从理论上讲,服务端机器的处理才能是存在上限的,关于一台服务端机器,当短时刻内出现很多的恳求调用时,会导致处理不及时的恳求积压,使机器过载。在这种情况下或许导致两个问题:
1.因为恳求积压,最终一切的恳求都有必要等待较长时刻才能被处理,从而使整个服务瘫痪。
2.服务端机器长时刻的过载或许有宕机的危险。因而,在或许存在过载危险时,回绝掉一部分恳求反而是更好的挑选。在之前的 Dubbo 版别中,限流是经过在 provider 端设置静态的最大并发值完成的。可是在服务数量多,拓扑杂乱且处理才能会动态改动的局面下,该值难以经过核算静态设置。
根据以上原因,咱们需求一种自适应的算法,其能够动态调整服务端机器的最大并发值,使其能够在保证机器不过载的前提下,尽或许多的处理接收到的恳求。
因而,咱们参考部分业界计划完成基础上,在 Dubbo 的结构内完成了两种自适应限流算法,分别是根据启发式滑润的 “HeuristicSmoothingFlowControl” 和根据窗口的 “AutoConcurrencyLimier”。
代码的 github 地址 [ 2]
作用介绍
自适应限流部分的有效性试验咱们在提供端机器配置尽或许大的情况下进行,而且为了凸显作用,在试验中咱们将单次恳求的杂乱度进步,将超时时刻尽或许设置的大,而且开启消费端的重试功用。
运用办法
要保证服务端存在多个节点,而且消费端开启重试战略的前提下,限流功用才能更好的发挥作用。设置办法与静态的最大并发值设置相似,只需在 provider 端将 “flowcontrol” 设置为 “autoConcurrencyLimier” 或许 “heuristicSmoothingFlowControl” 即可。
代码结构
-
FlowControlFilter:在 provider 端的 filter 负责根据限流算法的结果来对 provider 端进行限流功用。
-
FlowControl:根据 Dubbo 的 spi 完成的限流算法的接口。限流的具体完成算法需求承继自该接口并能够经过 Dubbo 的 spi 办法运用。
-
CpuUsage:周期性获取 cpu 的相关目标
-
HardwareMetricsCollector:获取硬件目标的相关办法
-
ServerMetricsCollector:根据滑动窗口的获取限流需求的目标的相关办法。比如 qps 等。
-
AutoConcurrencyLimier:自适应限流的具体完成算法。
-
HeuristicSmoothingFlowControl:自适应限流的具体完成办法。
原理介绍
HeuristicSmoothingFlowControl
相关目标
- alpha
alpha 为可承受的延时的上升幅度,默以为 0.3
- minLatency
在一个时刻窗口内的最小的 Latency 值。
- noLoadLatency
noLoadLatency 是单纯处理使命的延时,不包含排队时刻。这是服务端机器的固有特点,可是并不是一成不变的。在 HeuristicSmoothingFlowControl 算法中,咱们根据机器CPU的运用率来确认机器当时的 noLoadLatency。当机器的 CPU 运用率较低时,咱们以为 minLatency 便是 noLoadLatency。当 CPU 运用率适中时,咱们滑润的用 minLatency 来更新 noLoadLatency 的值。当 CPU 运用率较高时,noLoadLatency 的值不再改动。
- maxQPS
一个时刻窗口周期内的 QPS 的最大值。
- avgLatency
一个时刻窗口周期内的 Latency 的平均值,单位为毫秒。
- maxConcurrency
核算得到的当时服务提供端的最大并发值。
maxConcurrency=ceil(maxQPS*((2 + alpha)*noLoadLatency – avgLatency))
算法完成
当服务端收到一个恳求时,首先判别 CPU 的运用率是否超越 50%。假如没有超越 50%,则承受这个恳求进行处理。假如超越 50%,说明当时的负载较高,便从 HeuristicSmoothingFlowControl 算法中取得当时的 maxConcurrency 值。假如当时正在处理的恳求数量超越了 maxConcurrency,则回绝该恳求。
AutoConcurrencyLimier
相关目标
- MaxExploreRatio
默认设置为 0.3
- MinExploreRatio
默认设置为 0.06
- SampleWindowSizeMs
采样窗口的时长。默以为 1000 毫秒。
- MinSampleCount
采样窗口的最小恳求数量。默以为 40。
- MaxSampleCount
采样窗口的最大恳求数量。默以为 500。
- emaFactor
滑润处理参数。默以为 0.1。
- exploreRatio
探索率。初始设置为 MaxExploreRatio。若 avgLatency<=noLoadLatency*(1.0 + MinExploreRatio) 或许 qps>=maxQPS*(1.0 + MinExploreRatio)则 exploreRatio=min(MaxExploreRatio,exploreRatio+0.02)
不然
exploreRatio=max(MinExploreRatio,exploreRatio-0.02)
- maxQPS
窗口周期内 QPS 的最大值。
- noLoadLatency
- halfSampleIntervalMs
半采样区间。默以为 25000 毫秒。
- resetLatencyUs
下一次重置一切值的时刻戳,这儿的重置包含窗口内值和 noLoadLatency。单位是微秒。初始为 0.
- remeasureStartUs
下一次重置窗口的开始时刻。
- startSampleTimeUs
开始采样的时刻。单位为微秒。
- sampleCount
当时采样窗口内恳求的数量。
- totalSampleUs
采样窗口内一切恳求的 latency 的和。单位为微秒。
- totalReqCount
采样窗口时刻内一切恳求的数量和。注意区别 sampleCount。
- samplingTimeUs
采样当时恳求的时刻戳。单位为微秒。
- latency
当时恳求的 latency。
- qps
在该时刻窗口内的 qps 值。
- avgLatency
窗口内的平均 latency。
- maxConcurrency
上一个窗口核算得到当时周期的最大并发值。
- nextMaxConcurrency
当时窗口核算出的下一个周期的最大并发值。
Little’s Law
当服务处于安稳状况时:concurrency=latency*qps。这是自适应限流理论的基础。当恳求没有导致机器超载时,latency 根本安稳,qps 和 concurrency 处于线性关系。当短时刻内恳求数量过多,导致服务超载的时分,concurrency 会和latency一同上升,qps则会趋于安稳。
算法完成
AutoConcurrencyLimier 的算法运用进程和 HeuristicSmoothingFlowControl 相似。
完成与 HeuristicSmoothingFlowControl 的最大区别是 AutoConcurrencyLimier 是根据窗口的。每当窗口内积累了一定量的采样数据时,才利用窗口内的数据来更新得到 maxConcurrency。
其次,利用 exploreRatio 来对剩下的容量进行探索。
另外,每隔一段时刻都会主动缩小 max_concurrency 并持续一段时刻,以处理 noLoadLatency 上涨的情况。因为估计 noLoadLatency 时有必要先让服务处于低负载的状况,因而对 maxConcurrency 的缩小是难以避免的。
因为 max_concurrency
Dubbo 于上周上线了新版官网与文档,涵盖 Dubbo3 核心功用及特性,关于自适应负载均衡、自适应限流及更多计划的具体解说,请访问:dubbo.apache.org
相关链接
[1]代码的 github 地址
github.com/apache/dubb…
[2]代码的 github 地址
github.com/apache/dubb…