Av: Joakim Lundin

2018-02-23

Den snabbaste meddelandeplattformen

Flera gånger har jag blivit frågad om prestandan i olika meddelandeplattformar och jag har alltid känt att det varit svårt att ge ett bra svar. Meddelandeplattformar är byggda för att slussa igenom en stor mängd meddelanden på kort tid mellan sändare och mottagare och hastighet i den här bemärkelsen är ett relativt begrepp. En plattform kan vara väldigt snabb i ett sammanhang där en stor mängd klienter behöver vara uppkopplade och utbyta data samtidigt och till flera mottagare medan en annan plattform briljerar i att nå höga mättal i antal meddelande per sekund till och från en enskild klient. Dessutom påverkar en mängd andra faktorer som service-nivå (t.ex. garanterad leverans av meddelanden, persistens, klustring), funktion (t.ex. routing, access, prenumerationer) och miljö (t.ex. filsystem, nätverk, minne, OS). Det är med andra ord svårt att göra en rättvis jämförelse och få något ut av det. Står man inför valet av en meddelandeplattform rekommenderar jag därför att man i första hand tar hänsyn till de krav på funktionalitet man har på plattformen och därefter ser huruvida prestandan lever upp till förväntningarna i den miljö man vill driftsätta den i (samt att man tar höjd för skalbarhet).

En jämförelse mellan flera plattformar bör alltså ha både en kravbild av funktionalitet och en tydlig specifikation av den eller de miljöer i vilka plattformen kommer existera. En relevant jämförelse är alltså väldigt specifik medan en allmän jämförelse fortfarande kan vara intressant (rolig). Vi väljer här att göra det senare.

Villkor och förutsättningar

För att placera oss någorlunda sansat på skalan mellan relevant och intressant så sätter vi några grundläggande villkor för de tester vi gör. Villkoren har baserats på vad som i min erfarenhet är vanliga krav man ställer på meddelandekommunikation och formats för att få en enkelhet i testerna där själva överföringen av meddelandet sätts i fokus.

Persistens: Varje meddelande som skickas från klient måste persisteras på plattformen och varje meddelande som tas emot av klient ska ha varit persisterat på plattformen. Persistens i detta sammanhang betecknas av att meddelandet kommer att överleva om plattformen plötsligt går ner och i praktiken betyder det att vi i testerna kommer att spara meddelandet på disk (på ett eller annat sätt).

Sekvens: Testerna kommer inkludera både synkron och asynkron publicering från klient. Med synkron publicering menas här att meddelanden skickas sekventiellt, d.v.s. att ett meddelande inte kommer att skickas förrän klienten mottagit en bekräftelse på leverans av det tidigare meddelandet. När meddelanden skickas asynkront så kommer klienten inte att invänta någon bekräftelse på ett publicerat meddelande innan den publicerar följande. I det senare fallet kommer vi att ha en tolerans på 1000 ej bekräftade meddelanden. Likaså när vi tar emot meddelanden från servern så kommer vi att tillåta en s.k. prefetch på 1000 meddelanden vilket låter plattformen publicera löpande utan bekräftelser från klient fram tills dess att nivån är nådd.

Parallellitet: Testerna kommer att använda fyra samtidigt publicerande eller mottagande klienter. En klient definieras här som en session där meddelanden skickas eller tas emot i sekvens. Huruvida kontrolltrafiken mellan klienterna och plattformen sker i samma session kommer vi inte att ta hänsyn till. Endast en destination på plattformen får användas i sammanhanget för ett test. Datautbytet i testerna kommer (i den mån det är möjligt) att ske direkt mot destinationen.

Klustring: Endast en instans av meddelandeplattformen kommer att användas i testerna.

Meddelande: Kommer att hanteras som binär data. Ingen data utöver den som protokollet kräver kommer att användas i meddelandehuvuden eller liknande. Ingen kryptering eller komprimering av data kommer heller att användas.

Säkerhet och flödeskontroll: Vi kommer inte att sätta upp några regler för verifikation eller flödeskontroll mot de destinationer vi interagerar med (annat än vad som eventuellt krävs). Trafiken kommer inte att krypteras i sessionen mellan klient och plattform.

Urval

Valet av plattformar för testerna har gjorts med avsikt att de gemensamt ska ha ett snarlikt utbud med avseende på funktionalitet och att de dessutom är populära. I nedanstående avsnitt beskrivs plattformarna tillsammans med de anpassningar som gjorts för och val av interaktion med respektive plattform. Gemensamt för alla plattformar är att de sätts upp med endast en persistent kö som kommer att användas i testerna.

RabbitMQ

RabbitMQ är en populär och vida spridd meddelandeplattform. RabbitMQ var en av de första fanbärarna för AMQP och har en arkitektur som återspeglar sig i protokollet i dess tidigare versioner (upp till 0-9-1) då det inkluderade meddelandeartefakter så som “exchange”, “route”, “topic” och “queue”. AMQP 1.0 exluderade koncepten av de tidigare nämnda artefakterna och fokuserar enbart på själva protokollet som används mellan noder. Eftersom protokollet är så pass annorlunda i dess senare version så lever RabbitMQ kvar i version 0-9-1 och stödjer endast 1.0 genom en plug-in.

ActiveMQ

ActiveMQ är kanske den största och mest välanvända plattformen i testet. ActiveMQ går under Apache-flagg och erbjuder ett stort antal olika protokoll och APIer för kommunikation med plattformen och en kännetecknande egenskap för ActiveMQ är det stora utbudet av funktionalitet som erbjuds. I testerna kommer vi att använda både AMQP och OpenWire (som är plattformens ursprungliga protokoll). Persistens av meddelanden kan göras genom adaptrar mot en antal databaser men produkten levereras med KahaDB som standard och vilket följaktligen används i dessa tester. ActiveMQ är Java-baserad och i testerna har heapen utökats till 7GB.

ActiveMQ Apollo

Apollo är byggt med samma grundstenar som ActiveMQ och kan därför ses som ett omtag av den populära meddelandeplattformen. Apollo fokuserar på prestanda och säger sig ha en helt annan strategi och arkitektur för trådning och hantering av processer än dess företrädare. På andra plan är den mycket lik ActiveMQ och kan t.ex. på samma sätt erbjuda möjligheten att ansluta genom ett stort antal olika protokoll. För att ansluta till plattformen så kommer vi i testerna att använda AMQP. Precis som ActiveMQ körs Apollo på Java-plattformen och heapen har även för Apollo skruvats upp till 7GB.

Enterprise Message Service (EMS)

TIBCO EMS är den enda “stängda” utmanaren i testerna. TIBCO EMS är en av kärnkomponenterna i TIBCOs integrationssvit och där den sedan länge varit navet mellan de övriga produkterna i sviten. Plattformen använder ett proprietärt protokoll som tillgängliggörs med ett JMS API.

Konfiguration

Miljön har också skapats med hänsyn till att den ska vara tillgänglig för så många som möjligt, genomförandet ska vara lätt och testerna (till viss mån) ska vara replikerbara. Därför placeras plattformarna i docker-containrar och testklienten är ett enkelt kommandoradbaserat testverktyg som styrs genom ett antal inparametrar. Testerna har genomförts lokalt, d.v.s. att klienten har befunnit sig på samma fysiska maskin och datan har därmed endast överförts genom virtuella gränssnitt. Resurserna som har använts i testerna kan hittas genom listan i slutet av artikeln.

För interaktionen med plattformarna så används JMS som API i alla fall utom för RabbitMQ som tycks sakna stöd för den funktionalitet vi behöver i testerna genom JMS och AMQP 1.0 (genom det plug-in som följer med produktion).

Figur 1. Implementation av API

Tester och resultat

I testerna kommer två olika meddelanden att skickas. Ett tomt meddelanden för att få ett utslag på overhead i plattformarna samt ett meddelande innehållande 10kb slumpmässigt genererad binär data. Meddelandena kommer att skickas både synkront (sekventiellt per klient) och asynkront (utan att invänta bekräftelse från server). I de tester där klienterna agerar konsumenter tas ingen hänsyn till huruvida kommunikationen sker asynkront eller synkront. Klientens prefetch-buffer kommer att populeras till den tillåtna gränsen och meddelanden kommer att bearbetas därifrån i sekvens. Testerna körs enskilt vilket betyder att publicerare och mottagare ej kommer att vara anslutna till plattformen samtidigt. Varje testfall utförs X antal gånger vilket innebär lika många publiceringar eller mottagningar, varpå testet avslutas. En kortare sträcka på x-axeln i graferna nedan innebär följaktligen ett snabbare test. Testfallen summeras i nedanstående tabell och mer information kan hittas i det tidigare avsnittet “Villkor och förutsättningar”.

