恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

brpc bvar 完全指南:多线程计数器库的原理、使用与监控导出

  • 首页
  • 资讯中心
  • /
  • brpc bvar 完全指南:多线程计数器库的原理、使用与监控导出

相关资讯

快速上手 RemoveWindowsAI:备份与还原安全网完整指南 2026/9/13 19:22:26
context-mode 强制路由规则解析:在 Kiro 上守护 AI 编码 Agent 的上下文窗口 2026/9/13 19:22:26
MAS微软激活脚本完整指南:4种Windows/Office激活方式一次讲清,附避坑细节 2026/9/13 19:22:26

最新资讯

cua-auto 跨平台 GUI 自动化库实战指南:pyautogui 风格的鼠标、键盘、屏幕、窗口、剪贴板与 Shell/PTY 操作
Data Manager API Java 客户端与工具库安装指南:从 Maven 依赖到本地发布完整实践
BERT原理与微调实战:从动态语义表示到NLP项目落地
Text-to-CAD:从自然语言到可制造三维模型的AI辅助设计实战指南
Lithe-IDEA:面向Spring Boot的极简Java开发环境
技术团队高效远程协作的四大支柱体系

今日推荐

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化
Flutter应用改名全指南:从Android到iOS的配置与工具实践

本周热门

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化
Flutter应用改名全指南:从Android到iOS的配置与工具实践

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

brpc bvar 完全指南:多线程计数器库的原理、使用与监控导出

发布时间:2026/9/13 19:22:26
brpc bvar 完全指南:多线程计数器库的原理、使用与监控导出 brpc bvar 完全指南多线程计数器库的原理、使用与监控导出【免费下载链接】brpcbrpc is an Industrial-grade RPC framework using C Language, which is often used in high performance system such as Search, Storage, Machine learning, Advertisement, Recommendation etc. brpc means better RPC.项目地址: https://gitcode.com/GitHub_Trending/brpc/brpcbvar 是 brpc 内置的多线程环境计数器类库通过 thread local 存储把写竞争转移到读端让高频写入几乎零开销。本文基于 brpc 官方文档docs/cn/bvar.md为核心骨架结合源码src/bvar与配套文档bvar_c.md、vars.md深入讲解其设计原理、新增计数器的方法、内置指标的含义以及 dump 落盘、监控系统接入与 Prometheus 导出/brpc_metrics的完整实战方案读完即可在 brpc 服务中无顾虑地使用 bvar 监控系统。bvar 是什么为多线程计数而生的高性能计数器bvar 是 brpc工业级 C RPC 框架自带的计数器类库支持单维度 bvar和多维度 mbvar方便记录和查看用户程序中的各类数值。它利用了thread local 存储减少了 cache bouncing缓存行颠簸相比百度内部的旧计数器库 UbMonitor 几乎不会给程序增加性能开销也快于竞争频繁的原子操作。brpc 集成了 bvar通过/vars可查看所有曝光的 bvar通过/vars/VARNAME可查阅某个 bvar。brpc 大量使用了 bvar 提供统计数值因此当你需要在多线程环境中计数并展现时应该第一时间想到 bvar。但 bvar 不能代替所有的计数器它的本质是把写时的竞争转移到了读——读得合并所有写过的线程中的数据而不可避免地变慢了。当你读写都很频繁或需要基于最新值做一些逻辑判断时你不应该用 bvar。设计原理把写竞争转移到读端要理解 bvar 的原理需要先理解 Cacheline缓存行这一节现代 CPU 为了以低价格获得高性能大量使用了多级 cache如常见的 L1/L2 每核心独有、L3 所有核心共享。当一个核心写自己的 L1 cache 是极快的约 4 cycles、~2ns但当多个核心同时访问同一个 cacheline 时CPU 必须完成复杂的缓存一致性同步竞争激烈时一次fetch_add可能耗费数百纳秒。bvar 的核心思路正是文档中提到的计数器例子当很多线程都在累加一个计数器时每个线程只累加私有的变量而不参与全局竞争在读取时累加所有线程的私有变量。这样写操作只触碰本线程的 thread local 变量几乎不产生 cacheline 同步开销极小读操作需要合并所有线程的私有数据比之前慢多了但由于这类计数器的读多为低频的记录和展现如监控展示慢点无所谓极小的写开销使得用户可以无顾虑地使用 bvar 监控系统这正是设计 bvar 的目的。在源码中这一机制由detail::AgentCombiner实现见 src/bvar/detail/combiner.h 的引用关系实际入口在 src/bvar/reducer.hReducer把各线程 agent 的值按运算符合并读时遍历所有线程私有数据求和。性能对比bvar vs 原子变量 vs UbMonitor下图是 bvar 和原子变量、静态 UbMonitor、动态 UbMonitor 在被多个线程同时使用时的开销。可以看到bvar 的耗时基本和线程数无关一直保持在极低的水平约 20 纳秒而动态 UbMonitor 在 24 核时每次累加的耗时达 7 微秒这意味着使用 300 次 bvar 的开销才抵得上使用一次动态 UbMonitor 变量。bvar 类型总览与快速上手bvar 分为多个具体的类常用类型及其语义如下详细用法见单维度 bvar 文档类型说明bvar::AdderT计数器默认 0varname N相当于varname Nbvar::MaxerT求最大值默认std::numeric_limitsT::min()varname N相当于varname max(varname, N)bvar::MinerT求最小值默认std::numeric_limitsT::max()varname N相当于varname min(varname, N)bvar::IntRecorder求自使用以来的平均值。注意这里的定语不是一段时间内一般要通过 Window 衍生出时间窗口内的平均值bvar::WindowVAR获得某个 bvar 在一段时间内的累加值衍生于已存在的 bvar会自动更新bvar::PerSecondVAR获得某个 bvar 在一段时间内平均每秒的累加值也是自动更新的衍生变量bvar::WindowExT获得某个 bvar 在一段时间内的累加值不依赖其他 bvar需要给它发送数据bvar::PerSecondExT获得某个 bvar 在一段时间内平均每秒的累加值不依赖其他 bvar需要给它发送数据bvar::LatencyRecorder专用于记录延时和 qps 的变量。输入延时平均延时/最大延时/qps/总次数就都有了bvar::StatusT记录和显示一个值拥有额外的 set_value 函数bvar::PassiveStatus按需显示值。无法 set_value 或不知以何种频率 set_value 时传入打印回调函数实现按需打印bvar::GFlag将重要的 gflags 公开为 bvar以便监控它们一个典型的快速示例#include bvar/bvar.h namespace foo { namespace bar { // bvar::AdderT用于累加下面定义了一个统计read error总数的Adder。 bvar::Adderint g_read_error; // 把bvar::Window套在其他bvar上就可以获得时间窗口内的值。 bvar::Windowbvar::Adderint g_read_error_minute(foo_bar, read_error, g_read_error, 60); // ^ ^ ^ // 前缀 监控项名称 60秒,忽略则为10秒 // bvar::LatencyRecorder是一个复合变量可以统计总量、qps、平均延时延时分位值最大延时。 bvar::LatencyRecorder g_write_latency(foo_bar, write); // ^ ^ // 前缀 监控项别加latencyLatencyRecorder包含多个bvar它们会加上各自的后缀比如write_qps, write_latency等等。 // 定义一个统计已推入task个数的变量。 bvar::Adderint g_task_pushed(foo_bar, task_pushed); // 把bvar::PerSecond套在其他bvar上可以获得时间窗口内*平均每秒*的值这里是每秒内推入task的个数。 bvar::PerSecondbvar::Adderint g_task_pushed_second(foo_bar, task_pushed_second, g_task_pushed); // ^ ^ // 和Window不同PerSecond会除以时间窗口的大小. 时间窗口是最后一个参数这里没填就是默认10秒。 } // bar } // foo在应用的地方// 碰到read error foo::bar::g_read_error 1; // write_latency是23ms foo::bar::g_write_latency 23; // 推入了1个task foo::bar::g_task_pushed 1;注意Window和PerSecond都是衍生变量会自动更新你不用给它们推值。bvar 也可以作为成员变量或局部变量使用。新增 bvar命名、曝光与线程安全增加 C bvar 的具体方法请看快速介绍。这里补充几个关键实践约束确认变量名是全局唯一的否则会曝光失败如果-bvar_abort_on_same_name为 true程序会直接 abort默认 false重名时打印 FATAL 日志并返回 -1。程序中有来自各种模块不同的 bvar为避免重名建议如此命名模块_类名_指标。模块一般是程序名可加产品线缩写如 inf_ds、ecom_retrbs类名一般是类名或函数名如 storage_manager、file_transfer、rank_stage1指标一般是 count、qps、latency 这类。bvar 会做名字归一化无论你打入的是foo::BarNum、foo.bar.num、foo bar num还是foo-bar-num最后都是foo_bar_num。指标后缀约定个数以_count为后缀如 request_count每秒个数以_second为后缀如 request_second、process_inblocks_second不要写成_count_second或_per_second每分钟个数以_minute为后缀如 request_minute。如果需要使用定义在另一个文件中的计数器需要在头文件中声明对应的变量namespace foo { namespace bar { // 注意g_read_error_minute和g_task_pushed_second都是衍生的bvar会自动更新不要声明。 extern bvar::Adderint g_read_error; extern bvar::LatencyRecorder g_write_latency; extern bvar::Adderint g_task_pushed; } // bar } // foo不要跨文件定义全局 Window 或 PerSecond——不同编译单元中全局变量的初始化顺序是未定义的在 foo.cpp 中定义Adderint foo_count、在 foo_qps.cpp 中定义PerSecondAdderint foo_qps(foo_count)是错误做法。关于线程安全bvar 是线程兼容的可以在不同线程里操作不同的 bvar比如同时 expose/hide 不同的 bvar是安全的但除了读写接口bvar 的其他函数都是线程不安全的——不能在多个线程中同时 expose 或 hide 同一个 bvar这很可能导致程序 crash。这些约束同样写在基类 src/bvar/variable.h 的注释中。曝光expose机制用户以默认参数建立 bvar 时它并未注册到任何全局结构中此时 bvar 纯粹是一个更快的计数器。通过expose或expose_as函数把 bvar 注册到全局表中即可被list_exposed、count_exposed、describe_exposed、find_exposed等查询并出现在/vars中。brpc 内置的 bvarbvar 默认统计了进程、系统的一些变量以process_、system_等开头例如process_context_switches_involuntary_second : 14 process_context_switches_voluntary_second : 15760 process_cpu_usage : 0.428 process_cpu_usage_system : 0.142 process_cpu_usage_user : 0.286 process_disk_read_bytes_second : 0 process_disk_write_bytes_second : 260902 process_faults_major : 256 process_faults_minor_second : 14 process_memory_resident : 392744960 system_core_count : 12 system_loadavg_15m : 0.040 system_loadavg_1m : 0.000 system_loadavg_5m : 0.020还有 brpc 内部的各类计数器bthread_switch_second : 20422 bthread_timer_scheduled_second : 4 bthread_timer_triggered_second : 4 bthread_timer_usage : 2.64987e-05 bthread_worker_count : 13 bthread_worker_usage : 1.33733 bvar_collector_dump_second : 0 bvar_collector_dump_thread_usage : 0.000307385 bvar_collector_grab_second : 0 bvar_collector_grab_thread_usage : 1.9699e-05 bvar_collector_pending_samples : 0 bvar_dump_interval : 10 bvar_revision : 34975 bvar_sampler_collector_usage : 0.00106495 iobuf_block_count : 89 iobuf_block_count_hit_tls_threshold : 0 iobuf_block_memory : 729088 iobuf_newbigview_second : 10可以看到命名规范的实际落地bthread_switch_second模块bthread指标每秒切换次数、iobuf_block_count模块iobuf类名block指标count等。监控 bvar开启 dump 导出到文件打开 bvar 的 dump 功能可以把所有 bvar 导出到文件格式为每行一对名字:值。有两种开启方式用 gflags 解析输入参数在程序启动时加入-bvar_dump在 brpc 中也可通过 /flags 服务在启动后动态修改#include gflags/gflags.h ... int main(int argc, char* argv[]) { google::ParseCommandLineFlags(argc, argv, true/*表示把识别的参数从argc/argv中删除*/); ... }不想用 gflags 解析参数、希望直接在程序中默认打开#include gflags/gflags.h ... int main(int argc, char* argv[]) { if (google::SetCommandLineOption(bvar_dump, true).empty()) { LOG(FATAL) Fail to enable bvar dump; } ... }dump 功能由如下 gflags 控制名称默认值作用bvar_dumpfalseCreate a background thread dumping all bvar periodically, all bvar_dump_* flags are not effective when this flag is offbvar_dump_excludeDump bvar excluded from these wildcards(separated by comma), empty means no exclusionbvar_dump_filemonitor/bvar.app.dataDump bvar into this filebvar_dump_includeDump bvar matching these wildcards(separated by comma), empty means including allbvar_dump_interval10Seconds between consecutive dumpbvar_dump_prefixappEvery dumped name starts with this prefixbvar_dump_tabscheck the codeDump bvar into different tabs according to the filters (separated by semicolon), format: *(tab_namewildcards)当bvar_dump_file不为空时程序会启动一个后台导出线程以bvar_dump_interval指定的间隔更新bvar_dump_file其中包含了被bvar_dump_include匹配且不被bvar_dump_exclude匹配的所有 bvar。下图是 gflags 界面上各 dump 参数的配置示例打开 dump 功能后应检查 monitor/ 目录下是否有数据比如$ ls monitor/ bvar.echo_client.data bvar.echo_server.data $ tail -5 monitor/bvar.echo_client.data process_swaps : 0 process_time_real : 2580.157680 process_time_system : 0.380942 process_time_user : 0.741887 process_username : gejun例如配置了 include/exclude 过滤后导出文件形如$ cat bvar.echo_server.data rpc_server_8002_builtin_service_count : 20 rpc_server_8002_connection_count : 1 rpc_server_8002_nshead_service_adaptor : brpc::policy::NovaServiceAdaptor rpc_server_8002_service_count : 1 rpc_server_8002_start_time : 2015/07/24-21:08:03 rpc_server_8002_uptime_ms : 14740954像iobuf_block_count : 8被bvar_dump_include过滤了rpc_server_8002_error : 0则被bvar_dump_exclude排除了。每次导出都会覆盖之前的文件这与普通 log 添加在后面是不同的需要注意采集节奏。如果你的程序没有使用 brpc、仍需要动态修改 gflag可以调用google::SetCommandLineOption()但请勿直接设置 FLAGS_bvar_dump_file / FLAGS_bvar_dump_include / FLAGS_bvar_dump_exclude一方面这些 gflag 类型都是 std::string直接覆盖是线程不安全的另一方面不会触发 validator检查正确性的回调也就不会启动后台导出线程。汇聚到监控系统监控系统应定期搜集每台单机导出的数据并把它们汇总到一起。以百度内部的 noah 为例bvar 定义的变量会出现在 noah 的指标项中用户可勾选并查看历史曲线导出到 Prometheus/brpc_metrics除 dump 到本地文件外bvar 还内置了对 Prometheus 的原生支持。将 Prometheus 的抓取 url 地址的路径设置为/brpc_metrics即可例如 brpc server 跑在本机的 8080 端口则抓取 url 配置为127.0.0.1:8080/brpc_metrics。从源码看该路径由 Prometheus 内置服务实现见 src/brpc/builtin/prometheus_metrics_service.cppPrometheusMetricsService::default_method设置Content-Type: text/plain后调用DumpPrometheusMetricsToIOBuf其中通过bvar::Variable::dump_exposed(dumper, nullptr)把全部已曝光 bvar 以 Prometheus 文本格式输出若bvar_max_dump_multi_dimension_metric_number 0还会通过bvar::MVariableBase::dump_exposed一并导出多维 mbvar。延时类指标会输出为 Prometheus summary 格式包含quantile标签如 0.5、0.9、0.99、0.999、0.9999、avg以及_sum、_count系列。配合 vars 服务你还可以在浏览器中直接访问/vars查看所有曝光 bvar、用通配符过滤如/vars/foo*,b$r用$代替?匹配单个字符因为?是 URL 保留字符、点击数值型 bvar 查看历史趋势与分位值曲线让 bvar 的监控链路从采集—存储—展示形成完整闭环。小结bvar 是 brpc 为多线程计数场景量身打造的高性能计数器库它以 thread local 存储把写竞争转移为读时的合并开销换来近乎恒定的纳秒级写性能配合_count/_second/_minute命名规范与Adder、Maxer、Window、LatencyRecorder等丰富的计数器原语可以无顾虑地在业务代码中埋点。通过-bvar_dump落盘、/vars在线查询、/brpc_metrics对接 Prometheus一套从进程内到监控大盘的指标体系即可快速搭建完成。深入源码可继续阅读 src/bvar/window.hWindow/PerSecond 采样实现、src/bvar/latency_recorder.h延时统计组合变量与多维度 mbvar 文档。【免费下载链接】brpcbrpc is an Industrial-grade RPC framework using C Language, which is often used in high performance system such as Search, Storage, Machine learning, Advertisement, Recommendation etc. brpc means better RPC.项目地址: https://gitcode.com/GitHub_Trending/brpc/brpc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号