Broker testleri

Prometheus ve Grafana ile MQTT İzleme

Prometheus ve Grafana ile MQTT broker izleyin: mosquitto-exporter, EMQX metrikleri, Python probe exporter'ı, Docker Compose stack'i, dashboard'lar ve alarmlar.

Güncellendi · 9 dk okuma

Prometheus ve Grafana ile MQTT İzleme

Prometheus ve Grafana, bir MQTT broker'ını izlemek için kullanılan yaygın ikilidir. Prometheus metrikleri HTTP üzerinden toplar ve alarm kurallarını değerlendirir. Grafana dashboard'ları çizer. Broker'lar metriklerini iki şekilde sunar: bazılarının yerel bir Prometheus endpoint'i vardır (EMQX, VerneMQ, bir extension aracılığıyla HiveMQ), Mosquitto gibi diğerleri ise yalnızca $SYS topic'leri yayınlar ve bunları çevirecek bir exporter'a ihtiyaç duyar.

Bu rehber büyük ihtimalle ihtiyaç duyacağınız üç veri kaynağını bağlar: Mosquitto için bir exporter, EMQX'in yerel endpoint'i ve yönetilen broker'lar dahil her broker'la çalışan istemci taraflı bir probe. Ardından dashboard'lar ve alarmlar eklenir.

Metrikler nereden gelir?

BrokerPrometheus metrikleri nasıl alır
Mosquittomosquitto-exporter $SYS/# topic'ine abone olur ve /metrics sunar (varsayılan port 9234)
EMQX 5Dashboard/API portunda (18083) yerleşik /api/v5/prometheus/stats endpoint'i ya da bir Pushgateway'e gönderim
HiveMQHiveMQ Prometheus Monitoring Extension, /metrics sunar (varsayılan port 9399)
VerneMQHTTP listener'ında yerleşik /metrics (varsayılan port 8888)
Yönetilen brokerSağlayıcı sunuyorsa onun metrikleri, ayrıca kendi istemci taraflı probe'unuz

Broker tarafı metrikler broker'ın ne yaptığını anlatır: bağlantılar, throughput, kuyruklar ve düşürülen mesajlar. İstemci taraflı bir probe ise cihazlarınızın ne yaşadığını gösterir: bağlanabiliyorlar mı ve bir mesaj ne kadar sürüyor? İkisine de ihtiyacınız var. Yalnızca birini seçebiliyorsanız probe'u seçin, çünkü DNS, TLS, load balancer ve kimlik doğrulama hatalarını yakalayan odur.

$SYS sizin için yeniyse önce $SYS topic'leri ile broker izleme yazısını okuyun. Aşağıdaki exporter bunun üzerinde ince bir katmandır.

Docker Compose ile yerel bir stack

Bu stack Mosquitto'yu, exporter'ı, Prometheus'u ve Grafana'yı birlikte çalıştırır. Dashboard'ları production'a yönlendirmeden önce hazırlamak için iyi bir laboratuvardır.

docker-compose.yml
services:
  mosquitto:
    image: eclipse-mosquitto:2
    ports: ["1883:1883"]
    volumes:
      - ./mosquitto.conf:/mosquitto/config/mosquitto.conf:ro

  mosquitto-exporter:
    image: sapcc/mosquitto-exporter
    command: ["--endpoint", "tcp://mosquitto:1883"]
    ports: ["9234:9234"]
    depends_on: [mosquitto]

  prometheus:
    image: prom/prometheus
    ports: ["9090:9090"]
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - ./alerts.yml:/etc/prometheus/alerts.yml:ro

  grafana:
    image: grafana/grafana
    ports: ["3000:3000"]
    volumes:
      - ./grafana-datasource.yml:/etc/grafana/provisioning/datasources/prometheus.yml:ro
mosquitto.conf (yalnızca yerel laboratuvar)
listener 1883
allow_anonymous true
sys_interval 10
grafana-datasource.yml
apiVersion: 1
datasources:
  - name: Prometheus
    type: prometheus
    url: http://prometheus:9090
    isDefault: true

allow_anonymous true yalnızca dizüstü bilgisayarınızda kabul edilebilir. Gerçek bir broker'da yalnızca $SYS/# okuyabilen ayrı bir izleme kullanıcısı oluşturun ve bunu exporter'a --user ve --pass ile verin. mosquitto.conf oluşturucu listener ve kimlik doğrulama bloklarını sizin için hazırlayabilir. Daha fazla servis içeren daha kapsamlı bir laboratuvar için MQTT Docker Compose stack'i yazısına bakın.

Exporter her sayısal $SYS topic'ini, adı topic yolunu izleyen bir metriğe dönüştürür; örneğin $SYS/broker/clients/connected broker_clients_connected olur. Sorgu yazmadan önce sürümünüzün ürettiği tam adları görmek için http://localhost:9234/metrics adresini açın.

Her broker için bir probe exporter'ı

Bu Python exporter'ı (paho-mqtt 2.x ve prometheus_client) her 15 saniyede bir TLS üzerinden bağlanır, benzersiz bir topic'e abone olur, bir mesaj yayınlar ve mesajın geri gelmesini bekler. İşlemin başarılı olup olmadığını ve her adımın ne kadar sürdüğünü dışa aktarır:

mqtt_probe_exporter.py
import os, ssl, threading, time, uuid
import paho.mqtt.client as mqtt
from prometheus_client import Gauge, Histogram, start_http_server

HOST, PORT, INTERVAL = "broker.connectmq.com", 8883, 15
success = Gauge("mqtt_probe_success", "1 if the last connect/publish/receive cycle worked")
connect_s = Gauge("mqtt_probe_connect_seconds", "TCP + TLS + CONNACK time of the last probe")
roundtrip = Histogram("mqtt_probe_roundtrip_seconds", "Subscribe, publish and receive time",
                      buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5))

def probe() -> bool:
    topic = f"testmqtt/probe/{uuid.uuid4().hex[:8]}"
    connected, received = threading.Event(), threading.Event()
    c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                    client_id=f"testmqtt-probe-{uuid.uuid4().hex[:6]}")
    c.username_pw_set(os.getenv("MQTT_USER"), os.getenv("MQTT_PASS"))
    c.tls_set(cert_reqs=ssl.CERT_REQUIRED)
    c.on_connect = lambda cl, ud, fl, rc, pr: connected.set() if not rc.is_failure else None
    c.on_subscribe = lambda cl, ud, mid, rcs, pr: cl.publish(topic, "ping", qos=1)
    c.on_message = lambda cl, ud, msg: received.set()
    t0 = time.perf_counter()
    try:
        c.connect(HOST, PORT, keepalive=10)
        c.loop_start()
        if not connected.wait(5):
            return False
        connect_s.set(time.perf_counter() - t0)
        t1 = time.perf_counter()
        c.subscribe(topic, qos=1)
        if not received.wait(5):
            return False
        roundtrip.observe(time.perf_counter() - t1)
        return True
    except OSError:
        return False
    finally:
        c.disconnect()
        c.loop_stop()

if __name__ == "__main__":
    start_http_server(9105)          # metrikler http://localhost:9105/metrics adresinde
    while True:
        success.set(1 if probe() else 0)
        time.sleep(INTERVAL)

Bağımlılıkları pip install paho-mqtt prometheus-client ile kurun. Her döngüde yeni bir bağlantı açmak bilinçli bir tercihtir: tıpkı yeniden başlayan bir cihaz gibi her seferinde DNS, TLS ve kimlik doğrulama da test edilir. Her çalıştırmada benzersiz bir client ID kullanın. Client ID oluşturucu yinelenen ID'lerin neden birbirini düşürdüğünü açıklar.

Scrape yapılandırması

prometheus.yml
global:
  scrape_interval: 15s

rule_files: ["/etc/prometheus/alerts.yml"]

scrape_configs:
  - job_name: mosquitto
    static_configs:
      - targets: ["mosquitto-exporter:9234"]

  - job_name: mqtt-probe
    static_configs:
      - targets: ["host.docker.internal:9105"]   # probe'un çalıştığı yer

  - job_name: emqx
    metrics_path: /api/v5/prometheus/stats
    static_configs:
      - targets: ["emqx:18083"]

Kullanmadığınız job'ları kaldırın. Güncel EMQX sürümlerinde istatistik endpoint'i kimlik doğrulama isteyecek şekilde yapılandırılabilir. Bu durumda bir API key ve secret ile basic_auth ekleyin. EMQX'i yerelde denemek için Docker'da EMQX yazısına bakın. host.docker.internal Docker Desktop'ta çalışır. Linux'ta probe'u başka bir Compose servisi olarak çalıştırın.

Gerçek soruları yanıtlayan dashboard'lar

Faydalı bir MQTT dashboard'unda az panel olur ve her biri bir olay sırasında birinin soracağı bir soruyu yanıtlar:

PanelPromQL (örnek)
İstemciler bağlı mı?broker_clients_connected veya sum(emqx_connections_count)
Saniyede gelen / giden mesajrate(broker_messages_received[5m]), rate(emqx_messages_sent[5m])
Mesaj düşürüyor muyuz?rate(broker_publish_messages_dropped[5m]) veya rate(emqx_messages_dropped[5m])
Bir istemci şu an bağlanabiliyor mu?mqtt_probe_success
Teslimat ne kadar yavaş?histogram_quantile(0.99, sum by (le) (rate(mqtt_probe_roundtrip_seconds_bucket[10m])))
Bağlanma süresimqtt_probe_connect_seconds

Sayaçlarda rate() kullanın, ham sayaç değerini asla grafiğe dökmeyin. Probe panellerini en üste koyun, çünkü kullanıcıların gördüğünü onlar gösterir. grafana.com'da Mosquitto exporter'ı ve EMQX için topluluk dashboard'ları yayınlanmıştır. İyi bir başlangıç noktasıdırlar ama metrik adlarının exporter sürümünüzle eşleştiğini kontrol edin.

Alarm kuralları

alerts.yml
groups:
  - name: mqtt
    rules:
      - alert: MqttProbeFailing
        expr: max_over_time(mqtt_probe_success[3m]) == 0
        labels: { severity: page }
        annotations:
          summary: "No successful MQTT round trip for 3 minutes"

      - alert: MqttProbeSlow
        expr: histogram_quantile(0.99, sum by (le) (rate(mqtt_probe_roundtrip_seconds_bucket[10m]))) > 0.5
        for: 10m
        labels: { severity: ticket }

      - alert: MqttClientsDropped
        expr: broker_clients_connected < 0.7 * (broker_clients_connected offset 10m)
        for: 2m
        labels: { severity: page }

      - alert: MqttExporterDown
        expr: up{job="mosquitto"} == 0
        for: 2m
        labels: { severity: ticket }

MqttClientsDropped klasik olay örüntüsünü yakalar: süresi dolan bir sertifika, bir ağ değişikliği ya da broker'ın yeniden başlaması sonrasında cihazların büyük bir kısmı aynı anda bağlantıyı kaybeder. page alarmlarını Alertmanager üzerinden nöbet kanalınıza, ticket alarmlarını daha sakin bir yere yönlendirin. Dış kontroller ve SLO hesapları için MQTT uptime izleme yazısına bakın.

İzlemenin kendisini test edin

Alarmlara güvenmeden önce her birini bilerek tetikleyin:

  1. Probe hatası: MQTT_PASS değerini yanlış bir değerle değiştirin ve probe'u yeniden başlatın. mqtt_probe_success 0'a düşmeli ve MqttProbeFailing yaklaşık üç dakika içinde tetiklenmelidir.
  2. İstemci düşüşü: bir grup test istemcisi bağlayın (bir cihaz simülatörü veya online istemcinin birkaç sekmesi), on dakika bekleyin ve sonra kapatın. Bağlı istemciler paneli buna göre düşmelidir.
  3. Exporter kapalı: docker compose stop mosquitto-exporter komutu MqttExporterDown alarmını tetiklemelidir.
  4. Gecikme: bir network shaper ile gecikme ekleyin ya da probe değerlerini ayrı bir gecikme testi ile karşılaştırın.

Testte hiç tetiklenmemiş bir alarm, gerçek bir kesinti sırasında da tetiklenmeyebilir.

Prometheus ve Grafana, $SYS'in tek başına sunamadığı geçmişi, dashboard'ları ve alarmları sağlar. Broker metriklerini istemci taraflı bir probe ile birleştirin, dashboard'u küçük tutun ve her alarma güvenmeden önce onu bir kez test edin.

Sıkça sorulan sorular

Mosquitto'nun yerleşik bir Prometheus endpoint'i var mı?

Hayır. Mosquitto istatistiklerini $SYS topic'lerinde yayınlar. mosquitto-exporter gibi bir exporter $SYS/# topic'ine abone olur ve değerleri Prometheus'un toplayabileceği bir HTTP /metrics endpoint'inde sunar.

Yönetilen bir MQTT broker'ını Prometheus ile izleyebilir miyim?

Evet, istemci tarafından. Broker'ın yanına exporter kuramasanız bile bağlanan, publish eden ve bir mesaj alan küçük bir probe başarı ve gecikme metrikleri dışa aktarabilir. Çoğu zaman zaten en faydalı sinyal budur.

İlk olarak hangi durumlar için alarm kurmalıyım?

Üç alarmla başlayın: probe'un birkaç dakika boyunca başarısız olması, bağlı istemci sayısında ani düşüş ve sıfırın üzerinde düşürülen mesaj. Normal p99 değerinizi öğrendikten sonra gecikme alarmları ekleyin.