Beim Erstellen von PHP Microservices ohne Frameworks wird eine Anwendung in kleinere, unabhängige Dienste aufgeteilt, die über ein Netzwerk kommunizieren. Hier ist eine allgemeine Anleitung, wie Sie PHP Microservices ohne Frameworks angehen können:
1. Überblick über die Architektur
- Entkopplungsdienste: Jeder Microservice ist für eine bestimmte Domäne zuständig (z. B. Authentifizierung, Benutzerverwaltung, Produktkatalog).
- Unabhängige Bereitstellung: Jeder Microservice kann unabhängig von anderen bereitgestellt werden, bei Bedarf sogar mit verschiedenen PHP-Versionen.
- Kommunikation: Microservices können miteinander kommunizieren über:
- HTTP/REST-APIs (mit cURL oder Guzzle in PHP)
- Nachrichtenwarteschlangen (z. B. RabbitMQ)
- gRPC (für schnellere, binärbasierte Kommunikation)
2. Projektstruktur
- Jede Dienstleistung sollte als eigenständiges Projekt strukturiert sein:
- Service A (Benutzerverwaltung)
- Dienstleistung B (Auftragsabwicklung)
- Dienst C (Authentifizierung)
- Jeder Dienst sollte über ein eigenes Git-Repository verfügen oder zumindest nach Verzeichnis/Modul getrennt sein.
3. HTTP-Kommunikation mit PHP
Verwenden Sie die integrierten Funktionen von PHP (oder cURL für erweiterte Funktionen), um zwischen Microservices über HTTP zu kommunizieren.
Beispiel für eine HTTP-Anfrage in PHP mit :file_get_contents
$url = 'http://userservice.local/api/users/1';
$response = file_get_contents($url);
$data = json_decode($response, true);
Beispiel für die Verwendung von cURL:
$ch = curl_init('http://authservice.local/api/login');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
'username' => 'user',
'password' => 'pass',
]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
4. Automatisches Laden und Namespaces
Verwenden Sie den Autoloader von Composer, um Abhängigkeiten zu verwalten, und PSR-4 zum automatischen Laden von Klassen in Ihren Microservices.
{
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}
5. Routing
Sie können Ihre eigene Routing-Logik implementieren oder ein leichtgewichtiges PHP-Mikroframework wie Slim oder Silex für die Verarbeitung von HTTP-Anfragen verwenden.
- Beispiel für grundlegendes natives Routing:
$requestUri = $_SERVER['REQUEST_URI'];
if ($requestUri == '/users') {
// Logic for user-related operations
} elseif ($requestUri == '/products') {
// Logic for product-related operations
}
6. Zugriff auf die Datenbank
Each microservice should have its own database or schema. Use PDO or a lightweight ORM like Doctrine for managing database interactions.
Example using PDO:
$pdo = new PDO('mysql:host=localhost;dbname=user_service', 'username', 'password');
$stmt = $pdo->query('SELECT * FROM users');
while ($row = $stmt->fetch()) {
echo $row['name'];
}
7. Inter-Service Communication (Asynchronous)
For asynchronous communication, you can use a message broker like RabbitMQ or Kafka.
- Use PHP libraries like php-amqplib to interact with RabbitMQ.
Example of sending a message:
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('task_queue', false, true, false, false);
$data = "New User Registered";
$msg = new AMQPMessage($data);
$channel->basic_publish($msg, '', 'task_queue');
$channel->close();
$connection->close();
8. Security (JWT Authentifizierung)
Implementieren Sie für die dienstübergreifende Authentifizierung von Benutzern JWT (JSON Web Token) für die zustandslose Authentifizierung.
- Bibliotheken wie firebase/php-jwt können für den Umgang mit JWT-Token in PHP verwendet werden.
- JWT-Token können über Header zwischen Diensten übergeben werden, um Anfragen zu authentifizieren.
Beispiel für die Verifizierung eines JWT:
use \Firebase\JWT\JWT;
$jwt = $_SERVER['HTTP_AUTHORIZATION'];
$key = 'your_secret_key';
try {
$decoded = JWT::decode($jwt, $key, array('HS256'));
echo "User ID: " . $decoded->userId;
} catch (Exception $e) {
echo 'Unauthorized: ' . $e->getMessage();
}
9. Service Discovery
In einer Microservices-Architektur, in der verschiedene Dienste miteinander kommunizieren und oft dynamisch skaliert oder neu gestartet werden, ist es unerlässlich, dass die beteiligten Dienste in der Lage sind, sich gegenseitig zu finden. Dies stellt sicher, dass alle Anfragen korrekt weitergeleitet und die Systemkomponenten effizient miteinander verbunden werden können. Der Prozess der dynamischen Ermittlung und Verwaltung von Diensten wird als Service Discovery bezeichnet.
In größeren, verteilten Systemen, in denen Dienste regelmäßig hinzugefügt, entfernt oder aktualisiert werden, müssen Mechanismen zum Finden und Kommunizieren mit den richtigen Instanzen der Dienste verwendet werden. In diesem Fall können spezialisierte Tools wie Consul oder Eureka verwendet werden, die das Service Discovery automatisch durchführen. Diese Tools bieten nicht nur eine zentrale Anlaufstelle für alle verfügbaren Dienste, sondern ermöglichen auch die Registrierung von Diensten sowie die Überwachung ihrer Verfügbarkeit und Gesundheit. Consul und Eureka sorgen dafür, dass alle Instanzen eines Dienstes jederzeit ermittelt werden können, auch wenn sich deren IP-Adressen oder Ports aufgrund von Skalierungen oder Ausfällen ändern.
Für kleinere, weniger komplexe Anwendungen, bei denen der Overhead eines dedizierten Service Discovery-Tools möglicherweise nicht gerechtfertigt ist, gibt es auch einfachere Alternativen. In PHP-nativen Anwendungen können Sie Service-URLs fest codieren oder Umgebungsvariablen verwenden, um die Verbindung zu anderen Diensten zu konfigurieren. Fest codierte URLs bieten eine einfache Möglichkeit, Dienste anzusprechen, wenn sich deren Adressen nicht häufig ändern. Sie eignen sich jedoch nur für kleinere Systeme oder in Situationen, in denen Dienste stabil und nicht dynamisch skaliert werden.
Eine flexiblere und robustere Lösung ist die Verwendung von Umgebungsvariablen, die es ermöglichen, die URL des jeweiligen Dienstes je nach Umgebung (z. B. Entwicklung, Test, Produktion) anzupassen, ohne den Code selbst ändern zu müssen. Diese Methode trägt zur besseren Trennung von Code und Konfiguration bei und ermöglicht eine leichtere Wartung und Skalierung von Systemen.
Trotz dieser vereinfachten Ansätze in kleineren PHP-Anwendungen sollte bei wachsender Komplexität der Architekturen immer wieder geprüft werden, ob es sinnvoll ist, auf dedizierte Service Discovery-Mechanismen umzusteigen, die eine bessere Skalierbarkeit, Verfügbarkeit und Automatisierung bieten. Darüber hinaus kann Service Discovery auch die Grundlage für zusätzliche Optimierungen bieten, wie z. B. Lastenverteilung oder automatisches Failover, was zu einer höheren Ausfallsicherheit und einer besseren Performance des Systems führt.
Letztlich hängt die Wahl der richtigen Service Discovery-Lösung von der Komplexität der Anwendung, der Anzahl der Microservices sowie den spezifischen Anforderungen der Infrastruktur ab. In jedem Fall sollte sichergestellt werden, dass der Service Discovery-Prozess den gesamten Lebenszyklus eines Microservices-Systems unterstützt und kontinuierlich an die sich ändernden Bedingungen angepasst wird.
10. Load Balancing and Scaling
- Verwenden Sie Nginx oder HAProxy als Load Balancer, um den Datenverkehr auf Instanzen Ihrer PHP-Microservices zu verteilen.
- Containerisieren Sie Ihre PHP-Microservices mit Docker und orchestrieren Sie sie mit Kubernetes für die Skalierung.
11. Überwachung und Protokollierung
Verwenden Sie Protokollierungsbibliotheken wie Monolog, um Protokolle von allen Microservices zu zentralisieren.
Beispiel für die Protokollierung mit Monolog:
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$log = new Logger('name');
$log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));
$log->warning('Foo');
12. Umgang mit Fehlern und Ausfällen
Der Umgang mit Fehlern und Ausfällen ist ein wesentlicher Bestandteil jeder robusten und skalierbaren Systemarchitektur. Um die Verfügbarkeit und Zuverlässigkeit von Systemen zu gewährleisten, ist es wichtig, Mechanismen zu implementieren, die Fehler frühzeitig erkennen und verhindern, dass diese Fehler sich auf andere Teile des Systems ausbreiten. Ein zentraler Bestandteil dabei ist die Verwendung des Circuit Breaker-Musters.
Implementieren Sie Circuit Breaker (mit Bibliotheken wie PHP Circuit Breaker), um Fehler zwischen Diensten zu verwalten. Das Circuit Breaker-Muster hilft dabei, Fehler zu erkennen und zu verhindern, dass wiederholte fehlerhafte Aufrufe einen Dienst vollständig lahmlegen. Wenn ein Dienst fehlerhaft wird und eine vorher definierte Anzahl von Fehlschlägen überschreitet, wird der Circuit Breaker „geöffnet“, was bedeutet, dass der Dienst für eine bestimmte Zeit nicht mehr angesprochen wird. Während dieser Zeit werden Aufrufe an den Dienst sofort abgebrochen oder auf alternative Mechanismen umgeleitet. Nach einer gewissen „Erholungsphase“ wird der Circuit Breaker wieder „geschlossen“, und der Dienst kann erneut verwendet werden.
Neben Circuit Breakern sollten auch Wiederholungsmechanismen und Timeout-Limits implementiert werden, insbesondere wenn Sie dienstübergreifende HTTP- oder nachrichtenbasierte Aufrufe tätigen. Wiederholungsmechanismen helfen dabei, vorübergehende Fehler oder Netzwerkprobleme zu umgehen, indem sie Anfragen automatisch nach einer bestimmten Zeitspanne erneut senden. Es ist jedoch wichtig, dass diese Wiederholungsversuche begrenzt und mit zunehmendem Abstand durchgeführt werden, um zu verhindern, dass eine zu hohe Anzahl an Versuchen das System belastet.
Zusätzlich sollten Timeout-Limits gesetzt werden, um zu verhindern, dass ein Service zu lange blockiert und so das gesamte System beeinträchtigt. Timeout-Limits stellen sicher, dass bei Ausfällen innerhalb eines bestimmten Zeitrahmens eine Entscheidung getroffen wird, ob der Dienst als fehlerhaft betrachtet wird, um rechtzeitig auf Alternativen oder Wiederholungsmechanismen zurückzugreifen.
Durch die Kombination dieser Mechanismen – Circuit Breaker, Wiederholungsmechanismen und Timeout-Limits – können Sie sicherstellen, dass Ihre Systeme auch in Zeiten von Fehlern oder Ausfällen stabil und zuverlässig bleiben. Dies erhöht nicht nur die Fehlertoleranz, sondern auch die Benutzererfahrung, da Ausfälle oder Verzögerungen minimiert werden.
Darüber hinaus sollte bei der Implementierung von Fehlerbehandlungsstrategien eine gründliche Überwachung und Protokollierung der Systemaufrufe und Fehlerzustände berücksichtigt werden. So können Fehlerquellen schnell identifiziert und gegebenenfalls behoben werden, bevor sie ernsthafte Auswirkungen auf das Gesamtsystem haben.
Fazit
PHP Microservices ohne Frameworks können erstellt werden, indem vorhandene PHP-Tools und -Bibliotheken für Kommunikation, Routing, Datenbankverwaltung und Protokollierung genutzt werden. Der Schlüssel liegt darin, die Dienste unabhängig zu halten, Best Practices für die API-Entwicklung zu befolgen und asynchrones Messaging für komplexere Workflows einzuführen.
Zu einem weiteren Beitrag: DDD verursacht Komplexität