news 2026/10/8 1:42:00

Hyperf 服务监控组件 hyperf/metric 全指南:Prometheus、StatsD、InfluxDB 多后端接入与业务指标采集实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Hyperf 服务监控组件 hyperf/metric 全指南:Prometheus、StatsD、InfluxDB 多后端接入与业务指标采集实战
  • 后端
  • Web框架
  • 微服务
  • RPC框架
  • 异步编程

【免费下载链接】hyperf

🚀 A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.

项目地址:https://gitcode.com/hyperf/hyperf
点击查看免费下载

在微服务体系治理中,服务的可观测性是核心诉求之一。作为运维者,很难直观掌握每一个服务的健康状态,而业界围绕 telemetry(遥测)与 monitoring(监控)已经沉淀了大量云原生方案。Hyperf 的hyperf/metric组件正是对这一能力的抽象:它把可观测性、遥测与监控的关键支柱收敛为统一接口,让开发者可以快速接入现有监控基础设施(Prometheus、StatsD、InfluxDB 等),同时避免与任何特定供应商强绑定。阅读本文后,你将掌握:如何安装并配置该组件、如何用三种后端驱动(Prometheus / StatsD / InfluxDB)采集与上报指标、如何通过中间件与注解统计 HTTP 请求与业务调用、如何自定义上报链路以及如何在 Grafana 中一键导入现成仪表盘。

组件定位与设计理念

hyperf/metric是 Hyperf 体系中的指标(Metrics)组件,位于仓库 src/metric 目录。它解决的核心问题是:在超高性能协程框架中,如何以统一的编程模型向不同监控后端上报指标,而不必在业务代码中散落各后端的专有 API。

从 composer.json 可以看到组件面向 PHP >= 8.2,关键字为prometheus、statsd、metrics、influxdb,并通过suggest声明了各驱动所需的三方依赖。组件本身只负责「抽象 + 采集 + 分发」,具体后端的差异被适配器(Adapter)隔离在src/metric/src/Adapter/目录下(Prometheus、StatsD、InfluxDB、NoOp、RemoteProxy五套实现),这正是其"不锁定供应商"的架构根基。

安装与初始化

通过 Composer 安装组件

composer require hyperf/metric

hyperf/metric本身是可独立安装的组件包,随后按需安装对应后端的客户端依赖:

# Prometheus composer require promphp/prometheus_client_php # StatsD 依赖 composer require domnikl/statsd # InfluxDB 依赖 composer require influxdb/influxdb-php

补充说明:仓库内 src/metric/composer.json 的suggest中提示的是slickdeals/statsd与influxdata/influxdb-client-php,与文档示例中的包名略有差异——前者同样提供Domnikl\Statsd命名空间,后两者对应不同版本的 InfluxDB 客户端。实际以你所在项目的依赖解析结果为准。

发布组件配置文件

若项目中尚不存在配置文件,执行以下命令生成config/autoload/metric.php:

php bin/hyperf.php vendor:publish hyperf/metric

发布动作由 ConfigProvider.php 中的publish节点定义,源文件即 src/metric/publish/metric.php。同时该 ConfigProvider 还会注册以下内容:

  • 依赖注入绑定:MetricFactoryInterface→MetricFactoryPicker,Prometheus\Storage\Adapter→InMemory(默认内存存储),StatsD 连接 →UdpSocket;
  • AOP 切面:CounterAnnotationAspect、HistogramAnnotationAspect(支撑注解埋点);
  • 事件监听器:OnPipeMessage、OnMetricFactoryReady、OnWorkerStart等;
  • 常驻进程:MetricProcess(即独立监控进程)。

核心配置解析

顶层选项

'default' => env('METRIC_DRIVER', 'prometheus'),

default的值对应配置文件中metric下标里某个驱动配置的key,即当前生效的驱动名。可以随时通过环境变量切换驱动而无需改动业务代码。

'use_standalone_process' => env('TELEMETRY_USE_STANDALONE_PROCESS', true),

use_standalone_process:是否启用「独立监控进程」。强烈建议开启。若关闭,指标采集与上报将由 Worker 进程内联完成(参见 OnWorkerStart.php 中use_standalone_process为 false 时调用spawnHandle()的分支)。

