在Azure中用Telegraf和Grafana监控Apache Kafka的方法

406 阅读7分钟

监控有助于推动生产力,提高服务的可用性。Apache Kafka也不例外。随着Apache Kafka越来越受欢迎,并成为微服务架构中分布式消息传递的事实标准,对于DevOps工程师来说,了解一些关键指标是非常重要的,比如 - 消费者滞后?复制不足的分区?或者你的Kafka集群坏了吗? - 以便拥有一个高度可靠和可用的Kafka集群,并保持对数据和应用健康的关注。

监控Apache Kafka的工具

有很多工具可以用来监控Apache Kafka,包括。

  • LinkedIn Burrow
  • 雅虎Kafka管理器
  • KafDrop
  • Confluent控制中心 - 如果你使用Confluent Kafka和其他许多工具的话

我们还可以使用Java管理扩展(JMX)与流行的JMX客户端(如Prometheus、Telegraf等)来监控Apache Kafka。

在这篇文章中,我将通过使用Telegraf和Grafana监控部署在Azure云上的Apache Kafka。 请注意,Azure也提供了使用HDInsight Kafka的管理Kafka。 但如果你想建立一个与云无关的Apache Kafka集群,那么为该集群提供一个监控解决方案是很重要的。在这篇文章中,我将指导你安装、设置和运行使用Telegraf代理的监控解决方案,以及Grafana、Jolokia代理、Azure Monitor。因此,我们会在Grafana这边的仪表盘上看到系统、Kafka Broker、Kafka Consumer和Kafka Producer的指标。

让我们来看看这些组件中的一些。

Jolokia代理

Jolokia是一个基于JMX-HTTP代理的方法,支持许多平台。除了基本的JMX操作外,它还通过批量请求和细粒度的安全策略等独特的功能增强了JMX远程。

Telegraf

Telegraf是一个轻量级的服务器进程,能够收集、处理和汇总指标。Telegraf是一个插件驱动的服务器代理,用于收集和发送来自数据库、系统和物联网传感器的指标和事件。

格拉法纳

Grafana是一个流行的全功能的开源前台仪表盘解决方案。这是一个可视化工具,旨在与各种数据源如Graphite、InfluxDB、Elasticsearch等合作。这个解决方案可以为用户快速、轻松地开发仪表盘。

Azure监控器

Azure监控器从各种企业内部和Azure来源收集监控遥测数据。Azure监控器允许收集细化的性能和利用率数据、活动和诊断日志,以及来自Azure资源的通知。

构建监控系统架构

这是一个高层次的架构图,为Azure虚拟机上托管的Apache Kafka构建一个监控解决方案。

在这里,我创建了两个子网--一个用于Kafka集群,另一个用于设置监控解决方案,以隔离访问责任。当你在一个单独的子网中设置监控解决方案时,请确保你已经更新了子网各自NSG中的入站/出站规则,以便进行适当的通信。监控子网将有一个虚拟机来托管Grafana和Telegraf代理。

为了处理HA,你需要创建2个VM,并使用Azure应用网关来平衡负载。让我们来看看这个设置。

1.安装Jolokia

  • 这里下载最新版本的Jolokia JVM-Agent。( jolokia-jvm-1.7.1-agent.jar版本是目前最新的)
  • 将jolokia-jvm-1.7.1-agent.jar保存在Kafka服务器的/opt/kafka/libs或任何位置。
  • 配置Kafka以使用Jolokia。

在kafka-server-start.sh中添加以下片段。

export JMX_PORT=9999 export RMI_HOSTNAME=<KAFKA_SERVER_IP_ADDRESS> export KAFKA_JMX_OPTS="-javaagent:/opt/kafka/libs/jolokia-agent.jar=port=8778,host=$RMI_HOSTNAME -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=$RMI_HOSTNAME -Dcom.sun.management.jmxremote.rmi.port=$JMX_PORT"
  • 重新启动Kafka服务。
  • 通过运行验证你可以访问端口8778的Jolokia。

Curl -http://KAFKA_SERVER_IP_ADDRESS:8778/jolokia/version

2.安装Telegraf代理

这个集成使用Jolokia的Telegraf输入插件来通过JMX获得Kafka指标。

你可以从这里下载最新的Telegraf代理。

3. 配置Jolokia输入插件

/etc/telegraf/telegraf.d ,创建一个名为jolokia-kafka.conf 的文件,并输入以下内容。

注意:将KAFKA_SERVER_IP_ADDRESS替换为Kafka服务器IP地址。

## Read JMX metrics through Jolokia
 [[inputs.jolokia2_agent]]
   ## An array of Kafka servers URI to gather stats.
   urls = ["http://KAFKA_SERVER_IP_ADDRESS:8778/jolokia"]
   name_prefix = "kafka."

   ## List of metrics collected on above servers
   [[inputs.jolokia2_agent.metric]]
     name = "heap_memory_usage"
     mbean  = "java.lang:type=Memory"
     paths = ["HeapMemoryUsage"]

   ## This collects thread counts metrics.
   [[inputs.jolokia2_agent.metric]]
     name = "thread_count"
     mbean  = "java.lang:type=Threading"
     paths = ["TotalStartedThreadCount","ThreadCount","DaemonThreadCount","PeakThreadCount"]

   ## This collects garbage collection metrics.
   [[inputs.jolokia2_agent.metric]]
     name = "garbage_collector"
     mbean  = "java.lang:type=GarbageCollector,name=*"
     paths = ["CollectionCount","CollectionTime"]
     tag_keys = ["name"]

   # Kafka Server Broker Topic Metrics
   [[inputs.jolokia2_agent.metric]]
     name = "server_brokertopics_messagesinpersec"
     mbean  = "kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec"
   [[inputs.jolokia2_agent.metric]]
     name = "server_brokertopics_bytesinpersec"
     mbean  = "kafka.server:type=BrokerTopicMetrics,name=BytesInPerSec"
   [[inputs.jolokia2_agent.metric]]
     name = "server_brokertopics_bytesoutpersec"
     mbean  = "kafka.server:type=BrokerTopicMetrics,name=BytesOutPerSec"

   # Kafka Server Request Handler Metrics
   [[inputs.jolokia2_agent.metric]]
     name = "server_requesthandler_avgidlepct"
     mbean  = "kafka.server:name=RequestHandlerAvgIdlePercent,type=KafkaRequestHandlerPool"

   # Kafka Server Delayed Operation Purgatory Metrics
   [[inputs.jolokia2_agent.metric]]
     name = "server_delayedoperationpugatory_fetch"
     mbean  = "kafka.server:type=DelayedOperationPurgatory,name=PurgatorySize,delayedOperation=Fetch"
   [[inputs.jolokia2_agent.metric]]
     name = "server_delayedoperationpugatory_produce"
     mbean  = "kafka.server:type=DelayedOperationPurgatory,name=PurgatorySize,delayedOperation=Produce"

   # Kafka Server Replica Fetcher Manager Metrics
   [[inputs.jolokia2_agent.metric]]
     name = "server_replicafetchmanager.maxlag"
     mbean  = "kafka.server:type=ReplicaFetcherManager,name=MaxLag,clientId=Replica"

   # Kafka Server Replica Manager Metrics
   [[inputs.jolokia2_agent.metric]]
     name = "server_replicamanager_underreplicated"
     mbean  = "kafka.server:type=ReplicaManager,name=UnderReplicatedPartitions"
   [[inputs.jolokia2_agent.metric]]
     name = "server_replicamanager_partitioncount"
     mbean  = "kafka.server:type=ReplicaManager,name=PartitionCount"
   [[inputs.jolokia2_agent.metric]]
     name = "server_replicamanager_leadercount"
     mbean  = "kafka.server:type=ReplicaManager,name=LeaderCount"
   [[inputs.jolokia2_agent.metric]]
     name = "server_replicamanager_isrshrinkspersec"
     mbean  = "kafka.server:type=ReplicaManager,name=IsrShrinksPerSec"
   [[inputs.jolokia2_agent.metric]]
     name = "server_replicamanager_isrexpandspersec"
     mbean  = "kafka.server:type=ReplicaManager,name=IsrExpandsPerSec"

   # Kafka Network Request Metrics
   [[inputs.jolokia2_agent.metric]]
     name = "network_requestmetrics_requests_fetch_consumer"
     mbean  = "kafka.network:type=RequestMetrics,name=RequestsPerSec,request=FetchConsumer"
   [[inputs.jolokia2_agent.metric]]
     name = "network_requestmetrics_requests_fetch_follower"
     mbean  = "kafka.network:type=RequestMetrics,name=RequestsPerSec,request=FetchFollower"
   [[inputs.jolokia2_agent.metric]]
     name = "network_requestmetrics_requests_produce"
     mbean  = "kafka.network:type=RequestMetrics,name=RequestsPerSec,request=Produce"
   [[inputs.jolokia2_agent.metric]]
     name = "network_requestmetrics_totaltime_fetch_consumer"
     mbean  = "kafka.network:type=RequestMetrics,name=TotalTimeMs,request=FetchConsumer"
   [[inputs.jolokia2_agent.metric]]
     name = "network_requestmetrics_totaltime_fetch_follower"
     mbean  = "kafka.network:type=RequestMetrics,name=TotalTimeMs,request=FetchFollower"
   [[inputs.jolokia2_agent.metric]]
     name = "network_requestmetrics_totaltime_produce"
     mbean  = "kafka.network:type=RequestMetrics,name=TotalTimeMs,request=Produce"

   # Kafka Network Processor Metrics
   [[inputs.jolokia2_agent.metric]]
     name = "network_processor_avgidlepct"
     mbean  = "kafka.network:name=NetworkProcessorAvgIdlePercent,type=SocketServer"

   # Kafka Controller Metrics
   [[inputs.jolokia2_agent.metric]]
     name = "controller_activecontrollers"
     mbean  = "kafka.controller:type=KafkaController,name=ActiveControllerCount"
   [[inputs.jolokia2_agent.metric]]
     name = "controller_offlinepartitions"
     mbean  = "kafka.controller:type=KafkaController,name=OfflinePartitionsCount"
   [[inputs.jolokia2_agent.metric]]
     name = "controller_stats_leaderelectionrateandtime"
     mbean  = "kafka.controller:type=ControllerStats,name=LeaderElectionRateAndTimeMs"
   [[inputs.jolokia2_agent.metric]]
     name = "controller_stats_uncleanleaderelections"
     mbean  = "kafka.controller:type=ControllerStats,name=UncleanLeaderElectionsPerSec"

   # Zookeeper Metrics
   [[inputs.jolokia2_agent.metric]]
     name = "zookeeper_disconnects"
     mbean  = "kafka.server:type=SessionExpireListener,name=ZooKeeperDisconnectsPerSec"
     paths = ["Count","OneMinuteRate","FiveMinuteRate","FifteenMinuteRate","MeanRate"]
   [[inputs.jolokia2_agent.metric]]
     name = "zookeeper_sync_connects"
     mbean  = "kafka.server:type=SessionExpireListener,name=ZooKeeperSyncConnectsPerSec"
     paths = ["Count","OneMinuteRate","FiveMinuteRate","FifteenMinuteRate","MeanRate"]
   [[inputs.jolokia2_agent.metric]]
     name = "zookeeper_auth_failures"
     mbean  = "kafka.server:type=SessionExpireListener,name=ZooKeeperAuthFailuresPerSec"
     paths = ["Count","OneMinuteRate","FiveMinuteRate","FifteenMinuteRate","MeanRate"]
   [[inputs.jolokia2_agent.metric]]
     name = "zookeeper_readonly_connects"
     mbean  = "kafka.server:type=SessionExpireListener,name=ZooKeeperReadOnlyConnectsPerSec"
     paths = ["Count","OneMinuteRate","FiveMinuteRate","FifteenMinuteRate","MeanRate"]
   [[inputs.jolokia2_agent.metric]]
     name = "zookeeper_authentications"
     mbean  = "kafka.server:type=SessionExpireListener,name=ZooKeeperSaslAuthenticationsPerSec"
     paths = ["Count","OneMinuteRate","FiveMinuteRate","FifteenMinuteRate","MeanRate"]
   [[inputs.jolokia2_agent.metric]]
     name = "zookeeper_expires"
     mbean  = "kafka.server:type=SessionExpireListener,name=ZooKeeperExpiresPerSec"
     paths = ["Count","OneMinuteRate","FiveMinuteRate","FifteenMinuteRate","MeanRate"]

