Schlange stehen

Ein Überblick zu Message Queues für PHP
Kommentare

Message Queues sind im Enterprise-Umfeld ein oft angewandtes Mittel, um Aufgaben voneinander zu koppeln und auf verschiedene Systeme oder Server zu verteilen. Da PHP im Enterprise-Umfeld immer häufiger anzutreffen ist, entstehen auch hierfür immer mehr Lösungen, um Message Queues zu implementieren.

Als Webentwickler erliegt man oft der Versuchung, dass alle Operationen innerhalb eines Requests abgearbeitet werden, auch wenn diese gar nicht für die Ausgabeseite des Benutzers notwendig sind und durchaus zu einem späteren Zeitpunkt ausgeführt werden könnten. Das bedeutet nicht nur, dass der Webserver unnötigerweise belastet wird, sondern auch, dass der Benutzer lange auf seine Antwort warten muss. In vielen Fällen würde es genügen, die Aufgaben zu einem späteren Zeitpunkt auszuführen. Gerade im Enterprise-Umfeld sind solche Aufgaben an der Tagesordnung. Buchungen von Ressourcen oder Abarbeitung von Bestellungen sind Beispiele, bei denen es meist ausreicht, die Informationen zu sammeln und zeitversetzt zu verarbeiten. Oftmals kümmern sich um die Abarbeitung weitere Systeme, die auf anderen Servern laufen.

Über Message Queues werden solche Aufgaben sowohl zeitlich als auch räumlich von einander gekoppelt. Dabei handelt es sich um Softwarelösungen, die eine Warteschlange zur Verfügung stellen. Meist arbeiten diese nach dem „Publish and Subscribe“-Ansatz. Der Client (Publisher) schreibt Werte (Nachrichten) in die Queue, auf der Serverseite werden diese durch einen Subscriber aus der Warteschlange genommen und verarbeitet. Das Auslesen erfolgt nach dem FiFo-Prinzp (First-in-First-out), die ältesten Nachrichten werden also zuerst ausgelesen. Bei der Auswahl einer Message-Queue-Software liegt der Fokus in der Regel auf der Skalierbarkeit und der Stabilität bzw. Ausfallsicherheit der Lösung. Da PHP immer mehr im Bereich der Enterprise-Systeme Fuß fasst, ist es kaum verwunderlich, dass auch der Bedarf nach Messaging-Lösungen steigt und sich einige Entwickler bereits mit der Umsetzung beschäftigt haben. Trotzdem steht die Entwicklung hier noch am Anfang und so ist auch die Auswahl an Lösungen noch überschaubar. Im Folgenden werden die derzeit verfügbaren Möglichkeiten aufgezeigt, die PHP-Entwicklern zur Verfügung stehen.

JMS-Bridges

Der JEE-Standard von Sun definiert, dass jeder Java-Application-Server eine Message-Queue-Implementierung mitbringen muss. Aus diesem Grund ist der Einsatz innerhalb von Java-Enterprise-Anwendungen sehr beliebt. Mit JMS (Java Messaging Service) legt der Standard zudem sehr exakt fest, wie die Message Queues verwendet werden. Leider ist dieser Standard primär auf Java-Systeme zugeschnitten, sodass es für PHP-Entwickler nicht gerade einfach ist, auf die Funktionen einer JMS Message Queue zuzugreifen. Grundvoraussetzung für den Einsatz von JMS ist eine funktionstüchtige Installation eines Java-Application-Servers wie JBoss oder GlassFish. Beide bringen eine entsprechende Message-Queue-Implementierung von Haus aus mit.

Wie bereits erwähnt, lässt sich eine JMS-Implementierung nur durch Java mit Nachrichten füllen und auslesen. Glücklicherweise existieren mittlerweile verschiedene Möglichkeiten, wie sich aus PHP heraus Java-Funktionen nutzen lassen. Die wohl populärste ist die Nutzung der PHP/Java Bridge. Diese Open-Source-Erweiterung erlaubt den Zugriff auf die Ressourcen eines JEE-Application-Servers und damit auch den Zugriff auf eine Message Queue. Listing 1 zeigt ein Beispiel hierfür.

"org.jnp.interfaces.NamingContextFactory",
"java.naming.factory.url.pkgs" => "org.jboss.naming:org.jnp.interfaces",
"java.naming.provider.url" => "jnp://queueserver:1099"
);

$ctx = new Java("javax.naming.InitialContext", $env);

// Erstellen der Verbindung
$queue = $ctx->lookup('queue/mdb');
$factory = $ctx->lookup('ConnectionFactory');
$con = $factory->createQueueConnection();

$session = $con->createQueueSession(false, 1);

// Erstellen und Senden der Nachricht
$msg = $session->createTextMessage('Testnachricht');

$sender = $session->createSender($queue);
$sender->send($msg);

