问题
“服务提供方所在的应用A有100台机器,某个调用方需要申请该应用的某个服务1000 QPS的调用量,根据经验,如果A应用的单机限流值配置成10,应该会有比较多的额度内的流量被限制住,如果配置的太高,又会有稳定性风险,限流值应该配置成多少合适呢?”
分析
把限流的问题抽象一下:若单机QPS平均值为m,求实际落到该机器的QPS 不超过k的概率P(x<=k),知道了这个概率分布情况,我们就能知道限流值n设置为多少合适,或者能相对量化的分析所配置的限流的作用效果。
为了便于分析,我们不妨假设,在不扩缩容的某个时间段,流量落到某台机器的概率是稳定的,而且我们知道每次流量落到哪台机器是独立事件,那么在单位时间内,落在某台机器的流量x可以认为是服从泊松分布的。
结论
故实际落到该机器的QPS x<=k 的概率为:
n三k
m
P(X<-K)二
xe-m
n!
nE0
使用该公式,代入不同的k和m,可以得到单机QPS平均值m取不同值时,实际打到某台机器的流量x不超过k的概率值(精确到百分比小数点后5位)。
m=1 | m=5 | m=10 | m=20 | ||||
k | x<k的概率 | k | x<k的概率 | k | x<k的概率 | k | x<k的概率 |
0 | 36.78794% | 0 | 0.67379% | 0 | 0.00454% | 0 | 0.00000% |
1 | 73.57589% | 1 | 4.04277% | 1 | 0.04994% | 1 | 0.00000% |
2 | 91.96986% | 2 | 12.46520% | 2 | 0.27694% | 2 | 0.00005% |
3 | 98.10118% | 3 | 26.50259% | 3 | 1.03361% | 3 | 0.00032% |
4 | 99.63402% | 4 | 44.04933% | 4 | 2.92527% | 4 | 0.00169% |
5 | 99.94058% | 5 | 61.59607% | 5 | 6.70860% | 5 | 0.00719% |
6 | 99.99168% | 6 | 76.21835% | 6 | 13.01414% | 6 | 0.02551% |
7 | 99.99898% | 7 | 86.66283% | 7 | 22.02206% | 7 | 0.07786% |
8 | 99.99989% | 8 | 93.19064% | 8 | 33.28197% | 8 | 0.20873% |
9 | 99.99999% | 9 | 96.81719% | 9 | 45.79297% | 9 | 0.49954% |
10 | 1 | 10 | 98.63047% | 10 | 58.30398% | 10 | 1.08117% |
11 | 1 | 11 | 99.45469% | 11 | 69.67761% | 11 | 2.13868% |
12 | 1 | 12 | 99.79811% | 12 | 79.15565% | 12 | 3.90120% |
13 | 1 | 13 | 99.93020% | 13 | 86.44644% | 13 | 6.61276% |
14 | 1 | 14 | 99.97737% | 14 | 91.65415% | 14 | 10.48643% |
15 | 1 | 15 | 99.99310% | 15 | 95.12596% | 15 | 15.65131% |
16 | 1 | 16 | 99.99801% | 16 | 97.29584% | 16 | 22.10742% |
17 | 1 | 17 | 99.99946% | 17 | 98.57224% | 17 | 29.70284% |
18 | 1 | 18 | 99.99986% | 18 | 99.28135% | 18 | 38.14219% |
19 | 1 | 19 | 99.99997% | 19 | 99.65457% | 19 | 47.02573% |
20 | 1 | 20 | 99.99999% | 20 | 99.84117% | 20 | 55.90926% |
21 | 1 | 21 | 100.00000% | 21 | 99.93003% | 21 | 64.36976% |
22 | 1 | 22 | 100.00000% | 22 | 99.97043% | 22 | 72.06113% |
23 | 1 | 23 | 100.00000% | 23 | 99.98799% | 23 | 78.74928% |
24 | 1 | 24 | 100.00000% | 24 | 99.99531% | 24 | 84.32274% |
25 | 1 | 25 | 1 | 25 | 0.99998232 | 25 | 88.78150% |
26 | 1 | 26 | 1 | 26 | 0.99999358 | 26 | 92.21132% |
27 | 1 | 27 | 1 | 27 | 0.99999775 | 27 | 94.75193% |
28 | 1 | 28 | 1 | 28 | 0.99999924 | 28 | 96.56665% |
29 | 1 | 29 | 1 | 29 | 0.99999975 | 29 | 97.81818% |
30 | 1 | 30 | 1 | 30 | 0.99999992 | 30 | 98.65253% |
31 | 1 | 31 | 1 | 31 | 0.99999998 | 31 | 99.19082% |
32 | 1 | 32 | 1 | 32 | 0.99999999 | 32 | 99.52726% |
33 | 1 | 33 | 1 | 33 | 1 | 33 | 99.73116% |
34 | 1 | 34 | 1 | 34 | 1 | 34 | 99.85110% |
35 | 1 | 35 | 1 | 35 | 1 | 35 | 99.91963% |
36 | 1 | 36 | 1 | 36 | 1 | 36 | 99.95771% |
37 | 1 | 37 | 1 | 37 | 1 | 37 | 99.97829% |
38 | 1 | 38 | 1 | 38 | 1 | 38 | 99.98912% |
39 | 1 | 39 | 1 | 39 | 1 | 39 | 99.99468% |
通过该表格可以发现,如果要保证99.9%的流量不被限流:
当单机QPS平均值为1的时候,我们的限流值要设置为不小于5.
当单机QPS平均值为5的时候,我们的限流值要设置为不小于12.
当单机QPS平均值为10的时候,我们的限流值要设置为不小于21.
当单机QPS平均值为20的时候,我们的限流值要设置为不小于35.
如果需要看更详细的概率分布,可以用下面这段简单的工具代码来生成,需要注意的是m调大的时候,实际QPS的上限MAX_K要相应的调大。
package com.cainiao.hyena; import java.math.BigDecimal; import java.math.RoundingMode; /** * [Poisson分布概率计算工具] * * @author jianping.pjp created on 2020/12/8 下午11:29 * Copyright 2020 (C) <Alibaba Global> */ public class PoissonTest { //在指定QPS平均值的前提下,我们猜测实际最大能打到的QPS,可根据实际跑出的结果来调整,这个值是和平均值正相关的 private static final int MAX_K = 40; public static void main(String[] args) { int m = 10; BigDecimal p = new BigDecimal(0); for (int k = 0; k < MAX_K; k++) { BigDecimal x = p2(m, k); p = p.add(x); System.out.println(k + "," + p.setScale(10, RoundingMode.DOWN).doubleValue()); } } private static BigDecimal p2(int m, int k) { BigDecimal a = new BigDecimal(1); if (k == 0) { return new BigDecimal(Math.exp(-m)); } BigDecimal r = new BigDecimal(-m).divide(new BigDecimal(k), 100, RoundingMode.DOWN); BigDecimal b = new BigDecimal(Math.exp(r.doubleValue())); for (int n = 1; n <= k; n++) { BigDecimal an = new BigDecimal(m).divide(new BigDecimal(n), 100, RoundingMode.DOWN).multiply(b); a = a.multiply(an); } return a; } }
验证
通过下面验QPS模拟生成工具代码可以验证我们的猜测,以下代码对平均值10 QPS做了100万次模拟试验,实验的结果符合我们的猜测。
package com.cainiao.hyena; import java.util.HashMap; import java.util.Map; import java.util.Random; /** * [模拟QPS实现验证] * * @author jianping.pjp created on 2020/12/10 下午1:07 * Copyright 2020 (C) <Alibaba Global> */ public class PoissonVerification { //在指定QPS平均值的前提下,我们猜测实际最大能打到的QPS,可根据实际跑出的结果来调整,这个值是和平均值正相关的 private final static int MAX_K = 40; public static void main(String [] args){ Random r = new Random(); //每次实验打到指定机器的实际QPS Map<Integer,Integer> map = new HashMap<>(); //模拟QPS平均值 int qps = 10; //实现次数 int experimentsTimes = 1000000; for(int i=0;i<qps*experimentsTimes;i++){ int n = r.nextInt(experimentsTimes); Integer c= map.get(n); if(c==null){ c = 0; } c++; map.put(n,c); } for(int k=0;k<MAX_K;k++){ //实际QPS不超过K的实验次数 int lk = 0; for(int i=0;i<experimentsTimes;i++){ Integer c = map.get(i); if(null ==c || c<=k){ lk++; } } double ratio = (double)lk/experimentsTimes; System.out.println(k+","+ratio); } } }
m=10 | ||
k | x<k的概率 | 试验结果 |
0 | 0.00454% | 0.00510% |
1 | 0.04994% | 0.05090% |
2 | 0.27694% | 0.28200% |
3 | 1.03361% | 1.02100% |
4 | 2.92527% | 2.91860% |
5 | 6.70860% | 6.70020% |
6 | 13.01414% | 12.99690% |
7 | 22.02206% | 21.95120% |
8 | 33.28197% | 33.25910% |
9 | 45.79297% | 45.80050% |
10 | 58.30398% | 58.31790% |
11 | 69.67761% | 69.67210% |
12 | 79.15565% | 79.15300% |
13 | 86.44644% | 86.48280% |
14 | 91.65415% | 91.68780% |
15 | 95.12596% | 95.15310% |
16 | 97.29584% | 97.30320% |
17 | 98.57224% | 98.56930% |
18 | 99.28135% | 99.28800% |
19 | 99.65457% | 99.66060% |
20 | 99.84117% | 99.84590% |
21 | 99.93003% | 99.92790% |
22 | 99.97043% | 99.97050% |
23 | 99.98799% | 99.98880% |
24 | 99.99531% | 99.99570% |
25 | 0.99998232 | 99.99870% |
26 | 0.99999358 | 99.99930% |
27 | 0.99999775 | 99.99990% |
28 | 0.99999924 | 1 |
29 | 0.99999975 | 1 |
30 | 0.99999992 | 1 |
31 | 0.99999998 | 1 |
32 | 0.99999999 | 1 |
33 | 1 | 1 |
相关资料
http://www.ruanyifeng.com/blog/2015/06/poisson-distribution.html