RabbitMQ Java 客户端指标,使用 Micrometer 和 Datadog
在这篇文章中,我们将介绍 RabbitMQ Java 客户端库如何收集运行时指标,并将它们发送到监控系统,如 JMX 和 Datadog。
RabbitMQ Java 客户端中的 Micrometer
Java 客户端从 4.6.0 和 5.2.0 版本开始提供对 Micrometer 的支持。这带来了什么好处?Micrometer 是一个指标外观:应用程序可以使用 Micrometer API 进行指标收集,并选择将这些指标发送到不同的后端,如 JMX、Prometheus、Netflix Atlas、CloudWatch、Datadog、Graphite、Ganglia 等。接下来,让我们看看 RabbitMQ Java 客户端的用户如何从 Micrometer 中获益。
我们可以从收集 Java 客户端指标开始,并使用 Micrometer 在 JMX 上公开它们
MeterRegistry jmxRegistry = new JmxMeterRegistry(JmxConfig.DEFAULT, Clock.SYSTEM);
ConnectionFactory connectionFactory = new ConnectionFactory();
MicrometerMetricsCollector metricsCollector = new MicrometerMetricsCollector(
jmxRegistry, "rabbitmq.client"
);
connectionFactory.setMetricsCollector(metricsCollector);
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
String queue = channel.queueDeclare().getQueue();
channel.basicConsume(queue, true, (ctag, msg) -> { }, (ctag) -> { });
executor.submit(() -> {
Random random = new Random();
while (true) {
Thread.sleep(random.nextInt(100));
channel.basicPublish("", queue, null, "".getBytes());
}
});
然后可以在 VisualVM 中检查这些指标

与我们在 之前的文章中使用 Dropwizard Metrics 所做的相比,并没有太多新内容。
但是 Micrometer 可以轻松地为与 JVM 进程相关的指标带来价值。我们只需将适当的 MeterBinder
绑定到 JMX meter registry
MeterRegistry jmxRegistry = new JmxMeterRegistry(JmxConfig.DEFAULT, Clock.SYSTEM);
// JVM and system metrics:
new ClassLoaderMetrics().bindTo(jmxRegistry);
new JvmMemoryMetrics().bindTo(jmxRegistry);
new JvmGcMetrics().bindTo(jmxRegistry);
new ProcessorMetrics().bindTo(jmxRegistry);
new JvmThreadMetrics().bindTo(jmxRegistry);
ConnectionFactory connectionFactory = new ConnectionFactory();
MicrometerMetricsCollector metricsCollector = new MicrometerMetricsCollector(
jmxRegistry, "rabbitmq.client"
);
connectionFactory.setMetricsCollector(metricsCollector);
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
String queue = channel.queueDeclare().getQueue();
channel.basicConsume(queue, true, (ctag, msg) -> { }, (ctag) -> { });
executor.submit(() -> {
Random random = new Random();
while (true) {
Thread.sleep(random.nextInt(100));
channel.basicPublish("", queue, null, "".getBytes());
}
});
然后新的指标就会显示在 JVisualVM 中,有很多指标

在实践中,应用程序通常有多个实例同时运行,有时分布在不同的数据中心。我们如何识别在给定数据中心运行的实例,并使监控系统意识到此信息?Micrometer 提供了指标标签:只需将数据中心信息添加到指标收集器即可。我们可以调整我们的示例程序,并迭代数据中心列表来模拟分布式实例。我们使用 dc
标签来表示数据中心信息,并添加一个 host
标签
for (String dc : new String[] {"us", "europe", "asia"}) {
Tags tags = Tags.of("host", hostname, "dc", dc);
MeterRegistry jmxRegistry = new JmxMeterRegistry(JmxConfig.DEFAULT, Clock.SYSTEM);
new ClassLoaderMetrics(tags).bindTo(jmxRegistry);
new JvmMemoryMetrics(tags).bindTo(jmxRegistry);
new JvmGcMetrics(tags).bindTo(jmxRegistry);
new ProcessorMetrics(tags).bindTo(jmxRegistry);
new JvmThreadMetrics(tags).bindTo(jmxRegistry);
ConnectionFactory connectionFactory = new ConnectionFactory();
MicrometerMetricsCollector metricsCollector = new MicrometerMetricsCollector(
jmxRegistry, "rabbitmq.client", tags
);
connectionFactory.setMetricsCollector(metricsCollector);
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
String queue = channel.queueDeclare().getQueue();
channel.basicConsume(queue, true, (ctag, msg) -> { }, (ctag) -> { });
executor.submit(() -> {
Random random = new Random();
int offset = dc.length() * 10;
while (true) {
Thread.sleep(random.nextInt(100) + offset);
channel.basicPublish("", queue, null, "".getBytes());
}
});
}
让我们看看现在在 VisualVM 中是什么样子

现在指标列表变得非常长,因为 Micrometer 将标签/键值对集合扁平化,并将它们添加到名称中。这是因为 JMX 是一个分层监控系统,它不支持维度。这使得我们很难作为一个整体来推理我们的指标,跨越我们所有的实例和数据中心。在现实生活中情况会更糟:这里我们在同一个 JVM 进程中模拟应用程序的不同实例,但在实际系统中,我们每个进程都会有一个标签页,更难推理。
幸运的是,Micrometer 利用了维度监控系统。想象一下,我们可以看到不同实例的聚合指标,并深入到特定的数据中心或给定的主机。
Datadog 就是这样一个系统,Micrometer 开箱即用地支持它。我们可以使用 DatadogMeterRegistry
并继续使用 JMX,这要归功于 CompositeMeterRegistry
for (String dc : new String[] {"us", "europe", "asia"}) {
CompositeMeterRegistry compositeMeterRegistry = new CompositeMeterRegistry();
MeterRegistry datadogRegistry = new DatadogMeterRegistry(config, Clock.SYSTEM);
MeterRegistry jmxRegistry = new JmxMeterRegistry(JmxConfig.DEFAULT, Clock.SYSTEM);
Tags tags = Tags.of("host", hostname, "dc", dc);
new ClassLoaderMetrics(tags).bindTo(compositeMeterRegistry);
new JvmMemoryMetrics(tags).bindTo(compositeMeterRegistry);
new JvmGcMetrics(tags).bindTo(compositeMeterRegistry);
new ProcessorMetrics(tags).bindTo(compositeMeterRegistry);
new JvmThreadMetrics(tags).bindTo(compositeMeterRegistry);
compositeMeterRegistry.add(datadogRegistry);
compositeMeterRegistry.add(jmxRegistry);
ConnectionFactory connectionFactory = new ConnectionFactory();
MicrometerMetricsCollector metricsCollector = new MicrometerMetricsCollector(
compositeMeterRegistry, "rabbitmq.client", tags
);
connectionFactory.setMetricsCollector(metricsCollector);
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
String queue = channel.queueDeclare().getQueue();
channel.basicConsume(queue, true, (ctag, msg) -> { }, (ctag) -> { });
executor.submit(() -> {
Random random = new Random();
int offset = dc.length() * 10;
while (true) {
Thread.sleep(random.nextInt(100) + offset);
channel.basicPublish("", queue, null, "".getBytes());
}
});
}
底层发生了什么?Micrometer 收集指标,并每 10 秒通过 HTTPS 将它们发送到 Datadog 服务。请注意,您需要一个 Datadog API 密钥才能使其工作,它用于 Datadog registry 配置中。主机和指标应该会显示在您的 Datadog Web UI 中,您可以轻松地为您的 RabbitMQ Java 客户端实例构建一个仪表板

很棒,不是吗?
更进一步
在单一级别(例如,特定的库,如 RabbitMQ Java 客户端)收集指标只是深入了解整个面向服务的系统的第一步。
Datadog 还提供 对 RabbitMQ 节点和集群的支持。节点需要安装 Datadog 代理,该代理将连接到 RabbitMQ 管理插件以收集指标。Datadog 工程师撰写了 一系列 博客文章,涵盖了 如何监控 RabbitMQ。对于任何对 RabbitMQ 运维感兴趣的人来说,这是一篇推荐阅读的文章。
回到客户端级别,Spring Boot 是用 Java 编写 RabbitMQ 应用程序的一种流行方式。Micrometer 是支持 Spring Boot 2.0 指标系统的库。RabbitMQ Java 客户端指标收集是 自动配置的,开发人员甚至不需要注册任何 MetricsCollector
。
在微服务和 IoT 工作负载的世界中,应用程序实例像雨后春笋般涌现,我们希望这能让您更容易了解使用 RabbitMQ 进行消息传递的基于 Java 的应用程序的运行情况,这要归功于这些指标!