date
related_level
slug
type
relate_date
summary
status
tags
category
last_updated
Jan 12, 2026 10:07 AM
是否已更新
orginal_page
是否推荐
prometheus_client 多进程模式:通过共享文件(PROMETHEUS_MULTIPROC_DIR) 聚合指标
- 背景
- Prometheus 客户端库假定采用线程模型,其中指标在工作进程之间共享
- Python 通常使用进程而不是线程来处理大型工作负载
将 prometheus_client 置于多进程模式会带来以下限制
- 注册表无法像往常一样使用,所有已实例化的指标都会被导出
- 将指标注册到注册表中供
MultiProcessCollector稍后使用,可能导致导出重复指标
- 自定义收集器无法正常工作
Gauge不能使用set_function方法
Gauge不能使用pid标签
Info类和Enum类不能使用
Exemplar类不能使用
- 不支持移除和清除标签
- pushgateway 不能使用
prometheus_client 实现多进程模式涉及以下步骤
部署层面:设置环境变量 PROMETHEUS_MULTIPROC_DIR
- 必须将
PROMETHEUS_MULTIPROC_DIR环境变量设置为prometheus_client可用于存储指标的目录 - 此目录必须在进程/Gunicorn 运行之间清空,建议每次在启动前清空
- 该环境变量应该通过启动 shell 脚本设置,而不是直接从 Python 设置
- 若在 Python 中
os.environ设置,可能只对主进程生效
每次在请求上下文中创建 registry
- 不要复用全局 registry
- 如果
MultiProcessCollector使用了已注册指标的 registry,则会从文件加载另一份,可能导致同一指标出现两次
- 最佳实践
- 每次请求上下文中使用一个全新的
registry=CollectorRegistry(),并只注册MultiProcessCollector
gunicorn 配置文件应包含以下函数
调整 Gauge 类指标:指定如何合并不同进程的 Gauge 值
multiprocess_mode 支持以下模式
- 在模式开头加上
live返回相同的结果,但仅考虑存活的进程
模式 | 行为 | 适用场景 |
'all' | 每个进程单独输出(带 pid 标签) | 调试、分析单个 worker |
'min' | 所有进程值的最小值 | 如“最低可用连接数” |
'max' | 所有进程值的最大值 | 如“最高队列长度” |
'sum' | 所有进程值的总和 | 最常用(如总请求数、总内存) |
'mostrecent' | 最近更新的进程的值 | 状态类指标(但慎用) |
prometheus_client 指标类
基类 MetricWrapperBase(Collector), Collector(Protocol)
- 详见文档
MetricWrapperBase继承自Collector,可被 Prometheus registry 收集并暴露
- 在
MetricWrapperBase实现了标签相关处理
四种原生指标类
Counter 类:递增,并在进程重新启动时重置
名称不要手动添加 _total 后缀
- 内部添加
_total后缀,在暴露时间序列时会用到
方法 inc(amount) 增加 value
方法 count_exceptions() 作为修饰器或上下文管理器对异常执行计数
- 方法
reset()重置计数
Gauge 类:增减
新增初始化参数 multiprocess_mode,默认为 all
multiprocess_mode: Literal['all', 'liveall', 'min', 'livemin', 'max', 'livemax', 'sum', 'livesum', 'mostrecent', 'livemostrecent'] = 'all',
- 若使用
'mostrecent'模式,仅允许通过set()方法设置带时间戳的数值 - 每个进程写入独立文件,由主进程合并为最新的值
live*为仅考虑进程存活
工具方法 set_to_current_time() 设置时间为当前 UNIX 时间戳
方法 inc(amount), dec(amount), set(value) 调整 value
方法 track_inprogress() 返回 InprogressTracker 对象作为修饰器或者上下文管理器跟踪正在进行的任务数
- 进入时增加计数,退出时减少计数
方法 time() 返回 Timer 对象作为修饰器或者上下文管理器记录代码块执行耗时
- 通过调用
set(duration)方法记录耗时
方法 set_function(f) 将 Gauge 的值绑定到一个函数
- 设置后其他方法失效
- 样例中,每次暴露指标时调用对应
len()函数并将结果作为指标值
源码实现
- 注意多线程安全
Summary 类:记录观测值数量与总和
- 保留
quantile标签名但未实际使用 - 需要计算分位数请使用
Histogram类
名称不要手动添加 _count, _sum 后缀
- 初始化
self._count和self._sum时内部添加对应后缀,在暴露时间序列时会用到
方法 observe(amount) 简单递增 _count 并为 _sum 增加 amount 数值
样例
方法 time() 返回 Timer 对象作为修饰器或者上下文管理器记录代码块执行耗时
time() 样例
- 与
Gauge类的 time() 类似但调用的方法是observe(duration)
Histogram 类:统计观测值分布
- 保留
le标签名
新增初始化参数 buckets: Sequence[Union[float, str]] = DEFAULT_BUCKETS
DEFAULT_BUCKETS = (.005, .01, .025, .05, .075, .1, .25, .5, .75, 1.0, 2.5, 5.0, 7.5, 10.0, INF)
桶的初始处理
- 转为
float,升序排列,自动追加INF作为最后一个桶(确保所有值都能落入某个桶),要确保包括INF在内至少有两个值
名称不要手动添加 _bucket, _sum 后缀
- 初始化
self._buckets和self._sum时内部添加对应后缀,在暴露时间序列时会用到
- 每个桶均为一个单独的计数器
方法 observe(amount) 为 _sum 对应增加 amount 且 amount 首次落入某个桶的上标范围内时,对应桶计数加一
- exemplar 为可选的示例元数据,如
observe(amount, exemplar={'trace_id': 'abc'}) - 通常用于关联追踪(Tracing)系统
样例
方法 time() 返回 Timer 对象作为修饰器或者上下文管理器记录代码块执行耗时
time() 样例
- 与
Gauge类的 time() 类似但调用的方法是observe(duration)
Counter, Summary, Histogram 默认导出一个以 _created 为后缀的额外时间序列
- 其值为指标创建时的 Unix 时间戳
- 可以通过设置环境变量
PROMETHEUS_DISABLE_CREATED_SERIES=True或在代码调用全局函数disable_created_metrics()中来禁用
其他辅助指标类
Info 类:用于暴露键值对元数据
info(val) 方法设置字典 val 的 key 为标签名,value 为标签值
- 所有值应为字符串
- key 不能与指标已有的标签名重叠,value 不能为空
Info 类样例
Enum 类:表示一个实体当前处于预定义状态集合中的某一个
初始化时必须提供 states 字符串序列
- 序列可以是 list 或 tuple 等
- 不能用指标名作为标签名
用整数索引表示当前状态
- 默认为
states字符串序列首个字符串
state(state) 方法设置当前状态
- 传入
state必须在states字符串序列中
Enum 类样例
Exemplar 类:NamedTuple,为 Counter 和 Histogram 指标的时间序列附加示例元数据
源码定义
Counter 样例
Histogram 样例
Exemplar 仅以 OpenMetrics 文本格式呈现
- 如果你使用了该库内置的 HTTP 指标服务器(例如
start_http_server()或集成到 Flask/FastAPI 中),那么客户端(如 Prometheus Server)可以通过 HTTP 内容协商来请求 OpenMetrics 格式 - Prometheus Server 默认就会发送
Accept: application/openmetrics-text请求头,因此会自动收到包含 Exemplars 的响应
- 如果你不是通过 HTTP 服务器暴露指标,默认的
generate_latest()(来自prometheus_client.exposition)不会输出 Exemplars,必须显式使用 OpenMetrics 专用的生成函数 from prometheus_client.openmetrics.exposition import generate_latest
- Prometheus 需要启用
--enable-feature=exemplar-storage标识才能存储 Exemplar
调用方法 labels(*labelvalues: Any, **labelkwargs: Any) 为指标添加标签
源码定义
- 建议仅通过调用
.labels()方法来初始化标签值,参考样例三
Counter 类样例一:位置参数
Counter 类样例二:关键字参数
Counter 类样例三:声明时不会被初始化
prometheus_client 收集器(collector)和注册表(registry)
prometheus_client 默认会运行一些收集器来收集 python 进程和当前平台的信息
进程收集器自动收集当前 Python 进程的系统资源使用情况
- 收集 CPU 使用率、内存占用、文件描述符和启动时间等,以
process_为前缀的指标暴露
- 仅在 Linux 上可用(因为依赖
/proc/self/stat等 Linux 特有接口)
- 可以导出有关其他进程的指标
- 通过构造函数参数 pid 和 namespace 来实现
平台收集器自动暴露 Python 运行环境的元数据,作为 python_info 指标的标签
- 指标值恒为
1,所有信息都在标签中
- 如果使用 Jython,还会包含所用 JVM 的元数据
- 除此之外还有一个 GC 收集器未展开说明
可以通过 prometheus_client.REGISTRY.unregister() 方法来手动禁用
CollectorRegistry 类负责管理所有注册的收集器
- 全局注册表实例
REGISTRY REGISTRY = CollectorRegistry(auto_describe=True)
初始化时可以提供 target_info 和 auto_describe
target_info字典参数用于设置全局target_info指标标签- 详见下面的
set_target_info()方法说明
在检测指标名冲突时,当收集器没有显式提供 describe() 方法时,auto_describe 决定是否回退到调用 collect() 来获取指标信息
- 内部
_get_name(collector)方法
方法 register(collector: Collector) 注册收集器
- 获取该收集器将产生的所有指标名,检查是否与已有指标名冲突
- 如果无冲突,更新两个映射字典
方法 unregister(collector: Collector) 注销收集器
方法 collect() 从 registry 中的所有 collector 收集指标并产出
- 返回一个可迭代对象(generator)
- Prometheus
/metricshandler 会遍历它来输出所有指标
方法 restricted_registry() 返回一个 RestrictedRegistry 对象,只收集指定名称的指标
RestrictedRegistry 对象的方法 collect() 只收集并输出 names 里的指标
方法 set_target_info(labels: Optional[Dict[str, str]]) 设置全局 target_info 指标标签
- 如果
labels非空,则注册一个名为target_info的虚拟收集器
- 如果
labels为 None 则移除 target_info
方法 get_target_info() 返回当前 target_info 指标标签
自定义收集器适用于无法直接在目标代码中埋点的场景(如第三方服务、黑盒系统等)
- 创建一个 Custom Collector,定期从外部系统(如 API、日志、数据库)拉取指标数据,并将其转换为 Prometheus 格式暴露出去
CustomCollector 类样例
继承 Collector,定义 collect() 方法
collect()方法必须 yieldMetricFamily对象- 每个
MetricFamily代表一个指标,可包含多个带标签的样本 - 可用类
CounterMetricFamily,GaugeMetricFamily,SummaryMetricFamily,HistogramMetricFamily,InfoMetricFamily等
- 注册到全局
REGISTRY,Prometheus 的 HTTP handler 就能自动抓取这些指标
可选,定义 describe() 方法用于检测命名冲突和防止重复注册
- 在注册阶段提前告知注册表,将 yield 哪些指标名称
describe()只需返回与collect格式相同的指标(但无需包含样本)
- 通常不需要实现
describe方法 - 创建 CollectorRegistry 时设置了
auto_describe=True且收集器未定义describe方法,那么注册时会调用collect而不是describe - 如果该行为会产生问题再实现合适的
describe方法或者直接返回空列表
prometheus_client 暴露指标
- 通常通过 HTTP 协议公开指标
最简单的是通过 start_http_server() 启动一个 HTTP 服务器
- 以下样例启动一个 HTTP 服务器在 8000 端口暴露指标
start_http_server()返回 HTTP 服务器实例和后台线程对象,可用于优雅地关闭服务器
可以通过 start_http_server() 启动一个 HTTPS 服务器
- 需要提供
certfile和keyfile
- 启用 HTTPS 后,可以通过设置
client_auth_required=True来启用 mTLS client_cafile可用于指定包含 CA 证书链的证书文件,该证书链用于验证客户端证书client_capath可用于指定包含 CA 证书链的证书目录,该证书链用于验证客户端证书
其他实现根据不同 web 框架而不同,仅列举 Django 和 Flask
Django
添加端点和视图
调整多进程设置
- 默认情况下,如果设置了环境变量
PROMETHEUS_MULTIPROC_DIR,则会启用多进程支持
- 可以通过
PrometheusDjangoView自定义暴露指标
- django-prometheus 提供 Django 应用程序的一些现成的监控指标
Flask
- 需要通过 Prometheus WSGI 应用来提供指标服务
myapp.py
- 运行 WSGI 应用
uwsgi --http 127.0.0.1:8000 --wsgi-file myapp.py --callable app
其他:与 node_exporter 的 textfile collect 集成
- 写入到文本文件然后让 node_exporter 读取
- 这里使用了一个独立的注册表,因为默认注册表可能包含其他指标(例如来自 Process Collector 的进程指标),而这里只希望将特定的自定义指标写入文本文件
其他:与 pushgateway 集成
pushgateway 需要分组键,详见 pushgateway 文档的 HTTP 方法
- 函数
push_to_gateway会将指标替换为具有相同分组键的值 - 对应
PUT方法
- 函数
pushadd_to_gateway只会替换名称和分组键相同的指标 - 对应
POST方法
- 函数
delete_from_gateway删除具有给定作业和分组键的指标 - 对应
DELETE方法
- 函数
instance_ip_grouping_key返回一个分组键,其中实例标签设置为主机的 IP 地址
样例:推送到位于本机 9091 端口的 pushgateway 实例
- 这里使用了一个独立的注册表,因为默认注册表可能包含其他指标(例如来自 Process Collector 的进程指标),而这里只希望推送特定的自定义指标
发送前压缩数据:设置 compression 参数设置为 'gzip' 或 'snappy'
- snappy 需要安装 python-snappy 软件包
pushgateway 身份验证处理
basic_auth_handler设置 Authorization 标头
- 函数
push_to_gateway设置对应 handler
pushgateway TLS 验证处理
tls_auth_handler设置对应 TLS 文件
- 函数
push_to_gateway设置对应 handler
- Author:白鸟3
- URL:https://blog.kun2peng.top/develop/prometheus_client_python
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