$session->close();

?>

Auf ähnliche Art und Weise funktioniert das Ganze über die PHP/Java Bridge, die in der ES-Version des Platform-Produkts von Zend enthalten ist. Diese kostenpflichtige Lösung ist vor allem für diejenigen interessant, die bereits die Zend Platform einsetzen. Der Einsatz von JMS ist folglich mit einem nicht zu unterschätzenden Aufwand verbunden. Neben der Installation und Konfiguration eines Java-Application-Servers und der Einrichtung der Queue auf diesem System, muss auch die PHP/Java Bridge korrekt installiert sein, um die Java-Klassen aus PHP heraus nutzen zu können. Wer eine einfache und schnell einsetzbare Lösung sucht, ist hier also an der falschen Stelle.

Zum Einsatz ist in der Regel eine Installation eines kompletten Java-Application-Servers notwendig. Diese Lösung hat allerdings dann ihren Reiz, wenn Sie als Nachrichtenkonsumenten Java-Programme einsetzen wollen. Dort kann eine derartige Lösung durch ihre nahtlose Integration ihre Stärken ausspielen. Je nach verwendetem Application-Server sind diese Lösungen auf hohe Last und Stabilität ausgelegt. Viele dieser Queue-Server sind seit Jahren bekannte und ausgereifte Lösungen.

[ header = Seite 2: ActiveMQ ]

ActiveMQ

ActiveMQ ist eine Message-Queue-Implementierung, die unter dem Dach der Apache-Organisation seit Jahren kontinuierlich weiterentwickelt wird und die sowohl einen beachtlichen Funktionsumfang besitzt als auch als sehr stabiles System bekannt ist. Nicht umsonst kommt ActiveMQ auch in verschiedenen Java-Application-Servern als Message-Queue-Implementierung zum Einsatz. ActiveMQ ist in Java programmiert und demnach erst einmal für den Einsatz mit PHP ungeeignet. Als Subprojekt existiert aber mit Stomp bereits seit einiger Zeit eine Lösung, mit der verschiedenste Programmiersprachen auf ActiveMQ zugreifen können. Listings 2 und 3 zeigen den schreibenden und lesenden Zugriff auf eine Queue über den PHP-Client von Stomp.

connect();
// senden einer Nachricht an die Queue
$con->send("/queue/phpmag", "Testnachricht");

// Disconnect
$con->disconnect();
?>
connect();

// Lesender Zugriff auf eine Queue
$con->subscribe("/queue/phpmag");
// Nachricht abrufen
$msg = $con->readFrame();

echo $msg->body;

// disconnect
$con->disconnect();
?>

Der Zugriff auf die Message Queue gestaltet sich damit recht einfach. Die Komplexität wird durch die PHP-Client-Bibliothek vor dem Entwickler verborgen. Wer jedoch auf der Suche nach einer einfachen und schnell einsetzbaren Lösung ist, der wird mit ActiveMQ wahrscheinlich nicht sehr glücklich werden. Der Aufwand für die Inbetriebnahme der ActiveMQ/Stomp-Lösung ist in vielen Fällen hoch. Auch ist die Software recht ressourcenhungrig. Zwar ist der Einsatz von PHP über Stomp möglich, einfach und unkompliziert ist aber wahrscheinlich keines der Attribute, die man der Gesamtlösung geben würde. Der große Vorteil liegt hier in der Möglichkeit, über ActiveMQ auch sehr heterogene Systemlandschaften miteinander verbinden zu können. Auch werden die Nachrichten persistent gespeichert und überstehen somit durchaus auch einen Ausfall des Queue-Servers.

memcached

memcached ist eigentlich keine Message Queue. Das Open-Source-Projekt hat sich in den letzten Jahren vielmehr einen hervorragenden Ruf als eine schnelle und verteilte Caching-Lösung erarbeitet. In einem Blog-Eintrag ist allerdings beschrieben, wie sich memcached auch als einfache und schnelle Message Queue einsetzen lässt. Leider steht die eigentliche Implementierung noch nicht frei zur Verfügung, der Autor hat aber bereits angedeutet, dass er die Lösung in Kürze als Open-Source veröffentlichen wird.

Die Logik hinter der Implementierung ist relativ einfach. Wie bei der Verwendung von memcached üblich werden die Nachrichten mit einem eindeutigen Schlüssel ausgestattet. Über diesen Schlüssel kann auf die Nachricht zugegriffen werden. Im Falle der Nachrichten ist dieser Schlüssel vom Typ Integer und fortlaufend nummeriert. Zusätzlich zu den Nachrichten werden in dermemcached-Instanz zwei weitere Werte gespeichert. Der erste beinhaltet den Schlüssel der ältesten Nachricht, der zweite die nächste freie Schlüsselnummer. Mit diesen Werten lässt sich die Message Queue relativ einfach aufbauen. Der Nachrichtenkonsument liest und löscht jeweils die älteste Nachricht und setzt den Wert für den ältesten Schlüssel auf den nächst höheren Wert. Der Nachrichtensender erstellt eine Nachricht mit der nächsten freien Schlüsselnummer und erhöht anschließend diesen Wert. Wer diese Funktionen in eine kleine Klasse packt und noch um ein wenig Logik erweitert, die vermeidet, dass der Wertebereich der Integer-Schlüssel überschritten wird, der hat seine eigene kleine Message-Queue-Implementierung komplettiert.