'enable_default_metric' => env('TELEMETRY_ENABLE_DEFAULT_TELEMETRY', true),

enable_default_metric:是否采集默认指标。默认指标包括:内存使用量、系统 CPU 负载,以及 Swoole Server 与 Swoole Coroutine 的相关指标。在源码层面,OnWorkerStart.php 会以default_metric_interval为周期定时写入worker_request_count、worker_dispatch_count、memory_usage、memory_peak_usage、gc_runs、gc_collected、ru_utime_tv_usec(来自getrusage())等一组系统级指标。

'default_metric_interval' => env('DEFAULT_METRIC_INTERVAL', 5),

default_metric_interval:默认指标的推送周期,单位为秒(下文各驱动的push_interval同理)。

完整发布配置(含增强项)

官方发布文件 src/metric/publish/metric.php 比文档示例更完整,其中还包含:

  • enable_command_metric(METRIC_ENABLE_COMMAND_METRIC,默认 true):是否在命令行场景启用指标;
  • buffer_interval(METRIC_BUFFER_INTERVAL,默认 5)与buffer_size(METRIC_BUFFER_SIZE,默认 200):仅在use_standalone_process = true时生效,用于控制 Worker 向独立监控进程投递指标数据的缓冲节奏与容量;
  • noop驱动:将default指向noop即可临时禁用指标采集,实现零成本开关;
  • Prometheus 的redis_config、redis_prefix、redis_gather_key_suffix:用于自定义模式下的 Redis 存储配置。

注意:文档示例中的环境变量名(如TELEMETRY_USE_STANDALONE_PROCESS、TELEMETRY_ENABLE_DEFAULT_TELEMETRY)与发布文件中的默认值(METRIC_USE_STANDALONE_PROCESS、METRIC_ENABLE_DEFAULT_METRIC)并不完全一致,两者都可按需调整,请以实际vendor:publish生成的config/autoload/metric.php为准。

三大后端驱动配置

配置 Prometheus

将 Prometheus 专属配置放入metric下标:

use Hyperf\Metric\Adapter\Prometheus\Constants; return [ 'default' => env('METRIC_DRIVER', 'prometheus'), 'use_standalone_process' => env('TELEMETRY_USE_STANDALONE_PROCESS', true), 'enable_default_metric' => env('TELEMETRY_ENABLE_DEFAULT_TELEMETRY', true), 'default_metric_interval' => env('DEFAULT_METRIC_INTERVAL', 5), 'metric' => [ 'prometheus' => [ 'driver' => Hyperf\Metric\Adapter\Prometheus\MetricFactory::class, 'mode' => Constants::SCRAPE_MODE, 'namespace' => env('APP_NAME', 'skeleton'), 'scrape_host' => env('PROMETHEUS_SCRAPE_HOST', '0.0.0.0'), 'scrape_port' => env('PROMETHEUS_SCRAPE_PORT', '9502'), 'scrape_path' => env('PROMETHEUS_SCRAPE_PATH', '/metrics'), 'push_host' => env('PROMETHEUS_PUSH_HOST', '0.0.0.0'), 'push_port' => env('PROMETHEUS_PUSH_PORT', '9091'), 'push_interval' => env('PROMETHEUS_PUSH_INTERVAL', 5), ], ], ];

Prometheus 支持三种操作模式,常量定义见 Constants.php:SCRAPE_MODE = 1、PUSH_MODE = 2、CUSTOM_MODE = 3。

Scrape 模式(Prometheus 官方推荐):设置'mode' => Constants::SCRAPE_MODE,并配置抓取地址scrape_host、抓取端口scrape_port、抓取路径scrape_path,Prometheus 即可按配置通过 HTTP 拉取全部指标。

注意:在异步风格(协程 Server)下,scrape 模式必须开启独立进程,即use_standalone_process = true。从实现看,Prometheus MetricFactory.php 的scrapeHandle()会在scrape_host:scrape_port上起一个内置 HTTP Server,以RenderTextFormat渲染CollectorRegistry中的指标;它还会检查该端口是否与server.servers中业务服务端口冲突并输出告警日志。

Push 模式:设置'mode' => Constants::PUSH_MODE,并配置推送地址push_host、推送端口push_port、推送周期push_interval。Push 模式仅推荐用于离线任务(offline task)。其实现位于pushHandle():按push_interval周期性地向 Pushgateway 发起 PUT 请求,请求 URL 形如http://host:port/metrics/job/{namespace}/ip/{ip}/pid/{pid},并校验响应码必须为 200 或 202。

Custom 模式:设置'mode' => Constants::CUSTOM_MODE。在该模式下组件只负责指标采集,上报动作完全交由使用者处理——例如通过自定义路由暴露指标,或把指标暂存到 Redis 由独立服务集中上报。本文「自定义上报」一节给出对应示例。

配置 StatsD

return [ 'default' => env('METRIC_DRIVER', 'statd'), 'use_standalone_process' => env('TELEMETRY_USE_STANDALONE_PROCESS', true), 'enable_default_metric' => env('TELEMETRY_ENABLE_DEFAULT_TELEMETRY', true), 'metric' => [ 'statsd' => [ 'driver' => Hyperf\Metric\Adapter\StatsD\MetricFactory::class, 'namespace' => env('APP_NAME', 'skeleton'), 'udp_host' => env('STATSD_UDP_HOST', '127.0.0.1'), 'udp_port' => env('STATSD_UDP_PORT', '8125'), 'enable_batch' => env('STATSD_ENABLE_BATCH', true), 'push_interval' => env('STATSD_PUSH_INTERVAL', 5), 'sample_rate' => env('STATSD_SAMPLE_RATE', 1.0), ], ], ];

StatsD 目前仅支持 UDP 模式,需要配置 UDP 地址udp_host、UDP 端口udp_port、是否批量推送enable_batch(用于减少请求数量)、批量推送周期push_interval、采样率sample_rate。发布配置中还可选timeout与persistent连接参数。从 StatsD MetricFactory.php 可以看到,handle()在开启批量模式时会按push_interval周期循环执行startBatch()/endBatch();发布文件同时会创建Domnikl\Statsd\Connection\UdpSocket作为默认 UDP 连接。

配置 InfluxDB

return [ 'default' => env('METRIC_DRIVER', 'influxdb'), 'use_standalone_process' => env('TELEMETRY_USE_STANDALONE_PROCESS', true), 'enable_default_metric' => env('TELEMETRY_ENABLE_DEFAULT_TELEMETRY', true), 'metric' => [ 'influxdb' => [ 'driver' => Hyperf\Metric\Adapter\InfluxDB\MetricFactory::class, 'namespace' => env('APP_NAME', 'skeleton'), 'host' => env('INFLUXDB_HOST', '127.0.0.1'), 'port' => env('INFLUXDB_PORT', '8086'), 'username' => env('INFLUXDB_USERNAME', ''), 'password' => env('INFLUXDB_PASSWORD', ''), 'dbname' => env('INFLUXDB_DBNAME', true), 'push_interval' => env('INFLUXDB_PUSH_INTERVAL', 5), ], ], ];

InfluxDB 默认使用 HTTP 模式,需要配置地址host、端口port(注意:InfluxDB 通常使用 HTTP 端口 8086)、用户名username、密码password、数据库dbname、批量推送周期push_interval。

版本提示:当前发布配置文件 src/metric/publish/metric.php 中 InfluxDB 段的字段为token、bucket、org,对应 InfluxDB 2.x 的鉴权与组织模型;文档示例中的username/password/dbname则对应 1.x 风格,请根据实际部署版本选择。

底层抽象:Counter / Gauge / Histogram

组件抽象出三种最常用的指标类型,确保业务代码与具体实现解耦:

  • Counter(计数器):描述单调递增的指标,例如 HTTP 请求总数。
interface CounterInterface { public function with(string ...$labelValues): self; public function add(int $delta); }
  • Gauge(仪表):描述随时间可升可降的指标,例如连接池当前可用连接数。
