Apache Druid Ambari Metrics Emitter 实战:将 Druid 集群指标接入 Ambari Metrics 收集器
2026/9/23 14:36:42 网站建设 项目流程

Apache Druid Ambari Metrics Emitter 实战:将 Druid 集群指标接入 Ambari Metrics 收集器

【免费下载链接】druidApache Druid: a high performance real-time analytics database.项目地址: https://gitcode.com/gh_mirrors/druid6/druid

本文围绕 Apache Druid 的社区扩展ambari-metrics-emitter展开,讲解如何把 Druid 各服务(Broker、Historical、Overlord 等)产生的运行时指标以批量(pickled)方式发送到 Ambari Metrics Collector(AMS),并重点剖析其中的事件转换器(Druid to Ambari Timeline Metric Converter)与指标命名规范。读完本文,你将掌握该扩展的完整配置方法、allwhiteList两种转换器的取舍、白名单映射文件的自定义格式,以及底层源码实现的关键细节,可直接在真实集群中落地使用。

扩展的加载与启用

ambari-metrics-emitter是一个独立的 Apache Druid 扩展(extension),源码位于仓库 extensions-contrib/ambari-metrics-emitter,其 Maven 坐标为org.apache.druid.extensions.contrib:ambari-metrics-emitter,并且直接依赖org.apache.ambari:ambari-metrics-common(见 pom.xml),因此目标环境中需要有 Ambari Metrics 相关的服务端组件。

使用该扩展的第一步是在 Druid 的扩展加载列表中加入ambari-metrics-emitter,具体方式参见官方加载扩展的说明文档 加载扩展。例如在common.runtime.properties中配置:

druid.extensions.loadList=[..., "ambari-metrics-emitter"] druid.emitter=ambari-metrics

其中druid.emitter用于指定当前进程实际激活的 emitter 名称(参考仓库示例配置 common.runtime.properties 中druid.emitter=noop的写法),此处替换为ambari-metrics后,扩展模块 AmbariMetricsEmitterModule 会通过 Guice 以@Named("ambari-metrics")的名字注册并托管一个AmbariMetricsEmitter实例,其生命周期由@ManageLifecycle管理。

工作原理:批量发送与内部队列

该扩展的本质是一个 DruidEmitter实现。核心类 AmbariMetricsEmitter 继承自 Ambari 的AbstractTimelineMetricsSink并实现Emitter接口。从源码可以看到其运行模型:

  • 每个ServiceMetricEvent被事件转换器转换为一个TimelineMetric后,放入一个容量为maxQueueSizeLinkedBlockingQueue队列;
  • 一个大小为 2 的定时线程池按flushPeriod周期执行ConsumerRunnable,从队列中批量取出事件,凑满batchSize个就调用emitMetrics()发送一次(即文档所说的 "pickled, i.e., batched"),队列清空时若还有剩余不足一批的事件也会被发送;
  • 发送目标 URI 由源码collectorURI构造逻辑可见,形如协议://主机:端口/ws/v1/timeline/metricsWS_V1_TIMELINE_METRICS/ws/v1/timeline/metrics),这一点也被单元测试 AmbariMetricsEmitterTest 验证:http://myHost:8080/ws/v1/timeline/metrics

此外,该实现明确忽略 Zookeeper 回退getZookeeperQuorum()返回null),并关闭了 host 内存聚合isHostInMemoryAggregationEnabled()返回false),因此所有 Collector 连接参数都必须通过配置文件显式给出。

完整配置参数详解

所有配置项统一以druid.emitter.ambari-metrics为前缀,对应的配置类为 AmbariMetricsEmitterConfig。完整参数如下:

property说明必填?默认值
druid.emitter.ambari-metrics.hostnameAmbari Metrics Server(Collector)的主机名。源码中通过Preconditions.checkNotNull强制非空,且由于禁用了 ZK 回退,该值必须直接可访问
druid.emitter.ambari-metrics.portAmbari Metrics Server 的端口
druid.emitter.ambari-metrics.protocol发送指标使用的协议,取值为httphttpshttp
druid.emitter.ambari-metrics.trustStorePath使用https时 trustStore 的文件路径
druid.emitter.ambari-metrics.trustStoreType使用https时 trustStore 的类型
druid.emitter.ambari-metrics.trustStorePassword使用https时 trustStore 的密码
druid.emitter.ambari-metrics.batchSize一次批量发送的事件个数100
druid.emitter.ambari-metrics.eventConverterDruid 事件到 Ambari Timeline Metric 的过滤与转换器(见下文)
druid.emitter.ambari-metrics.flushPeriod队列刷盘周期,单位毫秒1 分钟
druid.emitter.ambari-metrics.maxQueueSize缓冲事件的队列最大容量MAX_INT
druid.emitter.ambari-metrics.alertEmitters需要转发告警(Alert)事件的 emitter 名称列表空列表(不转发)
druid.emitter.ambari-metrics.emitWaitTime入队时的等待时间,单位毫秒;超时后事件会被丢弃0
druid.emitter.ambari-metrics.waitForEventTime消费者从队列取事件时的最长等待时间,单位毫秒1000(1 秒)

说明:原文档参数表中trustStorePassword一行误写为trustStoreType,本文按 AmbariMetricsEmitterConfig 中的实际@JsonProperty("trustStorePassword")予以修正。

上述默认值均可从 AmbariMetricsEmitterConfig 的常量定义中得到印证:DEFAULT_BATCH_SIZE = 100DEFAULT_FLUSH_PERIOD_MILLIS = 1 分钟DEFAULT_GET_TIMEOUT_MILLIS = 1 秒DEFAULT_PROTOCOL = "http"。其中hostnameporteventConverter三者均通过Preconditions.checkNotNull强制校验,缺失任一配置都会导致启动失败。

一个最小可用的配置示例(写入common.runtime.properties):

druid.emitter=ambari-metrics druid.emitter.ambari-metrics.hostname=ams-host.example.com druid.emitter.ambari-metrics.port=6188 druid.emitter.ambari-metrics.protocol=http druid.emitter.ambari-metrics.eventConverter={"type":"whiteList", "namespacePrefix":"druid", "appName":"druid"}

Ambari Metrics 指标命名规范

扩展将转换后的指标以 Timeline Metric 的形式写入 Ambari Metrics,其路径(metric name)遵循如下 schema:

<namespacePrefix>.[<druid service name>].[<druid hostname>].<druid metrics dimensions>.<druid metrics name>

以文档给出的示例druid.historical.hist-host1:8080.MyDataSourceName.GroupBy.query/time为例,逐段拆解:

  • druid—— namespace prefix(命名空间前缀,由用户自行定义);
  • historical—— druid service name(产生指标的服务,如 historical、broker、overlord);
  • hist-host1:8080—— druid hostname(该服务所在节点的主机名与端口);
  • MyDataSourceName—— 某个 dimension(维度)的值,此处为数据源名;
  • GroupBy—— 另一个 dimension 的值,此处为查询类型;
  • query/time—— 指标名。

命名是否规范直接决定了后续在 Ambari Metrics 中对指标的分类、检索与告警是否正确。需要特别留意的是,指标名中不允许出现点号或空白,源码中的 AmbariMetricsEmitter#sanitize 会把其中的.和空白统一替换为_,因此在设计 namespacePrefix 与维度取值时应避免歧义字符,防止不同指标被合并成同名。

事件转换器(Event Converter)

转换器接口 DruidToTimelineMetricConverter 定义了一个方法druidEventToTimelineMetric(ServiceMetricEvent):它既充当过滤器(对不需要发送的事件返回null),也负责定义 Druid 事件维度到 Ambari 指标名的映射关系。该接口通过 Jackson 多态注册了两种实现,type分别取allwhiteList;值得注意的是,当type字段缺失时,默认实现为whiteList转换器。

Send-All 转换器(type: all)

对应实现 SendAllTimelineEventConverter。它会发送 Druid 服务的全部指标事件,并保留所有维度,维度按维度名字典序排列后拼入路径:

<namespacePrefix>.[<druid service name>].[<druid hostname>].<dimensions values ordered by dimension's name>.<metric>

其中<namespacePrefix>.[<druid service name>].[<druid hostname>].这段前缀由用户控制。配置示例:

druid.emitter.ambari-metrics.eventConverter={"type":"all", "namespacePrefix": "druid.test", "appName":"druid"}

appName会被写入 Timeline Metric 的AppId字段(源码中metric.setAppId(appName)),用于在 Ambari Metrics 侧标记应用名,默认值为druid

White-list 转换器(type: whiteList)

对应实现 WhiteListBasedDruidToTimelineEventConverter。它只发送白名单内的指标与维度,指标名称为:

<namespacePrefix>.<druid service name>.<white-listed dimensions>.<metric>

all转换器不同,这里维度的顺序不是按名字排序,而是严格遵循白名单映射中维度的声明顺序(源码getOrderedDimValues()whiteListDimsMapper中列表的顺序取值)。

该转换器内置一份默认白名单映射,位于仓库资源文件 defaultWhiteListMap.json。源码readMap()显示:当未提供mapPath时,从 classpath 加载这份默认映射;提供了mapPath时则从该路径读取用户自定义的 JSON 文件。配置示例:

druid.emitter.ambari-metrics.eventConverter={"type":"whiteList", "namespacePrefix": "druid.test", "ignoreHostname":true, "appName":"druid", "mapPath":"/pathPrefix/fileName.json"}

注意:文档示例中的ignoreHostname参数在当前源码的转换器中并未作为属性使用,实际生效的核心参数为namespacePrefixappNamemapPath

Druid 会产生海量指标,官方强烈建议使用whiteList转换器,以控制发送到 Ambari Metrics 的数据量与存储成本,避免无关指标干扰监控和告警。

自定义白名单映射文件