Mit dieser Art der Nutzung von memcached lässt sich eine schnelle und einfache Message Queue implementieren. Wer allerdings den Fokus auf Robustheit legt und selbst bei einem Ausfall keine Daten verlieren darf, der wird auch mit dieser Lösung nicht hundertprozentig zufrieden sein, da memcached seiner Caching-Natur entsprechend alle Daten im Hauptspeicher ablegt und auch sonst eher auf Geschwindigkeit als auf Zuverlässigkeit getrimmt ist. Im Moment erweckt diese Lösung mehr den Anschein einer „Bastelarbeit mit Potenzial“. Des Weiteren ist außer dem Blog-Eintrag weder Support noch Dokumentation vorhanden.

[ header = Seite 3: Beanstalkd ]

Beanstalkd

Beanstalkd ist ein schneller, verteilt arbeitender Dienst zum Aufbau von Message Queues. Die Verwendung ist nicht auf PHP festgelegt, sondern bietet auch den Zugriff für andere Programmiersprachen wie Ruby. Für die Nutzung mit PHP steht eine Client-Library unter Sourceforge zur Verfügung. Das System wurde ursprünglich für Facebook entwickelt, um dort komplexe Aufgaben von der eigentlichen Seitenanzeige zu koppeln und dadurch die Anzeige zu beschleunigen. Mittlerweile ist daraus ein universell einsetzbares Message-Queue-System geworden, das durchweg auf hohe Geschwindigkeit getrimmt wurde. Listing 4 zeigt den Zugriff auf die Beanstalkd Queue.

 array( '127.0.0.1:11300' ),
));
$queue->use_tube('phpmag');

// Schreibender Zugriff auf die Queue
$queue->put(0, 0, 2000, 'Testnachricht');

// Lesender Queue-Zugriff
$msg = $queue->reserve();
echo $msg->get();
Beanstalk::delete($msg);
?>

Der Aufbau erinnert ein wenig an die zuvor beschriebene memcached-Lösung, was wohl ein wenig daran liegt, dass sich die Entwickler von Beanstalkd nach eigener Aussage von dessen Protokoll haben inspirieren lassen. Vielleicht liegt darin auch eine der Schwächen der Software begründet. Denn das Hauptaugenmerk liegt auch hier auf der Performance, nicht auf der Zuverlässigkeit und Ausfallsicherheit.

Beanstalkd arbeitet rein hauptspeicherbasiert. Ein Ausfall des Systems führt somit zu einem Verlust der Nachrichten. Dieses Problem soll allerdings in einer der nächsten Versionen behoben und eine persistente Speicherung der Queue-Inhalte ermöglicht werden. Beanstalkd ist eine vergleichsweise junge Software, Dokumentation und Support fallen dementsprechend dürftig aus.

Zend Job Queue

Im Rahmen der Bemühungen, PHP für Enterprise-Anwendungen salonfähig zu machen, bietet auch Zend eine Queue-Implementierung an. Diese ist in das Zend-Platform-Produkt integriert. Dabei ist zu beachten, dass es sich hierbei nicht um eine Queue für Nachrichten, sondern für Jobs handelt. Mit der Zend Job Queue können Aufgaben in eine Warteschlange gestellt werden, die anschließend von Zend Platform zu konfigurierbaren Zeiten abgearbeitet werden. Bei den Aufgaben handelt es sich um PHP-Skripte. Listing 5 zeigt ein Beispiel, in dem ein Job in die Warteschlage gestellt wird. Dieser Job ist so konfiguriert, dass er zwei Stunden nach dem Einstellen in die Queue durch Zend Platform abgearbeitet wird.

login("passwort");

// Erstellung eines Jobs
$job = new ZendApi_Job("import.php");
$job->setScheduledTime(time() + 2*60*60);

// Einstellen des Jobs in die Queue
$id = $queue->addJob($job);
?>

