首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
brpc 服务端性能问题排查实战指南:从 worker 线程与 CPU 指标到 rpcz 逐段定位
📅 2026/9/14 6:09:07
✍️ 爱科研究院
👁 阅读 3,247
brpc 服务端性能问题排查实战指南从 worker 线程与 CPU 指标到 rpcz 逐段定位【免费下载链接】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/brpcbrpc 服务在线上出现高延迟、低吞吐或负载不均时通常可以从其内置服务/vars、/flags、/rpcz出发沿着查线程 → 查 CPU → 判断瓶颈类型 → 逐层缩小范围的路径快速定位。本文基于 docs/en/server_debugging.md 的完整方法论结合 brpc 仓库源码bthread 调度、bvar 指标实现与示例程序展开讲解读完你将掌握如何用 bvar 指标判断 worker 线程与 CPU 是否吃紧、如何区分 CPU 密集型与 IO 密集型瓶颈、如何用 rpcz 与 TRACEPRINTF 逐段定位耗时函数以及如何用 bvar::LatencyRecorder 监控高频调用路径。背景排查所依赖的三个内置服务brpc 服务启动后会默认挂载一组内置服务页面性能排查主要用到三个/vars展示进程内全部 bvar 指标支持按名称过滤、按分号拼接多个指标并?expand展开查看/flags展示并支持动态修改 gflags 参数可改项右侧带有(R)标记/rpcz展示近期请求的调用链时间线span可查看请求在每个阶段的耗时。下文所有排查步骤都围绕这三个页面展开。关于这些页面的通用说明可参见 内置服务文档指标体系的完整介绍见 bvar 文档。第一步检查 worker 线程数是否吃紧两个关键指标指标含义/vars/bthread_worker_count进程内 worker 线程的总数/vars/bthread_worker_usage当前正在被使用的 worker 线程数每秒均值当usage 与 count 数值接近时说明 worker 线程已被排满即线程不够用。从源码看这两个指标由 bthread 的调度中枢TaskControl暴露bthread_worker_count是每个 tag 一个的bvar::Adderint64_t定义于 src/bthread/task_control.cpp、src/bthread/task_control.cppbthread_worker_usage是基于累计 worker 运行时间换算的每秒均值bvar::PerSecondPassiveStatusdouble在 src/bthread/task_control.cpp 中 expose。查看方式与判读直接在浏览器地址栏把/vars/bthread_worker_count;bthread_worker_usage?expand拼在服务 URL 后面即可同时看到两幅实时曲线。例如下图共有 24 个 worker 线程其中 23.93 个正在被使用说明所有线程都在满负荷干活、线程数不足而下图只有 2.36 个线程在使用中显然线程是充足的第二步检查 CPU 使用率是否吃紧两个关键指标指标含义/vars/system_core_count机器可用的 CPU 核数/vars/process_cpu_usage进程实际使用的 CPU 核数等价于占用了几颗核每秒均值当usage 与 count 接近时说明 CPU 已被打满CPU 成为瓶颈。这两个指标由 bvar 的默认变量模块提供实现位于 src/bvar/default_variables.cppsystem_core_count通过sysconf(_SC_NPROCESSORS_ONLN)取得在线核数src/bvar/default_variables.cppprocess_cpu_usage是每秒窗口的PassiveStatus其值等于(ru_stime ru_utime) / uptime即系统态与用户态 CPU 时间之和占实时时间的比例src/bvar/default_variables.cpp。由于该指标是占用核数而非百分比所以它可以直接与system_core_count对比。判读示例下图中核数为 24而进程实际使用了 20.9 颗核说明 CPU 是瓶颈下图中仅使用了 2.06 颗核CPU 非常充足第三步判断瓶颈类型CPU-bound 还是 IO-bound把前两步的两个指标放在一起对比即可判断程序的瓶颈性质process_cpu_usage与bthread_worker_usage接近说明是CPU-bound计算密集程序worker 线程大部分时间在算数process_cpu_usage明显小于bthread_worker_usage说明是IO-boundIO 密集程序worker 线程大部分时间处于阻塞状态等待下游、等锁、等 IO 等。进一步地可以用下面这个公式估算阻塞时间占比阻塞时间比例 ≈ 1 - process_cpu_usage / bthread_worker_usage例如process_cpu_usage 2.4、bthread_worker_usage 18.5则 worker 线程大约把 87.1% 的时间花在了阻塞上。这个比例越大说明程序越卡在等待上而不是在计算上。3.1 定位 CPU-bound 问题CPU 打满的可能原因有两类单机处理性能差或者流量在上游机器间分布不均。排查时先排除后者。排除上游流量分布不均的嫌疑在多个机器的/vars页面里查看 qps 是否与预期一致。例如在 vars 页面输入qps过滤也可以在命令行直接用 curl 查看$ curl brpc.baidu.com:8765/vars/*qps* bthread_creation_qps : 95 rpc_server_8765_example_echo_service_echo_qps : 57如果确认不同机器的流量分布确实不均且难以治理可以考虑使用 Limit concurrency限制并发 来削峰保护避免单机被打爆。提升单机性能CPU profiler若分布正常问题就集中在单机处理能力上。请使用 CPU profiler 分析程序热点用数据指导优化方向。一般来说CPU-bound 程序都能分析出几个明显的大热点函数针对它们优化即可见效。3.2 定位 IO-bound 问题IO-bound 的常见诱因worker 线程数量不足访问下游服务的客户端不支持 bthread导致同步等待时把整个 worker 挂起且延迟过长内部锁、IO 等导致的阻塞。如果阻塞不可避免请考虑改为异步处理模式。下面按排除法逐步定位。排除worker 线程不足的嫌疑动态调整 bthread_concurrency如果怀疑线程不够可以直接在 /flags 页面动态调大 worker 线程数。切换到 /flags 页面点击bthread_concurrency右侧的(R)输入新的线程数并确认回到 /flags 页面即可看到bthread_concurrency已变成新值关于线程数的设置范围bthread_concurrency是全局的 gflags 参数说明见 flags 文档进程内所有 Server 与 Channel 共享同一个线程池服务端也可通过ServerOptions.num_threads设置实际生效的 worker 数是所有num_threads与bthread_concurrency中的最大值详见 server 文档。但要注意单纯调大线程数未必有用。如果 worker 线程大部分时间阻塞在访问下游上真正的瓶颈在下游后端——此时调大线程数只会让每条线程的阻塞时间变得更长指标上 worker 依然满负荷。例如本例中调大线程数后 worker 仍然全部处于忙碌状态这说明瓶颈是阻塞本身而不是线程数需要继续向下排查。排除锁竞争的嫌疑contention profiler如果程序被某把锁阻塞外在表现同样会呈现 IO-bound 特征。请先用 contention profiler锁竞争分析器 检查锁的竞争情况确认是否存在高竞争的锁热点。使用 rpcz 逐段定位耗时rpcz 能展示近期所有请求以及请求在每个处理阶段花费的时间微秒点击某个 span 链接可以看到 RPC 的开始时间、各阶段耗时与结束时间下面是一个服务端被严重阻塞的典型例子从收到请求到真正开始运行处理逻辑花了20ms说明服务端没有足够的 worker 线程及时接手任务。用 TRACEPRINTF 向 span 注入自定义日志默认 span 信息较少我们可以在程序里补充。brpc 提供了TRACEPRINTF宏把日志直接打进对应请求的 rpcz 时间流中。该宏定义于 src/brpc/traceprintf.h其实现是先检查CanAnnotateSpan()若当前请求启用了 rpcz 则调用AnnotateSpan()写入并且会自动拼接[文件:行号]前缀若 rpcz 未开启宏参数不会求值因此不要在其中放入有副作用的表达式。参考示例 example/rpcz_echo_c/server.cpp在代码中这样使用#include brpc/traceprintf.h void* RunThreadFunc(void*) { TRACEPRINTF(RunThreadFunc %lu, bthread_self()); ... } // 在服务回调中 class EchoServiceImpl : public EchoService { virtual void Echo(...) { ... TRACEPRINTF(Handle request); ... } };重新运行程序后查看对应 span里面就会包含我们通过 TRACEPRINTF 注入的内容例如下图中在运行到第一条 TRACEPRINTF 之前用户回调已经运行了 2051ms假设这符合预期紧接着的foobar()却花费了 8036ms——而它本应快速返回。于是问题范围被进一步缩小到了foobar()内部重复加 TRACEPRINTF → 重跑 → 查看 span → 缩小范围这个循环直到定位到真正出问题的函数。使用 bvar 监控高频或低开销函数TRACEPRINTF主要适合调用次数少的函数如果某个函数被调用非常频繁或者函数本身开销很小每次都向 rpcz 打日志就不合适了。此时应该改用bvar。bvar 是一个多线程计数库可以极低的开销记录用户传入的值相比打日志几乎不影响程序行为。例如要监控foobar()的耗时分布可以这样写#include butil/time.h #include bvar/bvar.h bvar::LatencyRecorder g_foobar_latency(foobar); ... void search() { ... butil::Timer tm; tm.start(); foobar(); tm.stop(); g_foobar_latency tm.u_elapsed(); ... }bvar::LatencyRecorder是一个复合变量喂入延迟数据后会同时产出多个指标详见 bvar C 接口文档例如foobar_qps、foobar_latency、foobar_max_latency、foobar_count等。重跑程序后在 /vars 页面的搜索框输入foobar即可看到这组指标点击某个 bvar 还能看到动态曲线例如点击 cdf根据延迟分布可以推断函数的整体行为对大多数请求表现如何、长尾long tail请求表现如何。继续在子函数里添加更多 bvar、对比不同函数的分布曲线最终就能锁定问题源头。纯客户端场景先开一个 dummy server如果程序只用到了 brpc 的 client甚至完全没用 brpc但还想借助 /vars、/rpcz 等内置服务观察进程内的 bvar 指标需要先启动一个dummy server空服务。具体做法若程序已使用 brpc client在程序运行目录下创建一个名为dummy_server.port的文件里面写入一个端口号如 8888进程启动时就会在该端口拉起一个 dummy server通过它的内置服务即可看到进程内全部 bvar若程序完全没用 brpc则需要手动调用brpc::StartDummyServerAt(8888)启动详见 dummy server 文档。排查流程小结看线程/vars/bthread_worker_count与bthread_worker_usage接近 → 线程吃紧看 CPU/vars/system_core_count与process_cpu_usage接近 → CPU 打满定类型process_cpu_usage与bthread_worker_usage对比判断 CPU-bound 还是 IO-boundCPU-bound先查上游 qps 分布是否均匀再上 CPU profiler 找热点IO-bound依次排除线程不足动态调bthread_concurrency、锁竞争contention profiler再用 rpcz TRACEPRINTF逐段缩小范围高频路径改用bvar::LatencyRecorder记录耗时分布对比各函数 CDF 定位源头。这套先看指标定方向、再用链路与探针精确定位的方法配合 brpc 内置的 bvar、rpcz 与各类 profiler即可在不重启、不加外部监控的前提下完成大部分线上性能问题的排查与定位。【免费下载链接】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),仅供参考
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/9/14 6:09:07
跳频通信系统MATLAB仿真:从m序列到时频图绘制全解析
2026/9/14 6:04:06
低压无刷水泵驱动芯片选型实战指南
2026/9/14 6:04:06
STM32嵌入式开发转向VS Code的工程实践指南
2026/9/14 6:49:09
Vitest 快照系统内核:@vitest/snapshot 的架构设计与实现详解
2026/9/14 6:49:09
OpenClaw v2.4.1在Windows 11上的AI网关部署与优化
2026/9/14 6:49:09
AI PPT工具评测与选型指南
2026/9/14 6:49:09
脉冲神经网络顶刊论文研究现状与高效检索方法
2026/9/14 6:49:09
GWO优化SVR模型:工业预测中的超参数调优实践
2026/9/14 6:44:08
Apache POI替代EasyExcel的实战重估与性能优化
2026/9/14 0:03:40
KCF目标跟踪算法与OTB工程实现:毕业设计实战解析
2026/9/14 0:03:40
Megatron-LM 推理实战指南:基于 Megatron Core 高层 API 的离线推理与 OpenAI 兼容服务
2026/9/14 0:03:40
语音情感识别实战:Keras实现LSTM、CNN、SVM与MLP多模型对比
2026/9/13 0:01:25
拯救者Y7000黑屏故障排查与维修实战指南
2026/9/14 2:50:57
AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验
2026/9/13 0:01:25
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化