Litefs Prometheus 监控
更新日期: 2026-10-21 适用版本: v0.9.0(开发中)
概述
Litefs 内置 Prometheus 监控中间件,用于暴露应用的运行指标:
HTTP 请求总数 / 错误数 / 延迟直方图 / 响应体大小
数据库连接池状态(连接池容量、空闲、在用、溢出、失效)
缓存命中率与条目数
设计原则:
原则 |
实现方式 |
|---|---|
零侵入 |
以中间件形式接入,不改动业务代码 |
可选依赖 |
|
低基数 |
路由标签使用路由模板( |
线程安全 |
指标对象由 prometheus-client 内部保证线程安全;动态采集加锁串行化 |
安装
# 仅启用监控能力
pip install 'litefs[prometheus]'
# 或直接安装依赖
pip install prometheus-client
未安装时使用监控功能会抛出 PrometheusNotAvailable(继承 ImportError),并给出安装指引:
未安装 prometheus-client,请执行 pip install 'litefs[prometheus]' 或 pip install prometheus-client
快速开始
方式一:代码挂载(推荐)
from litefs.core import Litefs
from litefs.middleware import PrometheusMiddleware
app = Litefs()
app.add_middleware(PrometheusMiddleware)
app.run()
方式二:配置驱动
app = Litefs(
prometheus_enabled=True, # 开启监控
prometheus_path='/metrics', # 指标暴露路径
prometheus_namespace='litefs', # 指标名前缀
)
配置项同样支持写在 config.yaml 中:
prometheus_enabled: true
prometheus_path: /metrics
prometheus_namespace: litefs
prometheus_enabled为true时,框架会在应用构造阶段校验prometheus-client是否可用,缺失时立即失败,避免延迟到首个请求才报错。
方式三:自定义参数
app.add_middleware(
PrometheusMiddleware,
path='/internal/metrics', # 自定义暴露路径
namespace='myapp', # 自定义指标前缀
buckets=(0.01, 0.1, 1.0, 10.0), # 自定义延迟分桶(秒)
exclude_paths=('/internal',), # 这些路径不采集指标
)
指标清单
所有指标均以 namespace 为前缀(默认 litefs)。
指标名 |
类型 |
标签 |
含义 |
|---|---|---|---|
|
Counter |
|
请求总数 |
|
Counter |
|
错误响应总数(状态码 ≥ 400) |
|
Histogram |
|
请求耗时(秒) |
|
Histogram |
|
响应体大小(字节) |
|
Gauge |
|
数据库连接池状态 |
|
Counter |
|
缓存读操作总数( |
|
Gauge |
|
缓存条目数量 |
标签语义
标签 |
取值 |
说明 |
|---|---|---|
|
|
HTTP 请求方法 |
|
|
路由模板,未匹配到路由时为 |
|
|
HTTP 状态码 |
|
|
数据库实例名 |
|
|
连接池状态项 |
|
|
缓存实例标识 |
|
|
缓存后端类型 |
|
|
缓存读命中情况 |
为什么使用路由模板:若直接用原始路径作为标签,
/user/1、/user/2… 会产生无限增长的时序,撑爆 Prometheus 存储。框架在路由匹配成功后会把route.path(模板)挂到请求处理器上,中间件据此打标签,从而保证标签基数与路由数量同阶。
默认延迟分桶
0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0 (秒)
该分桶覆盖 5ms ~ 10s 的典型区间,P99 落在 100ms ~ 1s 之间。如需贴合业务 SLO,建议按实际延迟分布自定义 buckets。
/metrics 端点
curl http://127.0.0.1:8080/metrics
返回 Content-Type: text/plain; version=0.0.4; charset=utf-8,内容为 Prometheus 文本格式:
# HELP litefs_http_requests_total HTTP 请求总数
# TYPE litefs_http_requests_total counter
litefs_http_requests_total{method="GET",path="/user/{id}",status="200"} 12.0
# HELP litefs_http_errors_total HTTP 错误响应总数(状态码 >= 400)
# TYPE litefs_http_errors_total counter
litefs_http_errors_total{method="GET",path="/user/{id}",status="404"} 1.0
端点本身不会被计入请求指标(请求在中间件层直接短路),因此不会产生自监控噪声。
响应链路兼容性
Litefs 存在两条响应链路,中间件对两者均能正常采集指标:
链路 |
典型场景 |
|
状态码来源 |
|---|---|---|---|
WSGI / ASGI |
gunicorn、uvicorn、 |
|
三元组第一段 |
原生 Socket |
|
仅响应体字符串 |
|
原生 Socket 路径下,响应头保存在 request_handler._headers,状态码保存在 request_handler._status_code。
中间件通过 _extract_response() 统一这两种形态,提取出统一的三元组后再记录指标,因此
在 app.run() 默认模式下 /metrics 同样能采集到完整的请求指标。
动态指标的采集时机
连接池与缓存指标是快照型数据,在每次 /metrics 抓取时实时采集(scrape-time collection),而非在业务请求路径上采集:
连接池:遍历所有已初始化的数据库实例,读取
pool_size/checked_in/checked_out/overflow/invalid。 某些连接池实现(如 SQLite 的SingletonThreadPool)不提供完整状态接口,此时该数据库会被自动跳过,不影响其他指标。缓存:遍历缓存管理器中的实例,按增量方式累加命中/未命中计数(避免重复计数),并以 Gauge 反映当前条目数。
采集过程全部包裹异常保护,任何采集失败都不会影响业务请求。
Prometheus 抓取配置
scrape_configs:
- job_name: 'litefs'
scrape_interval: 15s
metrics_path: '/metrics'
static_configs:
- targets: ['127.0.0.1:8080']
多实例部署时用服务发现(consul_sd_configs / kubernetes_sd_configs)替代静态列表。
Grafana 常用查询
# QPS
sum(rate(litefs_http_requests_total[1m]))
# 错误率(按状态码分组)
sum(rate(litefs_http_errors_total[5m])) by (status)
# P95 延迟
histogram_quantile(0.95, sum(rate(litefs_http_request_duration_seconds_bucket[5m])) by (le, path))
# 数据库连接池水位
litefs_db_pool_connections{state="checked_out"} / litefs_db_pool_connections{state="pool_size"}
# 缓存命中率
sum(rate(litefs_cache_operations_total{result="hit"}[5m]))
/ sum(rate(litefs_cache_operations_total[5m]))
生产部署要点
1. 隔离暴露面
/metrics 会暴露内部路径、状态码分布等信息,不要直接暴露到公网。推荐在 Nginx 层做限制:
server {
listen 80;
location /metrics {
# 仅允许内网监控网段访问
allow 10.0.0.0/8;
deny all;
proxy_pass http://127.0.0.1:8080;
}
location / {
proxy_pass http://127.0.0.1:8080;
}
}
或使用 exclude_paths 排除敏感前缀。
2. 多进程模型(Gunicorn)
每个 worker 进程拥有独立的指标注册表,因此 /metrics 只会返回当前处理该请求的那个 worker 的数据。若使用 gunicorn -w 4,抓取到的指标只有 1/4 的量。
两种应对方式:
方式一(简单):Prometheus 对每个 worker 单独抓取。使用
gunicorn的SO_REUSEPORT或让每个 worker 绑定不同端口,逐个加入targets。方式二(推荐):启用 prometheus-client 的多进程模式。
export PROMETHEUS_MULTIPROC_DIR=/var/run/litefs/prometheus
gunicorn -w 4 -b :8080 wsgi:application
多进程模式需要使用
MultiProcessCollector,且指标需在进程启动时创建。本框架默认的单进程 / 多线程 / greenlet 模型无需额外配置。
3. 采样与降载
指标采集发生在请求路径上(Counter 递增、Histogram 观测),开销为常数级(微秒级),通常无需优化。但在超高 QPS 场景下可:
缩小
buckets数量(分桶越多,直方图开销越大)。对
/metrics端点本身做限流,避免被高频抓取。
4. 中间件顺序
监控中间件会记录所有请求,因此建议放在中间件链的最外层(最先注册),这样才能覆盖到被其它中间件短路掉的请求:
app.add_middleware(PrometheusMiddleware) # 最外层
app.add_middleware(LoggingMiddleware)
app.add_middleware(SecurityMiddleware)
API 参考
PrometheusMiddleware
PrometheusMiddleware(
app,
path='/metrics',
namespace='litefs',
buckets=None,
exclude_paths=None,
)
参数 |
类型 |
默认值 |
说明 |
|---|---|---|---|
|
|
|
指标暴露路径 |
|
|
|
指标名前缀 |
|
|
|
延迟分桶(秒), |
|
|
|
不采集指标的路径前缀列表 |
MetricsRegistry
from litefs.metrics import MetricsRegistry
registry = MetricsRegistry(namespace='litefs', buckets=None)
registry.observe_request(
method='GET', path='/user/{id}', status_code=200,
duration=0.012, response_size=1024,
)
print(registry.render())
方法 |
说明 |
|---|---|
|
渲染 Prometheus 文本格式(内部会先刷新动态指标) |
|
刷新连接池与缓存动态指标 |
|
记录一次 HTTP 请求 |
|
Prometheus 文本格式的 Content-Type |
异常
异常 |
触发条件 |
|---|---|
|
未安装 |
常见问题
Q:为什么 /metrics 返回 404?
A:确认中间件已挂载。若使用配置驱动方式,确认 prometheus_enabled: true 生效且 prometheus_path 与实际请求路径一致(区分大小写、包含上下文前缀)。
Q:指标里 path 都是 unmatched?
A:说明请求未匹配到任何路由(例如 404 请求),框架会统一归类到 unmatched,这是预期行为。
Q:连接池指标缺失?
A:当前数据库使用的连接池实现不提供完整状态接口(如 SQLite 内存库的 SingletonThreadPool),框架会自动跳过。生产环境使用 MySQL / PostgreSQL 时指标完整可用。
Q:缓存命中率为 0?
A:litefs_cache_operations_total 统计的是缓存读操作。若应用只写不读,或使用了不继承 CacheBackendBase 的缓存(如 FormCache),则不会产生读计数。
Q:如何统计某个特定接口的 QPS?
A:使用路由模板作为过滤条件,例如 rate(litefs_http_requests_total{path="/user/{id}"}[1m])。
相关文档
:doc:
middleware-guide—— 中间件系统总览:doc:
cache-system—— 缓存系统与后端说明:doc:
configuration—— 配置项完整列表:doc:
static-checks—— 静态检查规范