Kafka Monitoring için Grafana ve Prometheus Kullanımı
Monitoring; sistemlerin sağlıklı çalışıp çalışmadığını anlamak, hataları tespit etmek ve performansı ölçmek için hayati öneme sahiptir. Bu yazıda, popüler açık kaynak kodlu izleme (monitoring) araçları olan Prometheus ve Grafana’nın nasıl kullanılacağından bahsedecek ve Kafka’nın izlenmesiyle ilgili docker ortamında bir örnek yapacağız.
Prometheus
Prometheus, açık kaynak kodlu bir izleme ve uyarı sistemi olup, ölçüm verilerini birleştirmek ve işlemek için çok boyutlu veri modeli ve esnek sorgu diline sahiptir. Hedeflerini, servis keşif mekanizması veya statik yapılandırma ile belirleyebilir ve bu hedeflerden zaman serisi verilerini toplar. Bu veriler, Grafana gibi görselleştirme araçlarıyla incelenebilir.
Grafana
Grafana, çok çeşitli veri kaynaklarından veri görselleştirme ve analiz için kullanılan açık kaynaklı bir platformdur. Grafana, grafikler, histogramlar ve ölçekler oluşturarak veri analizi yapabilir. Ayrıca, kullanıcıların belirli metrikleri ve verileri izlemelerine olanak tanıyan bir uyarı özelliği de vardır.
Araçları tanıdığımıza göre uygulama kısmına geçebiliriz.
Demo
Uygulamayı Docker ortamında gerçekleştireceğiz. Kullandığımız docker-compose
dosyasını aşağıda paylaşıyorum. Proje dosyalarına GitHub üzerinden de erişebilirsiniz.
version: "3.8" services: grafana: image: "grafana/grafana:9.5.12" ports: - "3000:3000" environment: GF_PATHS_DATA: /var/lib/grafana GF_SECURITY_ADMIN_PASSWORD: admin container_name: grafana depends_on: - prometheus networks: - monitoring prometheus: image: "prom/prometheus:v2.47.1" ports: - "9090:9090" volumes: - ./etc/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml command: "--config.file=/etc/prometheus/prometheus.yml" container_name: prometheus networks: - monitoring jmx-kafka101: image: "kayademirseda/jmx_exporter:1.0" ports: - "5556:5556" environment: CONFIG_YML: "/etc/jmx_exporter/config.yml" JVM_OPTS: ${PROMETHEUS_JMX_AGENT_JVM_OPTS} volumes: - ./etc/jmx_exporter/config_kafka101.yml:/etc/jmx_exporter/config.yml container_name: jmx-kafka101 depends_on: - kafka101 networks: - monitoring jmx-kafka102: image: "kayademirseda/jmx_exporter:1.0" ports: - "5557:5556" environment: CONFIG_YML: "/etc/jmx_exporter/config.yml" JVM_OPTS: ${PROMETHEUS_JMX_AGENT_JVM_OPTS} volumes: - ./etc/jmx_exporter/config_kafka102.yml:/etc/jmx_exporter/config.yml container_name: jmx-kafka102 depends_on: - kafka102 networks: - monitoring jmx-kafka103: image: "kayademirseda/jmx_exporter:1.0" ports: - "5558:5556" environment: CONFIG_YML: "/etc/jmx_exporter/config.yml" JVM_OPTS: ${PROMETHEUS_JMX_AGENT_JVM_OPTS} volumes: - ./etc/jmx_exporter/config_kafka103.yml:/etc/jmx_exporter/config.yml container_name: jmx-kafka103 depends_on: - kafka103 networks: - monitoring kafka101: image: "kayademirseda/kafka:1.0" ports: - "19092:9092" - "9991:9991" container_name: kafka101 volumes: - ./etc/kafka/config/kafka1/server.properties:/kafka/config/server.properties - ./etc/kafka/data/kafka1/:/data/kafka/ environment: JMX_PORT: 9991 deploy: resources: limits: memory: ${KAFKA_BROKER_MEM_LIMIT} networks: - monitoring kafka102: image: "kayademirseda/kafka:1.0" ports: - "29092:9092" - "9992:9992" container_name: kafka102 volumes: - ./etc/kafka/config/kafka2/server.properties:/kafka/config/server.properties - ./etc/kafka/data/kafka2/:/data/kafka/ environment: JMX_PORT: 9992 deploy: resources: limits: memory: ${KAFKA_BROKER_MEM_LIMIT} networks: - monitoring kafka103: image: "kayademirseda/kafka:1.0" ports: - "39092:9092" - "9993:9993" container_name: kafka103 volumes: - ./etc/kafka/config/kafka3/server.properties:/kafka/config/server.properties - ./etc/kafka/data/kafka3/:/data/kafka/ environment: JMX_PORT: 9993 deploy: resources: limits: memory: ${KAFKA_BROKER_MEM_LIMIT} networks: - monitoring networks: monitoring: name: monitoring driver: bridge
Kısaca servislerin yapılandırmasına göz atalım.
- Grafana: Çeşitli veri kaynaklarından verileri görselleştirmek ve analiz etmek için kullanılan bir platformdur. Bu servis 3000 numaralı porttan hizmet verir. Ayrıca, Prometheus servisine bağımlıdır.
- Prometheus: Hedeflerden zaman serisi verilerini toplayan bir izleme ve uyarı sistemidir. Bu servis 9090 numaralı porttan hizmet verir.
- JMX-Kafka101, JMX-Kafka102, JMX-Kafka103: Bu servisler, Prometheus’un Kafka’dan JMX sorgulamalarını gerçekleştirmesini sağlar. Her bir JMX servisi, bir Kafka servisine bağımlıdır ve her biri farklı bir porttan hizmet verir.
- Kafka101, Kafka102, Kafka103: Bu servisler, Kafka brokerleridir.
Docker-compose dosyasını hızlıca inceledik. Şimdi de yapılandırma dosyalarını gözden geçirip görselleştirmeye başlayalım.
JMX ile Prometheus – Kafka Bağlantısını Kurma
Prometheus ile Kafka arasında bağlantı kurmak için jmx-exporter
‘ı kullanıyoruz. Parametrelerin Prometheus tarafından kullanılabilmesi için konfigürasyon dosyasını jmx
konteynerına eklememiz gerekmektedir.
- hostPort: Metriklerin alınacağı hedefin adresi ve portu belirlenir. Bu örnekte, metrikler
kafka101
hostunun9991
portundan alınır. Diğer konteynerlara erişim sağlamak için bu bölümü güncellememiz gerekmektedir. - lowercaseOutputName ve lowercaseOutputLabelNames: Bu ayarlar, metrik ve etiket isimlerinin küçük harfle çıktı olarak verilmesini sağlar. Bu, tutarlılık sağlamak ve karmaşayı azaltmak amacıyla yapılmaktadır.
- whitelistObjectNames ve blacklistObjectNames: Bu bölümler, hangi JMX nesnelerinin (ObjectName) metriklere dahil edileceğini veya hariç bırakılacağını belirtir.
whitelistObjectNames
belirli nesneleri dahil ederken,blacklistObjectNames
belirli nesneleri hariç tutar. Özellikle, belirli bir ön ek veya deseni içeren nesneleri filtrelemek için kullanılır. - rules: Bu bölüm, toplanan metrikler üzerinde işlem yapmak için Prometheus kurallarını tanımlar. Örneğin, metrik isimlerini yeniden adlandırmak, etiketler eklemek veya kaldırmak, metrik değerlerini dönüştürmek veya toplamak gibi işlemler gerçekleştirilebilir. Her kuralın altında, bir
pattern
(desen) belirtilir ve bu desen, eşleşen metrikler üzerinde işlem yapmak için kullanılır. Daha sonra, işlem yapılan metriğin adı (name
) ve etiketleri (labels
) belirtilir. Bu örnekte,Broker Metrics
veJVM Metrics
olmak üzere iki kural tanımlanmıştır. Her bir kuralın altında, desen, metrik adı ve etiketler belirtilmiştir. Örneğin, CPU kullanımı için bir kural tanımlanmış ve bu kuralınpattern
‘ıjava.lang<type=OperatingSystem><ProcessCpuLoad>
olarak belirlenmiştir. Bu desen, CPU kullanım metriklerini temsil eder. Daha sonra, bu metriğin Prometheus’ta nasıl adlandırılacağı (name
) ve hangi etiketlerle (labels
) işaretleneceği belirlenmiştir.
hostPort: kafka101:9991 lowercaseOutputName: true lowercaseOutputLabelNames: true # Whitelist is used to reduce scrapping time whitelistObjectNames: - java.lang:* - kafka.cluster:* - kafka.controller:* - kafka.log:* - kafka.server:type=KafkaServer,name=BrokerState - kafka.server:type=KafkaRequestHandlerPool,* - kafka.server:type=BrokerTopicMetrics,* - kafka.server:type=FetcherLagMetrics,* - kafka.server:type=FetcherStats,* - kafka.server:type=Request,* - kafka.server:type=Fetch,* - kafka.server:type=Produce,* - kafka.server:type=ReplicaManager,* - kafka.server:type=ReplicaFetcherManager,* - kafka.server:type=SessionExpireListener,* - kafka.server:type=controller-channel-metrics,* - kafka.server:type=socket-server-metrics,* - kafka.network:type=RequestChannel,* - kafka.network:type=Processor,* - kafka.network:type=SocketServer,* - kafka.network:type=RequestMetrics,* - kafka.coordinator.group:* blacklistObjectNames: - java.lang:type=ClassLoading,* - java.lang:type=Compilation,* - java.lang:type=MemoryManager,* - kafka.utils:* - kafka.controller:type=ControllerChannelManager,name=QueueSize,* # Following metrics are exposed per topics - kafka.log:type=Log,name=LogEndOffset,* - kafka.log:type=Log,name=LogStartOffset,* - kafka.cluster:type=Partition,name=InSyncReplicasCount,* - kafka.cluster:type=Partition,name=LastStableOffsetLag,* - kafka.cluster:type=Partition,name=ReplicasCounts,* - kafka.cluster:type=Partition,name=UnderReplicated,* - kafka.server:type=BrokerTopicMetrics,name=TotalFetchRequestsPerSec,* - kafka.server:type=BrokerTopicMetrics,name=TotalProduceRequestsPerSec,* - kafka.server:type=BrokerTopicMetrics,name=FailedProduceRequestsPerSec,* - kafka.server:type=BrokerTopicMetrics,name=FailedFetchRequestsPerSec,* - kafka.server:type=BrokerTopicMetrics,name=BytesRejectedPerSec,* rules: #------------------------------------------------------------------------------------------------------- # Broker Metrics : #------------------------------------------------------------------------------------------------------- # Total Topic Count - pattern: kafka.server<type=BrokerTopicMetrics, name=Topics><>Value name: kafka_server_broker_topic_count labels: service: kafka-broker env: cluster-demo # Total Message Count - pattern: kafka.server<type=BrokerTopicMetrics, name=MessagesInPerSec><>OneMinuteRate name: kafka_server_broker_total_messages_per_sec labels: aggregate: one_minute_rate service: kafka-broker env: cluster-demo # Total Partition Count - pattern: kafka.cluster<type=Partition, name=([^,]+), topic=([^,]+), partition=([^,]+)><>Value name: kafka_cluster_partition_$1 labels: topic: $2 partition: $3 service: kafka-broker env: cluster-demo #------------------------------------------------------------------------------------------------------- # JVM Metrics : #------------------------------------------------------------------------------------------------------- # CPU Usage - pattern: java.lang<type=OperatingSystem><ProcessCpuLoad> name: kafka_jvm_os_process_cpu_load labels: service: kafka-broker env: cluster-demo # RAM Usage - pattern: java.lang<type=OperatingSystem><TotalPhysicalMemorySize> name: kafka_jvm_os_total_physical_memory_size labels: service: kafka-broker env: cluster-demo # Heap Memory Usage - pattern: java.lang<type=Memory><HeapMemoryUsage>(\w*) name: kafka_jvm_heap_usage labels: type: $1 service: kafka-broker env: cluster-demo attrNameSnakeCase: true # Non-Heap Memory Usage - pattern: java.lang<type=Memory><NonHeapMemoryUsage>(\w*) name: kafka_jvm_non_heap_usage labels: type: $1 service: kafka-broker env: cluster-demo attrNameSnakeCase: true
Ardından, prometheus.yml
dosyasını oluşturuyoruz. Bu dosya, Prometheus’un yapılandırma dosyasıdır ve Prometheus’un hangi metrikleri, ne sıklıkta ve nereden toplayacağını tanımlar.
- Global Ayarlar: Bu bölüm, tüm scrape işlemleri ve kural değerlendirmeleri için genel ayarları tanımlar. Örneğin, scrape aralığı (
scrape_interval
) ve kural değerlendirme aralığı (evaluation_interval
) burada belirtilir. Örneğin, her 15 saniyede bir metrik alınması ve kuralların her 15 saniyede bir değerlendirilmesi belirtilir. - Alertmanager Yapılandırması: Bu bölüm, Alertmanager yapılandırmasını belirtir. Alertmanager, Prometheus’tan gelen uyarıları yönetmek ve bunlara yanıt vermek için kullanılır. Ancak,
targets
bölümü boş olduğu için herhangi bir Alertmanager hedefi belirtilmemiştir. - Kuralların Yüklenmesi: Bu bölüm, Prometheus’un yükleyeceği kural dosyalarını belirtir. Ancak, kural dosyaları yorumlanmış (
#
işaretiyle başlıyor) olduğu için herhangi bir kural dosyası yüklenmeyecektir. - Scrape Yapılandırmaları: Bu bölüm, Prometheus’un metrikleri toplayacağı hedefleri belirtir. Her scrape yapılandırması, bir “job” adı altında gruplandırılmış hedefler listesi içerir. Bu örnekte, “kafka” adında bir job tanımlanmış ve bu job’un metrikleri toplayacağı hedefler (
targets
) belirtilmiştir. Bu hedefler,jmx-kafka101:5556
,jmx-kafka102:5556
vejmx-kafka103:5556
adreslerindeki Kafka sunucularıdır.
# my global config global: scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute. evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute. # scrape_timeout is set to the global default (10s). # Alertmanager configuration alerting: alertmanagers: - static_configs: - targets: # - alertmanager:9093 # Load rules once and periodically evaluate them according to the global 'evaluation_interval'. rule_files: # - "first_rules.yml" # - "second_rules.yml" # A scrape configuration containing exactly one endpoint to scrape: # Here it's Prometheus itself. scrape_configs: # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config. - job_name: 'kafka' # metrics_path defaults to '/metrics' # scheme defaults to 'http'. static_configs: - targets: ['jmx-kafka101:5556','jmx-kafka102:5556', 'jmx-kafka103:5556']
Grafana Prometheus bağlantısı
Görselleştirmeleri yapabilmek için veri kaynağı olarak Prometheus eklememiz gerekiyor. Home> Administration > Data sources > Add data source adımlarını izleyerek Prometheus’u veri kaynağı olarak ekleyebilirsiniz.
Bu bağlantıyı, arayüzden olduğu gibi, yapılandırma dosyası ile de gerçekleştirebiliriz. Aşağıda bir örnek yapılandırma dosyasını bulabilirsiniz. Oluşturduğumuz datasource.yaml dosyasını /etc/grafana/provisioning/datasources dizinine kopyalayarak bağlantıyı sağlayabiliriz.
- apiVersion: Bu, yapılandırma dosyasının format sürümünü belirtir.
- deleteDatasources: Bu bölüm, silinecek veri kaynaklarını belirtir.
- datasources: Bu bölüm, eklenecek veya güncellenecek veri kaynaklarını belirtir. Her bir veri kaynağı için aşağıdaki bilgiler gerekir:
- name: Veri kaynağının adı.
- type: Veri kaynağının türü.
- access: Erişim modu.
- orgId: Veri kaynağının ait olduğu organizasyonun ID’si.
- url: Sunucu adresi.
- password: Kullanılacak şifre, eğer varsa.
- user: Kullanıcı adı, eğer varsa.
- database: Veritabanı adı, eğer varsa.
- basicAuth, basicAuthUser, basicAuthPassword: Temel kimlik doğrulama bilgileri, eğer kullanılacaksa.
- withCredentials: Başlıklarda kimlik bilgilerini etkinleştir veya devre dışı bırak.
- isDefault: Bu veri kaynağının varsayılan olup olmadığını belirtir, eğer varsa.
- jsonData: JSON formatında saklanacak alanlar.
- secureJsonData: Şifreli JSON verisi, örneğin TLS sertifikaları gibi.
- version: Yapılandırma sürümü.
- editable: Kullanıcıların UI’den veri kaynağını düzenleyip düzenleyemeyeceğini belirtir.
# config file version apiVersion: 1 # list of datasources that should be deleted from the database deleteDatasources: - name: Prometheus orgId: 1 # list of datasources to insert/update depending on # what's available in the database datasources: # <string, required> name of the datasource. Required - name: Prometheus # <string, required> datasource type. Required type: prometheus # <string, required> access mode. proxy or direct (Server or Browser in the UI). Required access: proxy # <int> org id. will default to orgId 1 if not specified orgId: 1 # <string> url url: http://prometheus:9090 # <string> database password, if used password: # <string> database user, if used user: # <string> database name, if used database: # <bool> enable/disable basic auth basicAuth: # <string> basic auth username basicAuthUser: # <string> basic auth password basicAuthPassword: # <bool> enable/disable with credentials headers withCredentials: # <bool> mark as default datasource. Max one per org isDefault: true # <map> fields that will be converted to json and stored in json_data jsonData: httpMethod: POST manageAlerts: true prometheusType: Prometheus prometheusVersion: 2.47.0 cacheLevel: 'High' tlsAuth: false tlsAuthWithCACert: false # <string> json object of data that will be encrypted. secureJsonData: tlsCACert: "..." tlsClientCert: "..." tlsClientKey: "..." version: 1 # <bool> allow users to edit datasources from the UI. editable: true
Grafana ile Grafik Oluşturma
Grafana ile çeşitli görselleştirmeler oluşturabiliriz. Veri analizi ve izleme için ideal bir araç olan Grafana, çeşitli grafikler, histogramlar, ısı haritaları ve daha fazlasını oluşturmamıza olanak sağlar. Veriye dayalı uyarıları oluşturabilir ve bu uyarıları e-posta, Slack gibi platformlara yönlendirebiliriz. Ayrıca, karmaşık sorguları kaydederek daha sonraki kullanımlar için saklayabiliriz.
Şimdi bir grafik oluşturmayı birlikte deneyelim. İlk olarak, yeni bir dashboard oluşturmalıyız. Bu adımları takip edebiliriz: Home > Dashboards > New Dashboard. Sonra, ‘Add new panel’ seçeneğini tıklayarak yeni bir grafik başlatabiliriz. Grafik oluştururken, veri kaynağını seçmeli ve bir sorgu yazmalıyız. Sorgu, grafikte neyin gösterileceğini belirler. Örneğin, belirli bir zaman aralığındaki bir metriğin değerlerini gösterebiliriz. Daha sonra, grafik türünü seçip, grafik ayarlarını özelleştirebiliriz. Tüm bu adımlar tamamlandığında, ‘Apply’ düğmesine tıklayarak grafik panelini dashboard’a ekleyebiliriz.
Örneğin, ortalama bellek kullanımını gözlemlemek için bir grafik oluşturalım. İlk olarak, grafikte göstermek istediğimiz verinin kaynağını belirleriz. Kaynağı belirledikten sonra, verinin nasıl gösterileceğini belirleyen sorguyu yazmamız gerekiyor. Sonra, oluşturduğumuz grafiğe bir isim verelim ve bu ismi sol paneldeki ilgili alana giriyoruz. Aynı panelde, hangi tür verinin nasıl bir formatla gösterileceğini belirleyen grafik türünün özelliklerini de ayarlayabilirz. Ayarlar tamamlandıktan sonra, ‘kaydet’ butonuna basıyourz burada bize hangi panoya eklemek istediğimiz soracak. Son olarak, grafiği hangi panoya eklemek istediğimizi belirleyip grafiği kayıt ediyoruz.
Bu yazıda Prometheus ve Grafana’nın karmaşık izleme görevlerini nasıl basitleştirdiğini gördük ve Kafka kümesinin izlenme sürecini anlattık ve bu araçların birlikte nasıl çalıştığını açıkladık. Herkese keyifli okumalar dilerim, bir sonraki yazıda görüşmek üzere.
Kaynaklar: