Einleitung: Vom einfachen Healthcheck zur tiefgehenden Observability
\nDas grundlegende Monitoring von PHP-Anwendungen, einschließlich Verfügbarkeitsprüfung (Healthcheck) und CPU-Auslastung, ist das Minimum, das zuerst eingerichtet werden muss. Für Produktionssysteme mit hoher Last und komplexer Geschäftslogik reicht dies jedoch nicht aus. Fortgeschrittenes Monitoring verlagert den Fokus von „lebend/tot“ auf Observability (Beobachtbarkeit) und ermöglicht die Beantwortung von Fragen wie: „Warum ist die Conversion-Rate gefallen?“, „Welcher Endpunkt hat die Arbeit verlangsamt?“, „Wie viele Benutzer konnten die Zahlung nicht abschließen?“.
\nIn diesem Artikel betrachten wir die Architektur des fortgeschrittenen Monitorings von PHP-Anwendungen, lernen, wie man benutzerdefinierte Metriken (einschließlich Geschäftsmetriken) erfasst, Alarme auf Basis von Anomalien konfiguriert und alles in ein einheitliches Grafana-Dashboard integriert. Alle Codebeispiele sind in PHP geschrieben und bereit für die Implementierung.
\n\n1. Architektur der Metrikenerfassung: Prometheus und benutzerdefinierte Exporter
\nDer moderne De-facto-Standard für die Metrikenerfassung ist Prometheus mit dem Pull-Modell. Eine PHP-Anwendung muss die Metriken nicht direkt über den Port /metrics bereitstellen. Stattdessen verwenden wir einen benutzerdefinierten Exporter – ein separates Skript, das die Anwendung abfragt (über Redis, eine Datenbank oder eine Datei) und die Antwort im Prometheus-Format erstellt.
\n\n1.1. Installation des Prometheus-Clients für PHP
\nDie empfohlene Bibliothek ist promphp/prometheus_client_php. Installation über Composer:
composer require promphp/prometheus_client_php\n\n1.2. Beispiel eines Metrik-Exporters (metrics.php)
\nWir erstellen ein Skript, das Metriken im Prometheus-Format zurückgibt. Zur Speicherung verwenden wir Redis (Flag PERSISTENT für die Produktion).
<?php\nrequire 'vendor/autoload.php';\n\nuse Prometheus\\CollectorRegistry;\nuse Prometheus\\Storage\\Redis;\nuse Prometheus\\RenderTextFormat;\n\n// Verbindung zu Redis\nRedis::setDefaultOptions(['host' => '127.0.0.1', 'port' => 6379]);\n$registry = new CollectorRegistry(new Redis());\n\n// Registrieren eines Histogramms für die Antwortzeit\n$histogram = $registry->getOrRegisterHistogram(\n 'app_http_request_duration_seconds',\n 'HTTP request duration in seconds',\n ['method', 'endpoint', 'status']\n);\n\n// Registrieren eines Zählers für Geschäftsmetriken\n$counter = $registry->getOrRegisterCounter(\n 'app_orders_total',\n 'Total number of orders processed',\n ['status'] // success, failed\n);\n\n// Simulation von Daten (in der Realität aus der DB oder Logs auslesen)\n$histogram->observe(0.12, ['GET', '/api/orders', '200']);\n$counter->incBy(1, ['success']);\n\n// Metriken ausgeben\n$renderer = new RenderTextFormat();\nheader('Content-Type: text/plain');\necho $renderer->render($registry->getMetricFamilySamples());\n\nAnschließend konfigurieren wir Nginx oder Apache so, dass dieses Skript unter dem Pfad /metrics verfügbar ist, und fügen das Target in Prometheus hinzu.
2. Geschäftsmetriken: Überwachung dessen, was wirklich wichtig ist
\nTechnische Metriken (Latenz, Fehlerrate) sind die Grundlage, aber Geschäftsmetriken geben Aufschluss über die Gesundheit des Produkts. Beispiele für solche Metriken:
\n- \n
- Anzahl erfolgreicher Bestellungen pro Minute – ein Rückgang signalisiert Probleme mit dem Zahlungsgateway. \n
- Durchschnittliche Bearbeitungszeit des Warenkorbs – ein Anstieg kann auf eine Regression im Code hindeuten. \n
- Prozentsatz der Registrierungsabbrüche – bei einem plötzlichen Anstieg ist möglicherweise das Formular defekt. \n
2.1. Integration von Geschäftsmetriken in den Anwendungscode
\nWir verwenden denselben prometheus_client_php, kapseln die Aufrufe jedoch in Middleware oder eine Service-Schicht. Beispiel für Laravel:
<?php\nnamespace App\\Http\\Middleware;\n\nuse Closure;\nuse Prometheus\\CollectorRegistry;\n\nclass MetricsMiddleware\n{\n protected $registry;\n\n public function __construct(CollectorRegistry $registry)\n {\n $this->registry = $registry;\n }\n\n publi