将上述指标扩展到所有的JMX指标,以便对Apache Kafka有一个完整的了解。你可以参考Apache Kafka文档中的JMX端点和度量。

4. 配置Azure Monitor输出插件

[[outputs.azure_monitor]]
  ## Timeout for HTTP writes.
  # timeout = "20s"

  ## Set the namespace prefix, defaults to "Telegraf/<input-name>".
   namespace_prefix = "kafka/"

  ## Azure Monitor doesn't have a string value type, so convert string
  ## fields to dimensions (a.k.a. tags) if enabled. Azure Monitor allows
  ## a maximum of 10 dimensions so Telegraf will only send the first 10
  ## alphanumeric dimensions.
  # strings_as_dimensions = false

  ## Both region and resource_id must be set or be available via the
  ## Instance Metadata service on Azure Virtual Machines.
  #
  ## Azure Region to publish metrics against.
  ##   ex: region = "southcentralus"
  # region = ""
  #
  ## The Azure Resource ID against which metric will be logged, e.g.
  ##   ex: resource_id = "/subscriptions/<subscription_id>/resourceGroups/<resource_group>/providers/Microsoft.Compute/virtualMachines/<vm_name>"
  # resource_id = ""

  ## Optionally, if in Azure US Government, China, or other sovereign
  ## cloud environment, set the appropriate REST endpoint for receiving
  ## metrics. (Note: region may be  unused in this context)
  # endpoint_url = "https://monitoring.core.usgovcloudapi.net"