interface GaugeInterface { public function with(string ...$labelValues): self; public function set(float $value); public function add(float $delta); }
  • Histogram(直方图):描述对某事件持续观测得到的统计分布,通常以百分位或 bucket 呈现,例如 HTTP 请求延迟。
interface HistogramInterface { public function with(string ...$labelValues): self; public function put(float $sample); }

对应的契约文件位于 src/metric/src/Contract 目录(CounterInterface.php、GaugeInterface.php、HistogramInterface.php、MetricFactoryInterface.php)。统一入口MetricFactoryInterface提供三个工厂方法:

public function makeCounter($name, $labelNames): CounterInterface; public function makeGauge($name, $labelNames): GaugeInterface; public function makeHistogram($name, $labelNames): HistogramInterface;

工厂方法会通过with(...$labelValues)绑定标签值(label),后续调用add/set/put写入具体数值。以 Prometheus 适配器为例,Prometheus MetricFactory.php 在创建指标时会自动附带 help 描述(如count xxx、gauge xxx、measure xxx),并统一使用 snake_case 的命名空间(getNamespace()会将非法字符替换为下划线,MetricFactoryTest.php 中验证了Hello-World!→hello__world_的转换)。

配置中间件:自动采集 HTTP 指标

配置好驱动后,只需注册中间件即可为请求开启 Histogram 统计。编辑config/autoload/middlewares.php,在httpServer 中启用:

<?php declare(strict_types=1); return [ 'http' => [ \Hyperf\Metric\Middleware\MetricMiddleware::class, ], ];

该中间件的统计维度包含request_status、request_path、request_method。实现细节见 MetricMiddleware.php:它默认以500作为兜底状态码(防止未捕获异常时缺失维度),request_path优先取路由分发结果Dispatched中的路由定义(未匹配时记为not_found),并用Timer(见 Timer.php)记录耗时写入http_requests直方图;同时维护CoroutineServerStats(CoroutineServerStats.php)中的连接数、请求数、响应数等统计。

重要提醒:如果你的服务存在过多request_path,建议重写该中间件并移除request_path维度,否则过高的基数(cardinality)会导致内存溢出。

业务指标自定义埋点

通过 HTTP 中间件采集遥测只是该组件能力的冰山一角。你可以注入Hyperf\Metric\Contract\MetricFactoryInterface,采集自身业务指标,例如「创建订单数」「广告点击数」:

<?php declare(strict_types=1); namespace App\Controller; use App\Model\Order; use Hyperf\Di\Annotation\Inject; use Hyperf\Metric\Contract\MetricFactoryInterface; class IndexController extends AbstractController { #[Inject] private MetricFactoryInterface $metricFactory; public function create(Order $order) { $counter = $this->metricFactory->makeCounter('order_created', ['order_type']); $counter->with($order->type)->add(1); // Logika order... } }

上述示例采集的是单个请求生命周期内的指标。有些指标则面向完整的生命周期,例如异步队列长度、商品库存量。这类场景可以监听MetricFactoryReady事件:

<?php declare(strict_types=1); namespace App\Listener; use Hyperf\Event\Contract\ListenerInterface; use Hyperf\Metric\Event\MetricFactoryReady; use Psr\Container\ContainerInterface; use Redis; class OnMetricFactoryReady implements ListenerInterface { protected ContainerInterface $container; public function __construct(ContainerInterface $container) { $this->container = $container; } public function listen(): array { return [ MetricFactoryReady::class, ]; } public function process(object $event) { $redis = $this->container->get(Redis::class); $gauge = $event ->factory ->makeGauge('queue_length', ['driver']) ->with('redis'); while (true) { $length = $redis->llen('queue'); $gauge->set($length); sleep(1); } } }

MetricFactoryReady事件定义在 src/metric/src/Event/MetricFactoryReady.php,事件携带一个「已就绪的工厂」MetricFactoryInterface。该事件由独立监控进程(MetricProcess.php)在handle()中派发,也会在非独立进程模式下由 OnWorkerStart.php 对 worker 0 派发,从而保证监听器里的长循环能拿到真实可用的工厂实例。

工程上更严谨的做法是:不要直接llenRedis 查询队列长度,而应通过队列驱动DriverInterface::info()方法获取队列长度——上面仅是简单演示。组件源码src/metric/src/Listener/下提供了完整示例,例如 QueueWatcher.php 会周期性地将队列的waiting、delayed、failed、timeout写入四个 Gauge 指标;PoolWatcher.php(及其子类DBPoolWatcher、RedisPoolWatcher)则按default_metric_interval周期上报连接池的connections_in_use、connections_in_waiting、max_connections。

组件还提供了门面式的便捷类 Metric.php(Beta 特性,API 可能变化):Metric::count()、Metric::gauge()、Metric::shift()、Metric::put()、Metric::time()可一次性创建并写入指标,其中Metric::time($name, $func)借助Timer自动统计回调执行耗时。

注解埋点:统计调用次数与耗时

你可以在类或方法上使用#[Counter(name="stat_name_here")]与#[Histogram(name="stat_name_here")]注解,让切面自动统计该方法的调用次数与执行耗时:

#[Counter(name: "order_create_count")] public function createOrder() { /* ... */ } #[Histogram(name: "order_create_duration")] public function processOrder() { /* ... */ }

实现上,CounterAnnotationAspect.php 与 HistogramAnnotationAspect.php 分别监听对应注解,指标名缺省时自动生成「类名::方法名」的 snake_case 形式,标签维度固定为class与method;Histogram 切面借助Timer在方法执行前后自动计时。注解本身的定义见 src/metric/src/Annotation 目录(Counter.php、Histogram.php,均为#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)])。注解机制依赖hyperf/di,具体用法可参考 Annotation 章节。

自定义 Histogram Bucket(仅 Prometheus 驱动)

使用 Prometheus 的 Histogram 时,有时需要自定义 bucket。可以借助注入的CollectorRegistry,在服务启动前自行注册同名 Histogram 并设置所需 bucket。之后使用MetricFactory时,同名 Histogram 会直接命中你注册的实例:

<?php namespace App\Listener; use Hyperf\Config\Annotation\Value; use Hyperf\Event\Contract\ListenerInterface; use Hyperf\Framework\Event\BeforeMainServerStart; use Prometheus\CollectorRegistry; class OnMainServerStart implements ListenerInterface { protected $registry; public function __construct(CollectorRegistry $registry) { $this->registry = $registry; } public function listen(): array { return [ BeforeMainServerStart::class, ]; } public function process(object $event) { $this->registry->registerHistogram( config("metric.metric.prometheus.namespace"), 'test', 'help_message', ['labelName'], [0.1, 1, 2, 3.5] ); } }

随后执行$metricFactory->makeHistogram('test'),返回的即为你先前注册的自定义 bucket 直方图。

自定义上报(仅 Prometheus 驱动)

将 Prometheus 驱动模式设为Constants::CUSTOM_MODE后,指标上报完全由你掌控。以下演示:把指标存储到 Redis,再在 Worker 中新增一个 HTTP 路由,返回由 Prometheus 渲染的指标文本。

使用 Redis 存储指标

指标存储介质由Prometheus\Storage\Adapter接口定义,默认使用内存存储(InMemory)。在config/autoload/dependencies.php中覆盖为 Redis 存储:

<?php return [ Prometheus\Storage\Adapter::class => Hyperf\Metric\Adapter\Prometheus\RedisStorageFactory::class, ];

RedisStorageFactory.php 会读取metric.metric.prometheus.redis_config(默认default)、redis_prefix、redis_gather_key_suffix等配置,通过Hyperf\Redis\RedisFactory获取对应连接并包装为 Prometheus 的 Redis 存储适配器(Redis.php)。

在 Worker 中新增 /metrics 路由

在config/routes.php中添加 Prometheus 路由:

注意:若要在 Worker 中读取指标,需要自行解决多个 Worker 之间的状态共享问题——一种方案就是上文所述把状态存到 Redis。

<?php use Hyperf\HttpServer\Router\Router; Router::get('/metrics', function(){ $registry = Hyperf\Context\ApplicationContext::getContainer()->get(Prometheus\CollectorRegistry::class); $renderer = new Prometheus\RenderTextFormat(); return $renderer->render($registry->getMetricFamilySamples()); });

在 Grafana 中一键创建监控面板(仅 Prometheus 驱动)

如果你开启了默认指标(enable_default_metric = true),hyperf/metric已经为你准备了一份开箱即用的 Grafana 面板。仓库内的仪表盘定义文件位于 src/metric/grafana.json,将其导入 Grafana 即可直接使用。

该仪表盘覆盖两类面板:一类是核心资源与运行状态(系统负载百分比、内存使用量、内存峰值、当前协程数量、连接数、接受请求计数、关闭请求计数等),另一类是按路径划分的请求概览(各路径请求数、错误数、P50/P90/P99 延迟、成功率)。

注意事项

  • 如果需要在自定义命令(hyperf/command)中使用本组件采集指标,启动命令时需追加命令行参数:--enable-event-dispatcher,否则事件分发(包括MetricFactoryReady)不会被启用,指标链路无法工作。
  • 在命令行场景下使用 Prometheus scrape 模式时,组件会输出告警:Using Prometheus scrape mode in a command. This will stop the command from terminating gracefully.(见 Prometheus MetricFactory.php 的handle()),因为 scrape 模式内置的指标 HTTP 服务会阻塞命令优雅退出,此时建议使用 push 模式或 custom 模式。
  • MetricFactoryPicker(MetricFactoryPicker.php)是工厂选择的枢纽:在非协程上下文返回NoOp工厂;当use_standalone_process = true但未检测到已注册进程(且非命令行)时也回退为NoOp(属于配置错误的兜底);在 Worker 中则返回RemoteProxy工厂,将指标数据通过PipeMessage消息通道投递给独立监控进程(由 OnPipeMessage.php 接收并写回真实工厂),从而保证 Worker 不受上报阻塞的影响。
  • 独立监控进程由 MetricProcess.php 承载(进程名metric,数量 1),仅在$server instanceof Swoole\Server且use_standalone_process = true时启用;异步协程 Server 场景下则通过OnCoroutineServerStart等监听器完成默认指标采集。

小结

hyperf/metric用一个轻量的抽象层把 Prometheus、StatsD、InfluxDB 的差异封装在适配器内部,向上提供 Counter / Gauge / Histogram 三种通用指标模型,向外支持 scrape、push、custom 三种上报模式。结合本文提到的中间件、注解、MetricFactoryReady事件、自定义 bucket、Redis 存储与 Grafana 面板,你可以快速构建一套从「系统默认指标」到「业务自定义指标」的完整服务可观测体系,并在不修改业务代码的前提下随时切换监控后端。

  • 后端
  • Web框架
  • 微服务
  • RPC框架
  • 异步编程

【免费下载链接】hyperf

🚀 A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.

项目地址:https://gitcode.com/hyperf/hyperf
点击查看免费下载
上一篇:颠覆性GitHub效率革命:让中文开发者告别语言障碍的界面汉化解决方案
下一篇:解决GitHub英文界面痛点:用GitHub汉化插件实现98%界面精准转换

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 1:39:37

电子保险丝TPS259483与STM32的电源完整性保护方案设计

每次做完一道涉及“电源完整性”的板子&#xff0c;我都习惯在笔记开头写一句&#xff1a;电源路径上的每一毫欧、每一微秒&#xff0c;都是系统可靠性的真实账单。今天要聊的就是这么一块东西——用 TI 的TPS259483AYWPR电子保险丝做主通路保护&#xff0c;搭配STM32F756ZG做系…

作者头像 李华
网站建设 2026/10/8 1:39:09

掌握 systemd:从入门到生产级配置

文章目录1. systemd 的诞生背景systemd 为什么出现&#xff1f;2. systemd 的核心组件核心组件列表3. systemd Unit 类型4. systemd Service Type 对比5. systemd timer vs crontab&#xff08;全面对比&#xff09;5.1 为什么 timer 更现代&#xff1f;5.2 timer 例子6. syste…

作者头像 李华
网站建设 2026/10/8 1:32:18

res-downloader 视频号视频下载指南

res-downloader 视频号视频下载指南 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_Trending/re/res-downloader res-downloader 是一款跨平台的资源嗅探下…

作者头像 李华