RabbitMQ zur Kommunikation zwischen zwei Systemen nutzen

Die Kommunikation zwischen zwei Systemen, beispielsweise zwischen CMS und Shop, ist immer spannend. Oft landet man bei Schnittstellen um Daten hin- und herzuschieben. Wenn es aber nur darum geht auf Signale zu reagieren, bietet sich ein Messaging System an. Wenn die Datenmenge sich schnell verändert/bewegt sind Messaging Systeme Gold wert. Zur Kommunikation bietet sich AMQP an. "AMQP (Advanced Message Queuing Protocol) stellt ein binäres Netzwerkprotokoll dar, das unabhängig von der Programmiersprache ist."

Zur Nutzung dieses Protokolls bietet sich RabbitMQ an. RabbitMQ ist eine Open Source Message Broker Software, die das Advanced Message Queuing Protocol (AMQP) implementiert. Die Installation wird euer Hoster übernehmen können oder ihr nutzt die Docker Images oder, wie im kommenden Beispiel, kann man sich ein RabbitMQ in der AWS Umgebung hochfahren.

Umsetzungsbeispiel "Youtube Konverter"

Unser Ziel ist über eine WebApplikation einen Youtube Link zu verschicken. Dieser Link wird an einen Raspberry verschickt, der das Video in eine MP3 umwandelt und dann zu Dropbox hochlädt. Wir konzentrieren uns dabei besonders auf den RabbitMQ Part.

  • Webserver
  • Raspberry mit installiertem Webserver
  • AWS Account mit RabbitMQ Instanz
  • Dropbox Account

RabbitMQ Instanz anlegen

Da dieser Schritt etwas dauert, bietet es sich an das Erstellen eines Brokers vorzuziehen. Bei Amazon dauert es gut 20 Minuten. Wenn man im Service Amazon MQ ist, muss man erst auf den Button "Broker erstellen" klicken. In der neuen Oberfläche wählt man dann das passende System aus. Per Default ist "Apache ActiveMQ" ausgewählt. Wir wählen in unserem Beispiel "RabbitMQ" aus.


Im nächsten Schritt stellen wir den Bereitstellungsmodus ein. Für unser Beispiel reicht eine Einzelinstanz aus. Je nach Datenmenge und Sicherheit bietet sich auch ein Cluster an, was natürlich die Kosten beeinflusst.


Bei den Einstellungen vergeben wir einen eindeutigen Broker Namen, z.B. Projektname_Broker. Bei der Instanz starten wir mit der einfachsten Variante mq.t3.micro, da sie kostenlos verfügbar ist.

Benutzername und Passwort benötigen wir für den Zugang zur Weboberfläche, aber auch später für die Verbindung.


Nach Ablauf von 15 bis 20 Minuten ist der Broker verfügbar. Wenn man diesen anklickt, findet man im Punkt "Verbindungen" den Endpoint zur Weboberfläche, aber auch den Endpoint für die Anwendung.

Message Push (push.php)

Um eine erste Nachricht Richtung AWS zu schicken, legen wir uns ein neues Projekt mit composer an. Zuerst installieren wir uns die passende Library php-amqplib Im Anschluss erstellen wir uns im Docroot eine push.php


composer require php-amqplib/php-amqplib
                                        

Fangen wir mit einem fixen Link an. Dies kann man ja später dynamisch gestalten. Zuerst tragen den passenden AWS Host und Nutzername und Passwort ein, um eine Verbindung herstellen zu können.


require('../vendor/autoload.php');

use PhpAmqpLib\Connection\AMQPSSLConnection;
use PhpAmqpLib\Message\AMQPMessage;

$youtubeUrl = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ';
$amazonHost = 'amqps://xxxxxxxxxxxx.mq.eu-central-1.amazonaws.com:5671';
$url = parse_url($amazonHost);

$vhost = '/';
$user = 'USER';
$password = 'PASSWORD';

$ssl_opts = ['ssl_version' => 'tlsv1.2','verify_peer' => false];
$connection = new AMQPSSLConnection($url['host'], 5671, $user, $password, $vhost, $ssl_opts);
$channel = $connection->channel();
                                        

Wir definieren nun Exchange und Queue um den Link zu verschicken. Es wird ein simpler String erwartet. Wer mit mehreren Werten in einem Array arbeiten möchte, kann z.B. mit einem JSON String arbeiten. Wenn die Nachricht dann verschickt wurde, werden Channel und Verbindung geschlossen.


$channel->exchange_declare('youtubeExchange', 'direct', false, false, false);
$channel->queue_declare('youtubeQueue', false, false, false, false);
$channel->queue_bind('youtubeQueue', 'youtubeExchange', 'youtubeRouting');

$msg = new AMQPMessage($youtubeUrl);
$channel->basic_publish($msg, 'youtubeExchange', 'youtubeRouting');

$channel->close();
$connection->close();
                                        

Wer sich tiefer mit der Materie auseinandersetzt, der kann natürlich Queue und Exchange mehrfach einsetzen. Nehmen wir an wir haben eine Applikation die mehrere Musiklinks in einer Aktion verschicken will. Dann könnte es einen "MusicExchange" geben, die eine Queue wäre z.B. für Youtube, die andre Queue könnte für Spotify Links sein.

In der RabbitMQ Doku gibt es dazu ein paar visuelle Beispiele, wie man Nachrichten sinnvoll verschicken kann.

Message Pull

Die Nachricht befindet sich nun in der Youtube Queue. Zeit diese in Empfang zu nehmen. Beim Pull kann grundsätzlich wie beim Push oben die Verbindung aufgebaut werden. Lediglich das Abholen der Nachricht sieht anders aus:


$callback = function ($msg) {
    echo $msg->body . LF;
};

$channel->basic_consume('youtubeQueue', '', false, true, false, false, $callback);
while ($channel->is_consuming()) {
    $channel->wait();
}
                                        

Den Aufruf könnte man z.B. mit /usr/bin/php pull.php über die Konsole abrufen. Bei Erfolg sieht man tatsächlich sofort die Nachricht, wenn man über ein anderes Browserfenster den Push durchführt. Da die Verbindung zur AWS nicht ewig aufrechterhalten werden kann, brauchen wir einen Dienst, der regelmäßig alles neu startet. Hinweis: Es gibt auch via PHP andere Wege, Stichwort Schleife. Aber ich hatte mich beim Raspberry für supervisor entschieden und es lief nach der Installation direkt.


[supervisord]
nodaemon=false

[supervisorctl]

[program:rabbitmq-order-export]
command=php /var/www/html/pull.php
numprocs=1
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor.rabbitmq.err.log
stdout_logfile=/var/log/supervisor.rabbitmq.out.log
                                        

Konvertierung und Dropbox Upload

Wir haben nun alle Basics, um den AWS Broker gescheit zu nutzen. Um Youtube Links zu einer MP3 umzuwandeln, kann man youtube-dl nutzen. (Bitte auch die rechtliche Komponente dabei beachten)


youtube-dl -x --audio-format mp3 --newline --prefer-ffmpeg URL
                                        

Nachdem die MP3 Variante erstellt wurde, sichere ich die Dateien in meiner Dropbox. Dafür gibt es ein schönes Shellscript

Fazit

Hätte ich dieses Wissen vorher schon gehabt, wären krude PHP Lösungen mit Cronjob, curl & Co gar nicht erst nötig gewesen. Mit RabbitMQ habe ich ein Messaging System, um schnell auf Signale/Inhalte zu reagieren. Dank AMQP gibt es einen guten Standard, den man bequem in verschiedenen Programmiersprachen nutzen kann.