5.重新启动Telegraf

执行 sudo service telegraf重启来重新启动Telegraf代理。

6.创建服务主体/Azure管理身份

为了从Grafana连接Azure Monitor,我们需要在Grafana安装的虚拟机上启用管理身份,使用管理身份在Grafana中配置Azure Monitor。这将简化数据源的配置,需要对数据源进行安全认证,而不必通过Azure AD应用注册为每个数据源手动配置凭证。

你也可以在Azure AD中创建一个应用注册和服务主体,以验证数据源,并在Grafana配置中配置服务主体。 确保你为服务委托人提供贡献者角色/查看者角色。

7.安装Grafana

关于在支持的操作系统上安装Grafana的各种选项,请参考这里。Grafana有OSS版和企业版,根据你的需要选择。

8**.将Azure Monitor配置为Grafana的数据源**

要为Grafana启用管理身份,请在Grafana服务器配置的[azure]部分设置 managed_identity_enabled标志。

[azure]
    managed_identity_enabled = true

然后,在Azure Monitor数据源配置中,将认证设置为管理身份。该数据源将使用管理身份来验证Azure监控指标、日志和Azure资源图。关于使用管理身份或使用服务委托人的数据源配置,请参考本文档

9. 重启Grafana

配置完成后重启Grafana服务器,现在你应该可以访问Grafana用户界面了。 你也可以通过将Grafana与Azure AD集成,将Grafana的访问权限制在一组用户中。你可以参考这里的文档。

10. 为Kafka关键指标创建监控仪表板

在Grafana中创建关键指标仪表盘,如CPU使用率、JVM使用率、在GC中花费的时间、每个主题中的消息、消费者滞后等。

注意:如果你想在AWS或GCP上建立Apache Kafka集群,我们也可以在其他云供应商如AWS和GCP上使用上述解决方案。Telegraf代理有输出插件支持AWS CloudWatch和GCP云监控(以前被称为Stackdriver)。因此,使用这个插件,你可以将指标数据存储在公共云提供的本地监控解决方案中,并使用Grafana,它对GCP和AWS监控解决方案都有本地支持。