Die Zend Job Queue kann allerdings noch viel mehr. Sich wiederholende Aufgaben lassen sich damit ebenso einfach erstellen wie Jobs, die von der Fertigstellung anderer Aufgaben abhängig sind. Sowohl die Jobs, als auch ihre Parameter und die Resultate können zudem zu jeder Zeit über die Administrationsoberfläche der Zend Platform eingesehen werden. Diese Lösung ist kostenpflichtig, da sie fest in das Zend-Platform-Produkt integriert ist. Da die Preise je nach Server recht happig sein können, wird es für viele Entwickler ein Grund sein, sich für ein anderes Produkt zu entscheiden. Wer allerdings eine Lösung für die zeitlich gesteuerte Abarbeitung von Aufgaben sucht, der bekommt mit dieser Software eine sehr flexible Möglichkeit an die Hand, die sich auf vielfältige Weise an eigene Bedürfnisse anpassen lässt.

[ header = Seite 4: dropr ]

dropr

Ein relativ junges Projekt ist dropr, die erste reine und freie Implementierung einer PHP Message Queue. Daher ist es kaum verwunderlich, dass dieses System von PHP aus deutlich einfacher ansprechbar ist, als die bisher vorgestellten Lösungen. Die Installation gestaltet sich auf einem Unix-System relativ einfach. Sie beschränkt sich auf den Aufruf eines Skripts und der Dienst lässt sich direkt über die Kommandozeile starten. Auch das Erzeugen von Warteschlangen ist schnell erledigt, es genügt das Anlegen eines Verzeichnisses mit den entsprechenden Benutzerrechten.

dropr besitzt sowohl auf der Client- als auch auf der Serverseite einen Nachrichtenspeicher. Sendet der Client eine Nachricht zum Server, werden diese zuerst im lokalen Speicher abgelegt und anschließend automatisch an den Server gesendet. Hierdurch wird erreicht, dass selbst beim Ausfall der Verbindung zwischen Client und Server keine Nachrichten verloren gehen und die Verarbeitung automatisch weiter stattfinden kann, sobald die Verbindung wieder möglich ist. Abbildung 1 zeigt den Ablauf eines solchen Datentransports zwischen Client und Server.

Abb. 1: Ablauf des Datentransports mit dropr

Zum Schreiben einer Nachricht genügt daher nicht allein die Angabe des Servers, auch der lokale Speicher muss mit angegeben werden. Listing 6 zeigt das Schreiben einer Nachricht in eine dropr Queue.

createMessage('Testnachricht', $peer, 'myChannel');
$msg->queue();
?>

Beim Schreiben wird neben der Queue auch noch ein Channel-Name angegeben, mit dem sich Nachrichten kategorisieren lassen. Das Auslesen einer Queue auf dem Server ist ebenso einfach und kann selektiv anhand der verwendeten Kategorie erfolgen. Listing 7 zeigt ein Beispiel hierfür.

getMessages('myChannel') as $msg) {
echo $msg->getId().':'.$msg.'
'; // Nachricht löschen $storage->setProcessed($msg); } ?>

Als Übertragungsprotokoll kommt HTTP zum Einsatz. Dropr setzt hier auf CURL, die Installation der entsprechenden PHP-Erweiterung ist demnach Grundvoraussetzung für den Einsatz der Software. Neben der eigentlichen Implementierung der Warteschlange liefert die aktuelle Version der Software auch noch Befehle zur Wartung der Queues, mit denen über die Kommandozeile beispielsweise die Anzahl der Nachrichten in einer Queue bestimmt werden können.

Dropr wird nach Aussagen der Entwickler schon seit längerer Zeit für den Jimdo-Webdienst eingesetzt und läuft dort stabil in einer Hochlastproduktivumgebung. Je nach Server schafft eine Standardinstallation von dropr erfahrungsgemäß zwischen 100 und 200 Messages pro Sekunde, was für viele Anwendungen mehr als ausreichend sein dürfte. Durch die lokale persistente Zwischenspeicherung der Nachrichten entsteht ein ausfallsicheres System, bei dem keine Daten verloren gehen.

Fazit

Wer zwei PHP-Systeme oder Tasks per Message Queue voneinander koppeln möchte, der ist mit dropr sehr gut bedient. Die aktuell vorliegende Version ist schnell und robust und kann durchaus als Backend für Produktivsysteme dienen. Wer darauf angewiesen ist, heterogene Systeme miteinander zu verbinden, der sollte eher zu einer Lösung basierend auf JMS oder einer freien Middleware-Implementierung wie ActiveMQ zurückgreifen. Dann entsteht auf Seiten von PHP zwar einiges an Mehraufwand, dafür ist man aber in der Lage, verschiedene Technologien miteinander zu verknüpfen. Die Zend Job Queues eignen sich hervorragend, um Aufgaben zeitversetzt abzuarbeiten. Wer Windows als Serversystem einsetzt, für den wird die Luft derzeit schon ein wenig dünner. Viele der vorgestellten Lösungen funktionieren nur auf Unix-basierten Betriebsystemen. Übrig bleiben hier nur die Zend Platform und die Java-basierten Lösungen auf JMS und ActiveMQ.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -