【免费下载链接】brpc
brpc 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".
brpc 内置的/status页面是服务运维与排障的第一站,它以"服务/方法"为维度重新组织与/vars同源的 bvar 统计,集中展示每个 RPC 服务的请求量、错误、延时分位值、并发度等核心指标。读完本文,你将掌握/status上每个字段的精确含义与统计口径、HTML 与纯文本两种输出形态的差异、页面背后的源码实现链路(StatusService与MethodStatus),以及如何通过实现brpc::Describable为服务注入自定义状态描述。
/status 是什么:与 /vars 同源,按服务重组
brpc server 启动后会挂载一批内置 HTTP 服务(builtin services),/status就是其中之一。它展示的是服务进程内部的主要统计信息,数据来源与/vars完全同源(底层都是 bvar 计数器),区别在于组织方式:
/vars是一个扁平的 bvar 大列表,按变量名平铺展示全部计数器;/status则按注册的服务(service)与方法(method)重新分组,让运维人员能一眼看清"每个方法"的独立表现。
页面的渲染入口是内置的brpc::StatusService,其default_method位于 src/brpc/builtin/status_service.cpp。它首先输出服务器version,随后按顺序输出非服务错误数、连接数、并发上限、当前并发度,再遍历Server::_fullname_service_map中所有用户注册的服务,逐方法打印统计。
/status 页面上的典型结构: version: <server version> non_service_error: <N> connection_count: <N> max_concurrency: <N> | unlimited concurrency: <N> [服务完整名(含 proto 包名)] <自定义描述(若实现了 Describable)> 方法名 (请求类型) returns (响应类型) count / qps / error / eps / latency / latency_percentiles / latency_cdf / max_latency / concurrency / max_concurrency核心字段逐项详解
原文档对页面上各个字段给出了精确定义,下面逐项展开,并结合源码补充其统计口径与底层实现。
non_service_error:服务处理之外的错误
non_service_error表示在 service 处理代码之外产生的错误个数。判定规则是:当请求被路由到一个合法的 service 之后,后续发生的错误计为service_error;反之,在获取到合法 service 之前发生的错误都算作non_service_error,典型场景包括:
- 请求解析失败(协议解析层面的错误);
- service 名称不存在(路由不到任何服务);
- 请求并发度超过上限被拒绝。
需要特别澄清的两点(原文档明确强调):
- 服务处理过程中访问后端服务失败(如下游 RPC 超时、连接失败)属于 service 自己的错误,不算non_service_error;
- 即使服务成功写出 response、但 response 内容本身代表业务失败(比如返回了错误码),该错误也会被记入对应的 service,而不是 non_service_error。
从实现上看,该计数对应 Server 上的_nerror_bvar,在 src/brpc/builtin/status_service.cpp 中直接读取其get_value()输出;同时它在 src/brpc/server.cpp 中被expose_as(prefix, "error")暴露为/vars/<server_prefix>_error,因此在/vars里也能查到这个同源指标。当 non_service_error 持续增长时,应优先检查协议不匹配、路由配置、限流配置等服务外层因素。
connection_count:客户端连接数
connection_count是向该 server 发起请求的连接个数(即服务端视角的入站连接数),不包含server 作为客户端对外发起的连接——后者记录在/vars/rpc_channel_connection_count中(channel 是 brpc 的客户端对象)。
源码中该值由Server::GetStat累加各 Acceptor 上的ConnectionCount()得出(见 src/brpc/server.cpp),并通过bvar::PassiveStatus<int32_t>以connection_count为名暴露(src/brpc/server.cpp),页面读取的是同一计数器。注意:连接数并不等于并发请求数,一个连接上可并行/串行承载多个请求。
服务名与方法签名
- example.EchoService:服务的完整名称,包含 proto 文件中定义的 package 名。比如 proto 中
package example;且 service 名为EchoService,则完整名是example.EchoService。 - Echo (EchoRequest) returns (EchoResponse):方法的签名。一个服务可以包含多个方法,页面会逐个列出。在 HTML 页面上,请求类型与响应类型是可点击链接,点击后跳转到
/protobufs/<消息完整名>查看对应 protobuf 消息的结构体定义(字段、类型、编号等)。
源码遍历逻辑位于 src/brpc/builtin/status_service.cpp:对每个用户服务取其ServiceDescriptor(d->full_name())、遍历method_count()个方法,通过MethodDescriptor取得输入/输出类型完整名,并拼出/protobufs/链接;若方法配置了 HTTP URL,还会以@<http_url>的形式附带显示。
count / error:成功与失败请求数
- count:成功处理的请求总个数(累积值)。
- error:处理失败的请求总个数(累积值)。
从底层看,这两个量都来自每个方法对应的brpc::MethodStatus(定义在 src/brpc/details/method_status.h):count 实际取自bvar::LatencyRecorder的_count,error 取自_nerror_bvar。计数逻辑在MethodStatus::OnResponded(method_status.h):
inline void MethodStatus::OnResponded(int error_code, int64_t latency) { _nconcurrency.fetch_sub(1, butil::memory_order_relaxed); if (0 == error_code) { _latency_rec << latency; // 成功:计入延时分位统计 } else { _nerror_bvar << 1; // 失败:error 计数 +1 } ... }可见"成功/失败"的判定依据是Controller::ErrorCode()是否为 0(由 method_status.cpp 中的ConcurrencyRemover析构时回调)。error 对应的 bvar 以error为名暴露(_nerror_bvar.expose_as(prefix, "error")),同时存在一个eps(errors per second,每秒错误率)衍生指标。
latency / latency_percentiles / latency_cdf / max_latency:延时四件套
这是/status上信息量最大的一组指标,且HTML 与纯文本两种形态的统计窗口不同:
- HTML 页面:从右到左依次是过去60s / 60m / 24h / 30d四个窗口的数值(曲线图)。
- 纯文本输出:默认是最近10 秒窗口的平均值,窗口长度由-bvar_dump_interval控制。
-bvar_dump_interval在 src/bvar/variable.cpp 中定义:DEFINE_int32(bvar_dump_interval, 10, "Seconds between consecutive dump"),默认 10 秒,指 bvar 后台"每次 dump/汇总的间隔秒数",纯文本下所有瞬时统计(latency、max_latency、qps)都以它为窗口宽度。该 flag 在运行期不可热加载(源码中注册了 validator 但注释说明bvar_dump_interval is actually unreloadable)。
各指标含义:
| 指标 | 含义 |
|---|---|
| latency | 平均延时。HTML 下为右到左 60s/60m/24h/30d 四个窗口;纯文本下为最近一个 dump 间隔(默认 10s)内的平均延时 |
| latency_percentiles | 延时的80%、90%、99%、99.9%分位值,统计窗口默认 10 秒(受-bvar_dump_interval控制),HTML 下有历史曲线 |
| latency_cdf | 以 CDF(累积分布函数) 方式展示分位值,仅 HTML 可用 |
| max_latency | 最大延时。HTML 下为右到左 60s/60m/24h/30d 四个窗口;纯文本下为最近一个 dump 间隔内的最大值 |
分位值的默认档位在 src/bvar/latency_recorder.cpp 中由三个 gflags 控制:
-bvar_latency_p1=80 # 第一档分位值,默认 80% -bvar_latency_p2=90 # 第二档分位值,默认 90% -bvar_latency_p3=99 # 第三档分位值,默认 99%每档都被校验在(0, 100)开区间内(valid_percentile),且源码注释明确"修改这些 flag 不会改变已暴露 bvar 的名字,实际使用中应避免运行期重载"。99.9% 档位是固定值(_latency_999),不随上述 flag 变化。
值得一提的是:LatencyRecorder::expose()(src/bvar/latency_recorder.cpp)会按前缀暴露latency、max_latency、count、qps、latency_80/90/99(纯文本)、latency_999、latency_9999、latency_cdf(HTML)与latency_percentiles(HTML)等一组 bvar,这就是/status与/vars同源的直接证据——页面字段与 bvar 名一一对应。
qps:每秒请求数
qps(Queries Per Second)在 HTML 下同样是从右到左的 60s/60m/24h/30d 四个窗口;纯文本下是最近一个 dump 间隔(默认 10s)内的平均 QPS。底层来自LatencyRecorder的_qps(bvar::PerSecond衍生指标),读取的是latency窗口内的请求数与时间跨度之比(见LatencyRecorder::qps(),src/bvar/latency_recorder.cpp),实现上用浮点换算以避免溢出。
processing / concurrency:当前正在处理的请求数
processing(master 分支已改名为concurrency)表示正在被方法处理的请求个数。这是排查服务卡死最关键的指标:如果服务流量归零后该计数仍持续不为 0,server 大概率存在 bug,例如忘记调用done->Run()(回调未触发),或请求卡死在某个处理步骤上。
从源码看,该方法级并发数来自MethodStatus的原子计数器_nconcurrency(butil::atomic<int>,method_status.h):
- 请求到达时
MethodStatus::OnRequested中_nconcurrency.fetch_add(1, ...)(method_status.h); - 请求结束时
OnResponded中_nconcurrency.fetch_sub(1, ...)。
两个操作都使用memory_order_relaxed,仅用于观测统计、不参与同步。方法级concurrency通过_nconcurrency_bvar(PassiveStatus<int>,读取回调cast_int)以concurrency为名暴露(method_status.cpp)。
页面头部还输出两个服务级指标(见 status_service.cpp):
- max_concurrency:服务级并发上限,取自
ServerOptions::max_concurrency;若<= 0则显示unlimited(不限流); - concurrency:服务级当前并发数,来自
Server::Concurrency()(src/brpc/server.h),是_concurrency的原子读。
方法级同样有独立的max_concurrency(当该方法配置了ConcurrencyLimiter时输出,读取_max_concurrency_bvar)。
HTML 与纯文本:两种输出形态
/status会根据 HTTP 请求的 Accept 头/访问方式自动选择输出形态(UseHTML(cntl->http_request())判定),并设置对应的Content-Type:
- HTML(
text/html):带完整页面骨架(<!DOCTYPE html>)、tab 导航(PrintTabsBody)、flot 曲线占位符(class="flot-placeholder"),latency_percentiles / latency_cdf / qps / concurrency 等字段均渲染为可点击的动态曲线。支持?expand查询参数控制是否展开全部曲线(cntl->http_request().uri().GetQuery("expand"))。 - 纯文本(
text/plain):源码注释明确其格式刻意兼容public/configure的键值格式,便于脚本直接解析加载。此时分位值展开为独立的latency_50 / latency_90 / latency_99 / latency_999 / latency_9999五行(见MethodStatus::Describe的非 HTML 分支,method_status.cpp),且 99.9% 与 99.99% 档位只在纯文本下可见。可用curl直接拉取:
# 纯文本形态,每行一个 "key: value" curl http://<server_addr>/status # 只看某个服务的分位值(通过 /vars 定位同名 bvar) curl http://<server_addr>/vars/<server_prefix>_latency_percentiles需要说明:页面上的 latency/latency_percentiles/max_latency/qps 等字段在 HTML 下展示的是 60s/60m/24h/30d 多窗口曲线(对应 bvar 内部为可点击变量保存的历史采样值),而纯文本形态只反映当前 dump 窗口(默认 10s)内的值,两者统计口径不同、各有用途。
源码级原理:StatusService 与 MethodStatus 的分工
/status的生成可以拆成两条链路:
1. 页面骨架与字段排版 ——StatusService::default_method(src/brpc/builtin/status_service.cpp)
- 输出
version(server->version()); - 输出服务级指标:
non_service_error(server->_nerror_bvar)、connection_count(server->GetStat)、max_concurrency、concurrency(server->Concurrency()); - 遍历
_fullname_service_map,跳过非用户服务(!sp.is_user_service())与Tabbed类型服务(这类监控页自己的状态不重要,源码注释// Tabbed services are probably for monitoring); - 若服务实现了
Describable,先输出自定义描述; - 逐方法输出签名与
MethodStatus::Describe的结果; - 末尾追加可选的
BaiduMasterService、NsheadService、ThriftService(ENABLE_THRIFT_FRAMED_PROTOCOL编译开关下)及 RTMP 消息统计。
2. 方法级指标采集与格式化 ——MethodStatus(src/brpc/details/method_status.h、method_status.cpp)
每个服务方法对应一个MethodStatus实例,它在OnRequested(请求进入)与OnResponded(请求结束,携带error_code与耗时微秒)之间完成全部计数。Describe方法负责把内部 bvar 组织成可读输出(count/qps/error/eps/latency/latency_percentiles/latency_cdf/max_latency/concurrency[/max_concurrency]),HTML 模式下每个数值都包上<span id="value-<bvar_name>">与 flot 占位 div,供前端 JS 拉取曲线。
由于所有数值底层都是 bvar,你可以随时在/vars中按名字精确定位到同一份数据(例如<server_prefix>_connection_count、<server_prefix>_concurrency、<service_name>.<method_name>_latency_percentiles),实现页面与脚本监控的互相印证。
自定义描述:实现 brpc::Describable
用户可以通过让对应 Service 实现brpc::Describable接口,在/status的服务名下追加自定义描述文本。接口定义在 src/brpc/describable.h:
class Describable { public: virtual ~Describable() {} virtual void Describe(std::ostream& os, const DescribeOptions&) const { os << butil::class_name_str(*this); } };默认实现只输出类名;子类重写Describe即可输出任意状态。DescribeOptions(describable.h)包含两个成员:
verbose:是否输出详细信息(页面渲染时StatusService置为true);use_html:是否以 HTML 形式输出(跟随页面形态,status_service.cpp中按use_html透传)。
原文档给出的标准写法:
class MyService : public XXXService, public brpc::Describable { public: ... void Describe(std::ostream& os, const brpc::DescribeOptions& options) const { os << "my_status: blahblah"; } };StatusService在遍历服务时通过dynamic_cast<Describable*>(sp.service)探测服务是否实现该接口(status_service.cpp),命中则调用Describe,并把输出插在服务名([服务完整名])与方法列表之间;输出不以换行结尾时自动补\n。因此你可以在描述里输出业务自定义状态、版本号、缓存水位、后端依赖健康状况等,随/status一并暴露给监控系统。若实现的是可写状态(需要非 const 访问),可使用配套的NonConstDescribable接口。
基于 /status 的常见排障实践
- 服务卡死排查:流量归零后,观察各方法
concurrency(processing)是否归零。若某个方法持续不为 0,优先检查该方法的回调是否遗漏done->Run(),或是否存在死锁/阻塞调用——ConcurrencyRemover在析构时才回调OnResponded(method_status.cpp),回调不触发则计数永远挂住。 - 错误分类定位:
non_service_error上涨,问题在服务外层(协议解析、路由、限流拒绝);某个方法自己的error/eps上涨,问题在该服务处理链路(含对后端的访问失败)。 - 长尾延迟分析:平均
latency正常不代表 SLA 达标,要看latency_percentiles的 99%/99.9% 与latency_cdf曲线在 99%~100% 区间(长尾区)的表现;99.9% 与 99.99% 分位值在纯文本形态下以latency_999 / latency_9999单独给出。 - 容量观测:
qps多窗口曲线反映流量趋势,connection_count反映连接规模,max_concurrency/concurrency反映限流与积压情况,可结合 docs/en/vars.md 中的-bvar_dump_interval、分位值背景知识一起阅读。
说明:本文所有字段释义均以 docs/en/status.md 为准,源码引用来自上述 brpc 仓库文件;
/status页面为 brpc server 内置服务,运行任一 brpc server 后即可通过http://<server_addr>:<port>/status访问验证(HTML 形态可直接浏览器打开,纯文本形态可用curl获取)。
【免费下载链接】brpc
brpc 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".
相关推荐
brpc /status 服务监控页详解:字段含义、数据来源与 Describable 自定义状态输出
brpc /status 服务监控页详解:字段含义、数据来源与 Describable 自定义状态输出 /status 是 brpc 服务器内置的监控页面之一,
RPC框架后端微服务网络通信brpc 的 /status 页面:服务运行时状态监控指标全解析与自定义状态输出实战
brpc 的 /status 页面:服务运行时状态监控指标全解析与自定义状态输出实战 brpc 内置的 /status 页面是服务运行时最直接的健康与性能观测入
JupyterLab Status Bar 扩展:通用状态栏架构与自定义状态项开发指南
JupyterLab Status Bar 扩展:通用状态栏架构与自定义状态项开发指南 导读 JupyterLab 底部的状态栏(Status Bar)是一个常
前端后端数据科学开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考