2021SC@SDUSC BRPC代码分析(六) —— bvar-IntRecorder、LatencyRecorder详解

2021SC@SDUSC


一、IntRecorder、LatencyRecorder类简介

        经过了五篇文章的讲解,bvar的主干部分类也算基本讲解完毕了,这篇文章再介绍一下一个基于bvar的实用工具Recorder计数器,这是一个统计类型的工具。在早些时候我们讲解过Reducer类和三种典型的Reducer,这是与之相似的另一种bvar,但与Reducer不同的是,Reducer用二元运算符把多个值合并为一个值,而这两种Recorder出于统计意义在实现时可能要保留每个值或进行更复杂的操作,并不是简单的对值做Op运算。在框架代码中一共实现了两类Recorder,下面将做出介绍,感兴趣的朋友可以与之前的Reducer作对照体验下这两个Recorder进行的操作。
bvar::IntRecorder:用于计算平均值。使用方法如下
IntRecorder latency;
latency << 1 << 3 << 5;
CHECK_EQ(3, latency.average());
bvar::LatencyRecorder:专用于计算latency(延迟)和qps的计数器。只需填入latency数据,就能获得latency / max_latency(获取最近窗口大小到秒的最大延迟) / qps(在最近的|window_size|秒内获得qps。“q”是指<<记录的) / count(获取记录的延迟总数量)。统计窗口是最后一个参数,不填为bvar_dump_interval(这里使用方法没填)。使用方法如下
LatencyRecorder write_latency(“table2_my_table_write”); // produces 4 variables:
// table2_my_table_write_latency
// table2_my_table_write_max_latency
// table2_my_table_write_qps
// table2_my_table_write_count
// In your write function
write_latency << the_latency_of_write;
下文将从IntRecorder(位于/bvar/utils/recorder.h)开始具体分析,两个Recorder有类似之处,将在后面简单分析LatencyRecorder的代码。

二、代码分析

首先是一个Stat包含数据处理的结构体,里面有两个变量,一个是sum记录总和,另一个是num记录变量数量。给出了整型和浮点两种类型的计算平均值方法,要注意特别处理一下除数num=0的情况。然后在Stat内部重载了+,+=,-,-=操作符,用来实现Stat的加减。
在这里插入图片描述
在这里插入图片描述
然后我们来看IntRecorder计数器类,它继承自Variable基类,这个基类在第一篇分析文章中讲解过,里面有expose,descirbe等方法,bvar::Reducer也继承了它。开头的三个变量是为了进行格式压缩,unsignedint64是64位无符号位数,利用这一变量的特性,人为设置一个SUM_BIT_WIDTH,得到一个MAX_SUM_PER_THREAD总和的最大值,MAX_NUM_PER_THREAD总数量的最大值。后续在判断溢出等操作我们在看它的应用,利用位运算实现了非常便捷且高效的判断,非常巧妙。
在这里插入图片描述
一个属性value_type定义数据类型。
还有一个重要属性sampler_type,是上篇文章讲解的Sampler的衍生类ReducerSampler,传入自定义的Op和InvOp。
在这里插入图片描述
看下它的构造函数和析构函数,提供含前缀和不含前缀的expose曝光全局注册方法。析构则将这个variable隐藏,如果有sampler就销毁。
在这里插入图片描述
方法有get_sampler为当前计数器获得一个采样,将其schedule全局注册以实现周期性地调用take_sample()采样。
在这里插入图片描述
下面是一些私有方法,这是上面提到的格式压缩,内部给出解压缩获得真实值的方法。
在这里插入图片描述
上面提到的压缩方式如下,按照SUM_BIT_WIDTH=44来看,uint64类型的n前20位表示num,后44位表示sum,这样给出的最大值如(1ul << SUM_BIT_WIDTH) - 1,得到就是对应位数的99999…。上面的方法将一个unint64还原。
在这里插入图片描述
_extend_sign_bit:如果符号位为1,则用1填充所有前(64位和+1)位用来表示完整的64位负数。
_get_complement:将补入的对象转换为对应位数的无符号整数。
_compress:将num和sum压缩为一个uint64类型的数。
在这里插入图片描述
_will_overflow判断两数相加是否会溢出,有上溢出和下溢出。
在这里插入图片描述
接下来要重载<<运算符了,首先截断打入sample过大和过小的情况,然后处理一下name不为空等情况。
在这里插入图片描述
利用前面文章提到过的agent概念,首先get_or_create一个agent用于存储,先取到uint64的压缩值n,然后判断是否超过最大数量或溢出,如果发生这些错误就说明存储已经到达极限,让这个agent提交并清空。否则就更新值继续即可。
在这里插入图片描述
IntRecorder就介绍完了,我们接下来简单看一下LatencyRecorder类,两者实际上很相似。只是它是针对特定值进行的采集和计算。
Percentile是百分位数的计算。一样继承自Variable基类
首先是CDF类(累积分布函数(Cumulative Distribution Function),又叫分布函数,是概率密度函数的积分,能完整描述一个实随机变量X的概率分布。),它被下面的LatencyRecorderBase使用,所以LatencyRecorder也是继承自Variable。先解释下CDF为了干什么。
Percentile是百分位数的计算。x%分位值(percentile)是指把一段时间内的N个统计值排序,排在第N * x%位的值。比如一段时间内有1000个值,先从小到大排序,排在第500位(1000 * 50%)的值是50%分位值(即中位数),排在第990位的是99%分位值(1000 * 99%),排在第999位的是99.9%分位值。分位值能比平均值更准确的刻画数值的分布,对理解系统行为有重要意义。工业级应用的SLA(服务级别协议)一般在99.97%以上(此为百度对二级系统的要求,一级是99.99%以上),一些系统即使平均值不错,但不佳的长尾区域也会明显拉低和打破SLA。分位值能帮助分析长尾区域。
下图是分位值的CDF,横轴是比例(排序位置/总数),纵轴是对应的分位值。比如横轴=50%处对应的纵轴值便是50%分位值。如果系统要求的性能指标是"99.9%的请求在xx毫秒内完成“,那么你就得看下99.9%那儿的值。

img
如果把CDF的纵轴分为很多小段,对每个小段计算两端对应的横轴值之差,并把这个差作为新的横轴,那么我们便绘制了PDF(概率密度函数(Probability Density Function))曲线,就像顺时针旋转了90度的正态分布那样。但中位数的密度往往很高,在PDF中很醒目,这使得边上的长尾很扁而不易查看,所以大部分系统测量结果选择CDF曲线而不是PDF曲线。

可用一些简单规则衡量CDF曲线好坏:

  • 越平越好。一条水平线是最理想的,这意味着所有的数值都相等,没有任何等待,拥塞,停顿。当然这是不可能的。
  • 99%和100%间的面积越小越好:99%之后是长尾的聚集地,对大部分系统的SLA有重要影响。

一条缓慢上升且长尾区域面积不大的CDF便是不错的曲线。

在这里插入图片描述
这是LatencyRecorder的基类,里面包含了要采集记录的内容,这些值大多都是要以Window窗类型来计算得出的。要注意的是还有一些PassiveStatus类型值,PassiveStatus按需显示值。在一些场合中,我们无法set_value或不知道以何种频率set_value,更适合的方式也许是当需要显示时才打印。_latency_p1、p2等值就是前百分之多少的位置的值是什么。
在这里插入图片描述
在latency_recorder.cpp中看到这三个百分位数的默认赋值是前80%,90%和99%。
在这里插入图片描述
然后是在这个计数器类中重载的<<,它传入的是latency延迟值,会对这三个地方产生影响,所以要打入这三个地方,比如_max_latency上面看到是Maxer的bvar类型,传入这个值他就自己做大小比较判断。
在这里插入图片描述
剩下的大部分值的get方法,都是这样调用内部属性和类的方法简单操作,和IntRecorder都类似,不再赘述。
在这里插入图片描述


总结

以上就是今天介绍的全部内容,本文进行了bvar内IntRecorder、LatencyRecorder两个实用采集器的功能说明和详细源码分析,之后的博客会继续进行其他代码的分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值