Testfall Riktning QoS Meddelandestorlek Sekvens Iterationer
1 Publicera Persistent 0kb Synkron 1 000 000
2 Publicer Persistent 10kb Synkron 500 000
3 Publicer Persistent 0kb Asynkron 1 000 000
4 Publicer Persistent 10kb Asynkron 500 000
5 Motta Persistent 0kb 1 000 000
6 Motta Persistent 10kb 500 000

Tabell 1. Testfall

Test 1: Synkron publicering (0kb)


Figur 2. Synkron publicering (0kb)

I detta test presterar TIBCO i särklass bäst från de övriga plattformarna. Samtliga plattformar tycks bibehålla en relativ konstant meddelandefrekvens över tid i takt med att kön fylls på.

Plattform Lägsta Medel Högsta
RabbitMQ 270.78 910.91 1183.43
TIBCO EMS 4255.32 16919.90 19607.84
ActiveMQ AMQP 134.048 669.13 1013.17
ActiveMQ OpenWire 212.18 634.21 1069.52
Apollo 778.21 6101.28 7812.5

Tabell 2. Meddelandefrekvens (m/s) där lägsta och högsta är taget över 1000 meddelanden

Test 2: Synkron publicering (10kb)

Figur 3. Synkron publicering (10kb)

Vi får ett liknande resultat med första testet med undantaget att ActiveMQ med bägge protokoll får en något högre meddelandefrekvens än RabbitMQ. ActiveMQ tycks märkligt nog prestera bättre efter att ködjupet passerat 300 000 meddelanden (eller 3GB).

Plattform Lägsta Medel Högsta
RabbitMQ 315.06 537.29 636.13
TIBCO EMS 3012.05 8148.63 12987.01
ActiveMQ AMQP 208.51 730.66 1811.59
ActiveMQ OpenWire 222.22 697.62 1893.94
Apollo 593.12 4861.12 6451.61

Tabell 3. Meddelandefrekvens (m/s) där lägsta och högsta är taget över 1000 meddelanden

Test 3: Asynkron publicering (0kb)

Figur 4. Asynkron publicering (0kb)

Värt att notera i siffrorna i tabellen är att högsta meddelandefrekvensen når mycket höga värden på framför allt TIBCO EMS och RabbitMQ men även för Apollo. Anledningen är att ett meddelande inte räknas som överfört förrän bekräftelsen har kommit från plattformen vilket tenderar att ske “klumpvis” eftersom plattformen tillåts att bekräfta flera meddelanden samtidigt. Notera också att ActiveMQ OpenWire är exkluderad i dessa tester då kommunikation avbryts med servern då man publicerar asynkront. Jag har ännu inte haft möjlighet att bekräfta det, men en kraftig misstanke är att klienten som tillhandahålls med ActiveMQ inte har fullt stöd för JMS 2.0.

Plattform Lägsta Medel Högsta
RabbitMQ 932.84 9152.59 1000000
TIBCO EMS 10309.28 60712.76 125000
ActiveMQ AMQP 155.16 629.39 1005.03
Apollo 1519.76 20852.01 62500

Tabell 4. Meddelandefrekvens (m/s) där lägsta och högsta är taget över 1000 meddelanden

Test 4: Asynkron publicering 10kb

Figur 5. Asynkron publicering (10kb)

Här ser vi ett intressant beteende hos Apollo som stundvis tycks nå den högsta meddelandefrekvensen för att sedan plötsligt stanna upp korta stunder. Något jag märkte under testerna var att den hade ett väldigt högt anspråk på heapen vilket också skulle kunna innebära att dessa avbrott beror på att Javas skräpsamlare plötsligt får mycket att göra. Ett annat intressant beteende är den tendens ActiveMQ visar att plötsligt prestera snabbare efter kön överstiger 3 GB. Inte heller i detta test kunde OpenWire inkluderas.

Plattform Lägsta Medel Högsta
RabbitMQ 977.52 2783.42 142857.14
TIBCO EMS 1414.43 8195.11 250000
ActiveMQ AMQP 176.87 705.05 1862.19
Apollo 60.50 6593.26 500000

Tabell 5. Meddelandefrekvens (m/s) där lägsta och högsta är taget över 1000 meddelanden

Test 5: Mottag (0kb)

Figur 6. Mottag (0kb)

I de övriga testerna har det inte gått att se någon större prestandaskillnad mellan ActiveMQ AMQP och ActiveMQ OpenWire vilket också känns naturligt eftersom det inte har verkat vara protokollet som varit plattformens flaskhals. I detta test kan det därför tyckas lite märkligt att det är så stor skillnad dem emellan. Även om det är en trolig förklaring så kan jag inte heller härleda det till en konfigurationsmiss.

Plattform Lägsta Medel Högsta
RabbitMQ 3663.00 13392.25 142857.14
TIBCO EMS 4464.28 8909.63 13513.51
ActiveMQ AMQP 220.60 1441.28 32258.06
ActiveMQ OpenWire 262.60 5803.32 333333.33
Apollo 1618.12 23586.018 111111.11

Tabell 6. Meddelandefrekvens (m/s) där lägsta och högsta är taget över 1000 meddelanden

Test 6: Mottag (10kb)

Figur 7. Mottag (10kb)

Efter en något skakig start börjar ActiveMQ med OpenWire att skyffla ut meddelanden i ansenlig hastighet och kan mycket väl kunna mäta sig med de övriga plattformarna, vilket den i andra tester här har haft svårt att göra.

Plattform Lägsta Medel Högsta
RabbitMQ 2358.49 4223.54 90909.09
TIBCO EMS 2898.55 6837.04 14705.88
ActiveMQ AMQP 126.47 1358.81 7142.85
ActiveMQ OpenWire 256.54 4705.21 34482.76
Apollo 983.28 5871.02 13513.51

Tabell 7. Meddelandefrekvens (m/s) där lägsta och högsta är taget över 1000 meddelanden

Sammanfattning

Jag vill igen understryka att det inte går att dra slutsatsen att en plattform är snabbare än en annan utifrån resultaten av testerna. Det är tydligt att i den miljö och med de premisser som testerna har genomförts så har TIBCO EMS presterat bäst i de flesta fall men jag är övertygad om att ActiveMQ som fallit något kort i dessa tester kan med gynnsamma villkor prestera bättre än TIBCO EMS. Dessutom finns ett otal möjligheter att anpassa och justera plattformarna till att prestera bättre i den miljö de är driftsatta i och antalet handpåläggningar som gjordes inför dessa tester var minimalt.

Min uppfattning är att den största flaskhalsen varken är protokollen eller de API som exponerar dem utan persistenslagret. Som jag tidigare har skrivit så använder respektive plattform sin egen strategi och teknologi för att persistera meddelanden. I de tester som genomfördes sattes plattformarna upp med endast en destination och det var aldrig mer (eller mindre) än fyra klienter som var uppkopplade mot dem. Om meddelanden skrivs och läses samtidigt och mot flera olika destinationer så sätter det helt andra villkor för hur datan ska hanteras och tillgängliggöras.

Jag måste dock erkänna att jag inte kan undvika att bli lite imponerad av den prestanda som TIBCO EMS lyckats påvisa i dessa tester och att jag faktiskt trodde att den skulle hamna längre ned i resultatlistan. Som jag tidigare flera gånger har antytt så finns det goda möjligheter att bygga vidare på testerna genom att inkludera nya villkor eller justera de befintliga och jag kommer att fortsätta att experimentera med detta när nästa tillfälle ges.

För den som själv är sugen eller nyfiken på implementationen finns de resurser som använts tillgängliga genom nedanstående lista.

#ActiveMQ #Apollo #Message-broker #RabbitMQ #TIBCO-ems

Att jobba iterativt och inkrementellt

Boktips för sommarläsningen!