bvar是多线程环境下的计数器类库,方便记录和查看用户程序中的各类数值,它利用了thread local存储避免了cache bouncing,相比UbMonitor几乎不会给程序增加性能开销,也快于竞争频繁的原子操作。brpc集成了bvar,/vars可查看所有曝光的bvar,/vars/VARNAME可查阅某个bvar,增加计数器的方法请查看bvar。brpc大量使用了bvar提供统计数值,当你需要在多线程环境中计数并展现时,应该第一时间想到bvar。但bvar不能代替所有的计数器,它的本质是把写时的竞争转移到了读:读得合并所有写过的线程中的数据,而不可避免地变慢了。当你读写都很频繁并得基于数值做一些逻辑判断时,你不应该用bvar。
/vars : 列出所有的bvar
/vars/NAME:查询名字为NAME的bvar
/vars/NAME1,NAME2,NAME3:查询名字为NAME1或NAME2或NAME3的bvar
/vars/foo*,b$r:查询名字与某一统配符匹配的bvar,注意用$代替?匹配单个字符,因为?在url中有特殊含义。
以下动画演示了如何使用过滤功能。你可以把包含过滤表达式的url复制粘贴给他人,他们点开后将看到你看到的内容。
1.0.123.31011及之后的版本加入了一个搜索框加快了寻找特定bvar的速度,在这个搜索框你只需键入bvar名称的一部分,框架将补上*进行模糊查找。不同的名称间可以逗号、分号或空格分隔。
你也可以在命令行中访问vars:
$ curl brpc.baidu.com:8765/vars/bthread*
bthread_creation_count : 125134
bthread_creation_latency : 3
bthread_creation_latency_50 : 3
bthread_creation_latency_90 : 5
bthread_creation_latency_99 : 7
bthread_creation_latency_999 : 12
bthread_creation_latency_9999 : 12
bthread_creation_latency_cdf : "click to view"
bthread_creation_latency_percentiles : "[3,5,7,12]"
bthread_creation_max_latency : 7
bthread_creation_qps : 100
bthread_group_status : "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "
bthread_num_workers : 24
bthread_worker_usage : 1.01056
点击大部分数值型的bvar会显示其历史趋势。每个可点击的bvar记录了过去60秒,60分钟,24小时,30天总计174个值。当有1000个可点击bvar时大约会占1M内存。
x%分位值(percentile)是指把一段时间内的N个统计值排序,排在第N * x%位的值就是x%分位值。比如一段时间内有1000个值,排在第500位(1000 * 50%)的值是50%分位值(即中位数),排在第990位的是99%分位值(1000 * 99%),排在第999位的是99.9%分位值。分位值能比平均值更准确的刻画数值分布,对衡量系统SLA有重要意义。对于最常见的延时统计,平均值很难反映出实质性的内容,99.9%分位值往往更加关键,它决定了系统能做什么。
分位值可以绘制为CDF曲线和按时间变化时间。
上图是CDF曲线。纵轴是延时。横轴是小于纵轴数值的数据比例。很明显地,这个图就是由从10%到99.99%的所有分位值组成。比如横轴=50%处对应的纵轴值便是50%分位值。那为什么要叫它CDF?CDF是Cumulative Distribution Function的缩写。当我们选定一个纵轴值x时,对应横轴的含义是"数值 <= x的比例”,如果数值是来自随机采样,那么含义即为“数值 <= x的概率”,这不就是概率的定义么?CDF的导数是概率密度函数,换句话说如果我们把CDF的纵轴分为很多小段,对每个小段计算两端对应的横轴值之差,并把这个差作为新的横轴,那么我们便绘制了PDF曲线,就像(横着的)正态分布,泊松分布那样。但密度会放大差距,中位数的密度往往很高,在PDF中很醒目,这使得边上的长尾相对很扁而不易查看,所以大部分系统测试结果选择CDF曲线而不是PDF曲线。
可以用一些简单规则衡量CDF曲线好坏:
- 越平越好。一条水平线是最理想的,这意味着所有的数值都相等,没有任何等待,拥塞,停顿。当然这是不可能的。
- 99%之后越窄越好:99%之后是长尾的聚集地,对大部分系统的SLA有重要影响,越少越好。如果存储系统给出的性能指标是"99.9%的读请求在xx毫秒内完成“,那么你就得看下99.9%那儿的值;如果检索系统给出的性能指标是”99.99%的请求在xx毫秒内返回“,那么你得关注99.99%分位值。
一条真实的好CDF曲线的特征是”斜率很小,尾部很窄“。
上图是按时间变化曲线。包含了4条曲线,横轴是时间,纵轴从上到下分别对应99.9%,99%,90%,50%分位值。颜色从上到下也越来越浅(从橘红到土黄)。滑动鼠标可以阅读对应数据点的值,上图中显示是”39秒种前的99%分位值是330微秒”。这幅图中不包含99.99%的曲线,因为99.99%分位值常明显大于99.9%及以下的分位值,画在一起的话会使得其他曲线变得很”矮“,难以辨认。你可以点击以"_latency_9999"结尾的bvar独立查看99.99%曲线,当然,你也可以独立查看50%,90%,99%,99.9%等曲线。按时间变化曲线可以看到分位值的变化趋势,对分析系统的性能变化很实用。
brpc的服务都会自动统计延时分布,用户不用自己加了。如下图所示:
你可以用bvar::LatencyRecorder统计非brpc服务的延时,这么做(更具体的使用方法请查看bvar-c++):
#include <bvar/bvar.h>
...
bvar::LatencyRecorder g_latency_recorder("client"); // expose this recorder
...
void foo() {
...
g_latency_recorder << my_latency;
...
}
如果这个程序使用了brpc server,那么你应该已经可以在/vars看到client_latency, client_latency_cdf等变量,点击便可查看动态曲线。如下图所示:
如果这个程序只是一个brpc client或根本没有使用brpc,并且你也想看到动态曲线,看这里。