- 可观测性
- 后端
【免费下载链接】metrics
:chart_with_upwards_trend: Capturing JVM- and application-level metrics. So you know what's going on.
导读
metrics-collectd是 Metrics 生态中专门用于对接 Collectd 的官方集成模块,其核心类CollectdReporter允许你的 Java 应用通过 Collectd 二进制协议,将MetricRegistry中注册的 Gauge、Counter、Meter、Histogram、Timer 等指标持续流式推送到 Collectd 服务器。读完本文你将掌握完整的接入步骤、CollectdReporter.Builder全量配置项、指标到 Collectd 数据点的映射规则,以及基于 HMAC-SHA256 签名与 AES-256 加密的安全上报方案。
模块定位:让指标"流"向 Collectd
Collectd 是一个系统统计信息采集守护进程(system statistics collection daemon),它通过插件化方式聚合来自多台主机的数据。metrics-collectd模块提供的 CollectdReporter.java 继承自 Metrics 核心的ScheduledReporter,因此具备定时调度上报的能力:启动后它会按固定周期扫描注册表,将最新指标值打包成 Collectd 二进制数据包,经 UDP 发送给 Collectd 服务器,由 Collectd 统一存储、转发到 Graphite、InfluxDB 等后端。
该模块本身不依赖额外第三方运行时库(仅依赖metrics-core与slf4j-api,见 metrics-collectd/pom.xml),在项目中引入后即可使用:
<dependency> <groupId>io.dropwizard.metrics</groupId> <artifactId>metrics-collectd</artifactId> <version>${metrics.version}</version> </dependency>快速上手:一段最小可用的接入代码
原文档给出了完整的最小接入示例,它清晰地展示了该模块的典型用法——先用Sender指定 Collectd 服务器地址与端口,再通过CollectdReporter.forRegistry(registry)构建器逐项配置,最后定时启动:
final Sender sender = new Sender("collectd.example.com", 2007); final CollectdReporter reporter = CollectdReporter.forRegistry(registry) .convertRatesTo(TimeUnit.SECONDS) .convertDurationsTo(TimeUnit.MILLISECONDS) .filter(MetricFilter.ALL) .build(sender); reporter.start(1, TimeUnit.MINUTES);对照 CollectdReporter.java 的源码,可以进一步理解这段代码的每一层含义:
new Sender(host, port):封装了到 Collectd 服务器的 UDP 连接。Sender.java 内部使用java.nio.channels.DatagramChannel,connect()时通过InetSocketAddress解析目标地址,每次上报时channel.send(buffer, address)发出数据包,上报结束后disconnect()关闭通道。forRegistry(registry):返回Builder,持有你要上报的MetricRegistry。convertRatesTo(TimeUnit.SECONDS):统一换算速率类指标(如每秒请求数、M1/M5/M15 移动平均速率)的时间单位。convertDurationsTo(TimeUnit.MILLISECONDS):统一换算时长类指标(Timer 的分位数、均值、标准差)的时间单位。filter(MetricFilter.ALL):指定上报过滤器,MetricFilter.ALL表示注册表中所有指标都上报,也可以传入自定义MetricFilter实现白名单/黑名单。build(sender):完成构建。此时如果启用了安全级别但未提供用户名/密码,build()会直接抛出IllegalArgumentException(见源码第 152-159 行的校验逻辑)。reporter.start(1, TimeUnit.MINUTES):从ScheduledReporter继承的调度入口,这里表示每隔 1 分钟上报一次;start()会同时记录本次上报周期,作为 Collectd 数据包中interval字段的来源(源码第 216 行将period传入MetaData.Builder)。
CollectdReporter.Builder 配置项全览
除快速上手用到的三个方法外,Builder还提供了多个可选项。下表整理了 CollectdReporter.java 中所有配置方法及其默认值:
| 配置方法 | 作用 | 默认值 |
|---|---|---|
withHostName(String) | 设置数据包中的主机名标识 | InetAddress.getLocalHost().getHostName();解析失败时回退为"localhost" |
scheduleOn(ScheduledExecutorService) | 指定定时上报使用的线程池 | ScheduledReporter内部创建的默认线程池 |
shutdownExecutorOnStop(boolean) | stop()时是否同时关闭传入的线程池 | true |
withClock(Clock) | 自定义时钟(主要用于测试时控制时间) | Clock.defaultClock() |
convertRatesTo(TimeUnit) | 速率单位换算 | TimeUnit.SECONDS |
convertDurationsTo(TimeUnit) | 时长单位换算 | TimeUnit.MILLISECONDS |
filter(MetricFilter) | 指标过滤 | MetricFilter.ALL |
disabledMetricAttributes(Set<MetricAttribute>) | 禁用部分属性,使其不被上报 | 空集合(全部上报) |
withMaxLength(int) | 指标名最大长度(超出部分截断) | 63(Sanitize.DEFAULT_MAX_LENGTH) |
withSecurityLevel(SecurityLevel) | 安全级别:NONE/SIGN/ENCRYPT | NONE |
withUsername(String)/withPassword(String) | 签名或加密时使用的凭据 | 空字符串 |
其中withMaxLength与disabledMetricAttributes直接影响了数据到达 Collectd 后的形态,详见下文命名净化与指标映射两节。
指标类型到 Collectd 数据点的映射规则
report()方法(源码第 214-240 行)会遍历注册表中全部指标,把每个指标名作为 Collectd 的plugin(插件名),并为每个数值属性生成一个type = "gauge"的type-instance数据点。具体映射逻辑见下表,对应源码 CollectdReporter.java:
| Metrics 指标类型 | 映射到 Collectd 的 type-instance | 说明 |
|---|---|---|
Gauge | value | 只接受Number类型;Boolean会转为1/0;其他类型(如String)直接跳过并打 warn 日志 |
Counter | count | 上报计数当前值 |
Meter | count、m1_rate、m5_rate、m15_rate、mean_rate | 计数 + 四个速率,速率经convertRatesTo换算 |
Histogram | count、max、mean、min、stddev、p50、p75、p95、p98、p99、p999 | 快照统计量 + 各百分位 |
Timer | 上述 Histogram 全部字段 + Meter 全部字段 | 时长类字段经convertDurationsTo换算,速率类字段经convertRatesTo换算 |
有两个实现细节值得注意:
- type-instance 直接采用
MetricAttribute的 code(如m1_rate、p95),见writeValue()中attribute.getCode()的调用(源码第 256-260 行),因此 Collectd 端看到的是统一、稳定的命名。 disabledMetricAttributes可裁剪上报字段。例如测试 CollectdReporterTest.java 展示了EnumSet.of(MetricAttribute.M5_RATE, MetricAttribute.M15_RATE)后,Meter 只上报count、m1_rate、mean_rate三个数据点,可用于减少网络流量。
另外,测试用例还验证了 Gauge 的兼容性边界:byte、short、int、long、float、double均可上报,而字符串型 Gauge 不会产生任何数据包(CollectdReporterTest.java)。
collectd 命名规范与 Sanitize 净化
Collectd 对指标名有严格的命名约束,因此该模块内置了 Sanitize.java 对名称进行净化:
- plugin / type名称:保留字符不允许出现
-、/、\0(空字符); - plugin-instance / type-instance名称:保留字符不允许出现
/、\0(允许连字符-); - 任何非法字符以及所有非 ASCII 字符(
c >= 128)都会被替换为下划线_; - 名称长度默认截断到 63 个字符,可用
withMaxLength调整。
例如指标名dash-illegal.slash/illegal会被净化为dash_illegal.slash_illegal;测试 CollectdReporterTest.java 同时验证了默认 63 与自定义withMaxLength(20)两种截断行为。
底层协议:从 ByteBuffer 到 Collectd 二进制包
PacketWriter是真正的"封包器"。PacketWriter.java 按照 Collectd 二进制协议逐段写入:HOST、TIME、PLUGIN、PLUGIN_INSTANCE、TYPE、TYPE_INSTANCE、INTERVAL元数据段,随后写入VALUES段(含值个数、数据类型标记gauge及 64 位双精度浮点数值)。每个数据包统一分配 1024 字节的缓冲区,数值部分使用小端序写入、头部使用大端序,与 Collectd 服务器端解析规则保持一致。
该实现同时支撑了两种安全协议:
- 签名段(SIGN):
TYPE_SIGN_SHA256 = 0x0200,使用HmacSHA256(password, username || packet)生成 32 字节签名,随原始包一起发送,保证数据完整性与来源真实性; - 加密段(ENCRYPT):
TYPE_ENCR_AES256 = 0x0210,先用 SHA-1 对数据包求指纹并与包体拼接,再用AES_256/OFB/NoPadding以sha256(password)为密钥加密,并携带 16 字节随机 IV 与用户名,防止传输中被窃听。
安全上报:NONE / SIGN / ENCRYPT 三级防护
SecurityLevel.java 定义了三个枚举值,对应无保护、签名、加密三种策略:
CollectdReporter.forRegistry(registry) .withHostName("app-server-01") .withSecurityLevel(SecurityLevel.ENCRYPT) .withUsername("metrics") .withPassword("s3cret") .build(sender) .start(30, TimeUnit.SECONDS);源码在build()阶段强制执行校验:只要securityLevel != NONE,username与password就必须非空,否则抛出IllegalArgumentException(CollectdReporter.java)。此外模块还提供 SecurityConfiguration.java 作为凭据的封装载体,测试类 CollectdReporterSecurityTest.java 与 PacketWriterTest.java 分别验证了签名/加密包的构造与接收方解析。
测试验证与进一步探索
该模块的测试目录(metrics-collectd/src/test/java/com/codahale/metrics/collectd)提供了一个基于jcollectd的本地 UDP 接收器Receiver,通过CollectdReporterTest等用例在真实端口上完成端到端验证,覆盖:各类型 Gauge 上报、布尔 Gauge 转换、计数器、Meter 速率、Histogram/Timer 全字段、禁用属性、命名净化与自定义最大长度。
如需在本地跑通完整链路,可参照测试的用法:在本机用Receiver(监听 25826 端口)模拟 Collectd 服务器,再以new Sender("localhost", 25826)构建 reporter 并调用report()或start(...)观察收包情况。生产环境中,只需将Sender指向真实的 Collectd 节点(默认网络协议端口为 2007),并确保 Collectd 开启对应的网络插件与安全配置即可持续接收来自 JVM 与应用的实时指标。
- 可观测性
- 后端
【免费下载链接】metrics
:chart_with_upwards_trend: Capturing JVM- and application-level metrics. So you know what's going on.
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考