白名单映射文件是一个 JSON 对象:key 是 Druid 指标名(或指标名前缀),value 是对应维度名的列表,维度名的顺序决定最终指标路径中维度的出现顺序。

匹配规则在源码getPrefixKey()中实现:先做精确匹配(whiteList.containsKey(key)),若未命中,则在排序映射表中找到小于该指标名的最大前缀键,并校验该指标名是否以此前缀开头(key.startsWith(headMap.lastKey()))。也就是说,白名单支持"前缀匹配",例如配置query即可覆盖query/timequery/cpu/time等所有以query开头的指标。

仓库自带的 defaultWhiteListMap.json 内容如下,可作为自定义映射的参考模板:

{ "ingest/events": ["dataSource"], "ingest/handoff/failed": ["dataSource"], "ingest/persists": ["dataSource"], "ingest/rows/output": ["dataSource"], "ingest/merge": ["dataSource"], "jvm/gc": [], "jvm/mem": ["memKind"], "query/cpu/time": ["dataSource", "type"], "query/node/time": ["dataSource", "type"], "query/node/ttfb": ["dataSource", "type"], "query/partial/time": ["dataSource", "type"], "query/segment/time": ["dataSource", "type"], "query/segmentAndCache/time": ["dataSource", "type"], "query/time": ["dataSource", "type"], "query/wait/time": ["dataSource", "type"], "segment/count": ["dataSource"], "segment/dropQueue/count": [], "segment/loadQueue/count": [], "segment/loadQueue/failed": [], "segment/loadQueue/size": [], "segment/scan/pending": [], "segment/scan/active": [], "segment/size": ["dataSource"], "segment/usedPercent": ["dataSource"], "segment/added/bytes": ["dataSource"], "segment/nuked/bytes": ["dataSource"] }

由映射可见:jvm/gcsegment/loadQueue/count等指标不带维度;query/time等查询类指标保留dataSourcetype(查询类型)两个维度,从而在 Ambari Metrics 中生成诸如<prefix>.<service>.<dataSource>.<type>.query/time的指标路径。维度取值为集合类型(如多值维度)时,源码getOrderedDimValues()会取集合的第一个元素作为维度值。

参数调优与运维建议

结合 AmbariMetricsEmitter 的实现,以下几点直接影响稳定性与数据完整性:

  • 队列容量与丢事件:当队列已满时,emit()eventsQueue.offer(..., emitWaitTime, MILLISECONDS)会失败并丢弃事件,同时以countLostEvents计数,每累计 1000 个丢失事件打印一条 error 日志。若日志频繁出现 "Lost total of ... events because of emitter queue is full",应调大maxQueueSize,或缩短flushPeriod/ 增大batchSize以加快消费。
  • 批量与周期batchSize控制每批发送的指标个数(默认 100),flushPeriod控制消费线程的调度周期(默认 1 分钟)。两者共同决定指标到达 AMS 的实时性,追求更实时监控时应适当调小flushPeriod
  • 告警转发emit()对不同类型的 Druid 事件做了分流——ServiceMetricEvent走转换与入队;AlertEvent转发给alertEmitters列表中指定的其他 emitter(通过 Guice 按名字查找注入);SegmentMetadataEvent被直接忽略;未知事件类型则抛出ISE。因此需要告警能力时,应在alertEmitters中列出如logging等已配置的 emitter 名称。
  • HTTPS 与 trustStore:当protocol=https时,start()中会调用loadTruststore(trustStorePath, trustStoreType, trustStorePassword)加载证书库,三个 trustStore 参数需配套填写完整。
  • 优雅关闭close()会先执行flush()(等待队列清空,超时上限为 60 秒),再关闭线程池,保证进程退出前尽量不丢数据。

源码级实现要点速览

如果你希望进一步深入该扩展的底层行为,以下路径值得精读:

  • 发送主流程与队列模型:AmbariMetricsEmitter.java(emit()ConsumerRunnableflush()sanitize());
  • 配置解析与默认值:AmbariMetricsEmitterConfig.java;
  • 转换器接口与类型注册:DruidToTimelineMetricConverter.java;
  • 全量转换实现:SendAllTimelineEventConverter.java;
  • 白名单转换实现(含前缀匹配与维度排序):WhiteListBasedDruidToTimelineEventConverter.java;
  • 默认白名单:defaultWhiteListMap.json;
  • 单元测试(覆盖 URI 构造、协议、端口、ZK 禁用等行为):AmbariMetricsEmitterTest.java。

总体而言,ambari-metrics-emitter为已有 Ambari 监控体系的 Druid 集群提供了一条低成本的指标接入通道:加载扩展、配置 Collector 地址与转换器即可完成对接。生产环境请务必采用whiteList转换器并按需裁剪默认白名单,以最小的指标量换取对关键查询、摄取与 Segment 负载的完整可观测性。

【免费下载链接】druidApache Druid: a high performance real-time analytics database.项目地址: https://gitcode.com/gh_mirrors/druid6/druid

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询