Azure Service Bus Messages komprimieren
In diesem Beitrag zeige ich wie man Azure Service Bus Messages komprimieren kann. Das ist nützlich um die Nachrichten in der Queue möglichst klein zu halten. Mit effizienter Komprimierung und Dekomprimierung bleibt man leichter unter den Speicherlimits der Cloud und erspart sich ein Upgrade auf einen teureren Tarif.
Azure Service Bus Messages komprimieren
Durch das Komprimieren der Messages bleibt man in der Regel unter dem gesetzten Limit der Größe einer Message in der Queue. Ich zeige wie das geht und welche Alternativen man hat, sollte es sich trotzdem nicht ausgehen.
Das Problem
Aktuell bin ich mit dem Problem konfrontiert, dass die maximale Größe der Message für die Azure Service Bus Queue die erlaubten 256 kB überschreitet. Das hat zur Folge, dass die Message der Queue nicht hinzugefügt wird und die Methode mit einer Exception abbricht. Was tun?
Im Standardsetting bietet die Queue nur eine maximal erlaubte Größe der Message von 256 kB an. Es stehen zwar einen Gigabyte für das Zwischenspeichern der Meldungen bereit, das Limit der einzelnen Message ist jedoch fix. Microsoft bietet für große Messages (1 MB – 100 MB) ein Upgrade auf das Premium Messaging an, das kostet aber dann auch gleich extra. Als Entwickler möchte man dann doch die zur Verfügung stehenden Mittel optimal nutzen, deshalb sollte man zuerst versuchen ob man durch Komprimierung der Daten doch mit dem Limit zurecht kommt.
Theorie
Ein einzelnes Message Objekt enthält neben einem Header mit Konfigurationsparametern mit fixer Größe einen variablen Teil in dem der Content der Message steht und in dem man beliebig viele eigene Properties stecken kann. Eine Microsoft.Azure.ServiceBus.Message verlangt beim Anlegen ein byte Array als Content. Was dort an Daten steht ist der Message egal. D.h. ob wir dort verschlüsselte oder komprimierte Daten schicken macht keinen Unterschied. In der Applikation kann man sich also darauf einigen den Content immer zu komprimieren und vor dem Lesen wieder zu dekomprimieren. Das kostet zwar etwas Rechenleistung, senkt aber die Größe der Nachricht deutlich (ein gesendetes Referenz XML von über 700 kB wurde dadurch auf 25 kB verkleinert).
Lösung
Ich habe für die Lösung eine statische Klasse erstellt mit 2 statischen Methoden compress und decompress. Implementiert sind diese damit sie asynchron laufen können. Mit compress wird ein übergebenes Array aus bytes komprimiert und im selben Format (byte Array) zurückgegeben. Das selbe macht die decompress Methode, aber in umgekehrter Reihenfolge. Das komprimierte byte Array wird als unkomprimiertes byte Array zurückgegeben. Als Komprimierungsfunktion wird gzip verwendet.
Zum Einsatz kommen diese Funktionen wie folgt:
Der Content vom Request der als Message abgebildet werden soll wird durch CompressAsync() in ein komprimiertes byte Array übersetzt.
Der Empfänger der Message kann den Body diese sofort mit der DecompressAsync in das ursprünglich Request Object repräsentiert als byte Array konvertieren.
Alternativen
Will man aus irgend einem Grund dich Nachrichten nicht komprimieren oder sind die Nachrichten trotz Komprimierung größer als das Limit, dann ist das zuvor beschriebene Upgrade auf Premium immer möglich. Um Kosten zu sparen könnte man aber auch andere Alternativen suchen. Eine solche wäre statt den Content in die Nachricht zu packen diesen in einem Blob Storage abzulegen und nur den Link auf die Daten in der Nachricht zu schicken. Voraussetzung dafür ist jedoch, dass das Zielsystem auch auf den Storage zugreifen kann und darf.
Fazit
Durch Komprimierung sinkt die Größe der Messsages in der Queue deutlich. Das Kompressionsverfahren ist für die vergleichsweise geringen Datengrößen effizient genug, dass im Live Betrieb keine Latenzen messbar sind. Es ist daher zu empfehlen jeglichen Content für den Service Bus zu komprimieren.