总述
95值,一种常见的计费方式,本意是排除一些特殊点以一个较为合理的方式计费(应该是国外有这种计费方式,我们也跟着有了)。现在通过合理使用5%的点,以节约成本。
常见的就是将单个计费带宽分成多个计费带宽,使得多个的95值之和小于单独总计费。
方式也很简单,先由第一条线路跑满前5%的点,再由第二条线路跑满接下来的5%的点就行。结果会比总的95值小。但实际情况由于有端口上限的存在还有保底的存在,分开来不一定比合起来少。下面会有例子说明。
写在前面的话,我当前的逻辑都是 数据都在已知情况下才能获取最优解,否则没法获得,没法知道最高的前5%的点就没法合理调度。
实际的情况远比本文的复杂,请以实际情况为准,本文所述仅提供一种思路,不一定正确。
问题的转换
95值就是一组数据按高到低排序,去掉前5%的数据后的最大值。
可以等价为,一组降序数据,去掉前n个点后的最大值。
一组数据分成m组,只有看前m*n+1个点就行了
解释,每组可以消n个点,总共就可以消m*n,
接下来保证满足第m*n+1 的点位,之后的点都小于该点位,肯定都满足就不用考虑
要这么认为95值就是最大值,但总数量中可以有5%的点超过这个95值。
如果分成两条线,每条都可以白漂5%的点,相当于白漂总线的10%的点,此时计费值为总线的90值,当然这是理想情况,实际情况比较复杂。
双线案例
只免费一个高点
可以看到分成2条线后,比之前少了1G
现实是如果有上限的存在就会变成这样
线路A打满前5%的点,B的95值要达到8才能满足
同理B打满时,A要达到7才行,
但由于A95+B95=15<16,所以A95+B95至少要为16才行,分解后的计费值为16.
(注意由于A先负责打满,B要填充的带宽要比 B打满时A填充的带宽要大,所以A95<B95)
计费值=MAX((A95+B95,P90))
A95+B95<P90时,可以有调整的空间
端口不必打满10G,只要打满9.5G就行了
这样分配也行
但下面这种情况就不行
这里A95+B95=15>14=P90 ,计费值就是15
满足公式: 计费值=MAX((A95+B95,P90))
总结如下
公式也是有的
1:PM+B95>=P100
2:A95+PM>=P95
3:A95+B95>=P90
计费值=MAX((A95+B95,P95))
求解(在数学上这么做是错的)
A95=(@2+@3-@1)/2
设S=P90+P95+P100
A95=(P95+P90-P100)/2=(S-P1002)/2
B95=(P90+P100-P95)/2=(S-P952)/2
PM=(P95+P100-P90)/2=(S-P90*2)/2
注意:这里有个要求PM必须小于端口支持的最大带宽
数据一
输入数据:18,17,16
线路0 检查带宽:17 Gb/s 对应95值: 7.5 Gb/s
线路1 检查带宽:16 Gb/s 对应95值: 8.5 Gb/s
端口带宽要满足9.5 Gb/s
由于端口有0.5G的冗余
满足 a95+b95=16,7<=a95,b95<=9 这个条件就行
数据二
输入数据:18,17,14
线路0 检查带宽:17 Gb/s 对应95值: 6.5 Gb/s
线路1 检查带宽:14 Gb/s 对应95值: 7.5 Gb/s
端口带宽要满足10.5 Gb/s
由于端口需求高出0.5G,所以求出的95值都要加上0.5
只能 a95=7,b95=8 这种分流方案
三线案例
改算法也适用分成任意多个线路
如分成3条线,就要看前4个点
3个未知数,3个等式还是能求出最优95值得
PM+B95+C95>=P100
A95+PM+C95>=P95
A95+B95+PM>=P90
A95+B95+C95>=P85
类似的设S=P100+P95+P90+P85
A95=(S-P1003)/3
B95=(S-P953)/3
C95=(S-P903)/3
PM=(S-P853)/3
这里我们可以推出一个通项公式
要分为n条线路,需要n+1个点(p0=P100,p1=P95…)(下标0~n)
设S为这n+1个点的和
i从0开始
第i个95=(S-Pi*n)/n
当i=n时求得就是端口最大值
计费值=MAX((A95+B95+C95,P95))
上面例子A95+B95+C95=9.5
A95=1.5,B95=2.5,C95=5.5
最优值
输入数据:18,17,14,13
线路0 检查带宽:17 Gb/s 对应95值: 2.667 Gb/s
线路1 检查带宽:14 Gb/s 对应95值: 3.667 Gb/s
线路2 检查带宽:13 Gb/s 对应95值: 6.667 Gb/s
端口带宽要满足7.667 Gb/s
此时线路最大值只要7.67
不能满足第4个点,所以计费值为13,但比当条线17这个计费值要小。
95值跟上面的关联
将数据从大到小分成20个区间,每个区间取最大值,第二区间的最大值就是95值,剩下的就是跟上面的一样算。20个区间就是20个数,这样问题就简单了。
现实情况
上面例子基本可以推出,分的线越多,计费值越小。举个现实的例子,分20条线,每个都只跑免费的1.5天,那么每条线的95就都是0了。运营商肯定不会让你这么玩的,一般会有保底,并且每个端口都有上限,全跑到一个口是不现实的,也没那么多口给你开。
客户按95计费的话,没有上限这一限制,但我们却要满足客户的最大带宽,如果跑到50G带宽,你这边必须要有5个端口,如果跑到100G带宽,你这边必须要有10个端口才能满足。就意味着客户平时可以只跑50G,晚高峰就跑1小时100G,客户多找几家,这100G基本就被白嫖了。但这边为了满足100G必须要开100G的口
分多线计费难点
1由于不知道未来点的情况,就无法将点精确的放在第一区间,还是第二区间,导致数值偏大,甚是超过单线95.
2流量划分不会那么精准,肯定比计算出来的值偏大
当a95+b95>p90时要严格按照区间跑
如图,P100,P97就是第一区间,P95,P93就是第二区间
如果P97使用线路B跑满,线路A的计费值就变成7,7+8>6+8,计费值就高了
所以区间跑错会拉高计费值。
当a95+b95<p90时,第一第二区间可以串着跑,各自只跑一个区间的点数就行。
当前比较好的就是通过历史数据进行调用。实际情况远比这复杂,如果趋势发生突变,反而会适得其反,这点要注意。
计算公式
$datainfo="18,17,16";
echo "输入数据:${datainfo}<br>";
$datas=explode(",", $datainfo);
$num=count($datas);
$sum=array_sum($datas);
$pos=0;
while($pos<$num){
$flux=($sum-$datas[$pos]*($num-1))/($num-1);
if($pos+1<$num){
echo "线路${pos} 检查带宽:${datas[$pos+1]} Gb/s 对应95值: ". round($flux,3)." Gb/s<br>";
}else{
echo "端口带宽要满足". round($flux,3)." Gb/s<br>";
}
$pos++;
}