Event stream processing (esp), een technologie om near real-time op gebeurtenissen te reageren, is al een tijdje hot. En zoals de Gartner Hype Cycle voorspelt, duurt het dan nooit lang voordat zo’n technologie in het dal van de desillusies belandt. Esp is zo’n lot ook beschoren. Tenzij organisaties zich goed realiseren wat de consequenties zijn van deze technologie en wat je moet organiseren om alle onderdelen van de gedistribueerde architectuur met elkaar te laten communiceren.
Allereerst: waar hebben we het over? Met event stream processing (esp) kun je event driven reageren. Dat betekent dat je reageert op basis van een gebeurtenis. Een klant die langs je winkel loopt en die je wilt targetten met een persoonlijk aanbod; een ander voorstel voor een vervangende vlucht doen nog voordat de passagier in de gaten heeft dat zijn vlucht is gecanceld of ernstig vertraagd. Het is niet vreemd dat bedrijven prachtige mogelijkheden zien in deze technologie. Er wordt zelfs in directiekamers over gesproken. De techniek staat voor niets, laten we deze kans pakken.
Wat mij betreft een goed idee, maar niet zonder dat je weet waar je het over hebt. Want deze technologie biedt niet alleen veel mogelijkheden, maar is ook complex. Gedistribueerd event driven werken betekent dat je parallel reactief aan de bak gaat. Voor de duidelijkheid: over het algemeen is reactief niet een term die als vooruitstrevend wordt gezien. Maar voor bijvoorbeeld een infrastructuur die je bij een derde afneemt per transactie, is dit prima. In dit geval vergroot het je flexibiliteit enorm, maar het betekent wel dat je de complexiteit die hier aan de achterkant bij hoort moet managen. Als je de consequenties niet volledig doorziet en als je niet begrijpt dat je bijvoorbeeld op een andere manier over data en dataconsistentie moet gaan nadenken, dan kun je er beter niet aan beginnen.
De bedoeling van dit artikel is niet om bedrijven angst aan te jagen, maar om aan ontwikkelteams en it-management duidelijk te maken wat de trade offs zijn van esp en streaming, zodat zij goed beslagen ten ijs komen als ze het gesprek aangaan met het C-level.
Ander architectuurmodel
Kafka is verreweg het bekendste esp-platform. Het stelt je in staat om realtime op events te reageren, en dit met hoge beschikbaarheid en schaalbaarheid. In dit artikel gaan we daarom met name uit van Kafka, al zijn de meeste implicaties ook op andere oplossingen van toepassingen.
Oplossingen die gebruik maken van een esp hanteren over het algemeen een ander architectuurmodel. Namelijk het scheiden van lees- en schrijfacties over streams en databases. De mutaties vinden in dit geval eerst plaats op de stream en pas later op de database. Dat brengt een aantal consequenties met zich mee.
In de eerste plaats zul je moeten accepteren dat de onderliggende databases niet altijd helemaal synchroon zijn. Data die meteen wordt verwerkt in de stream wordt immers pas later een keer opgeslagen in de database. Wanneer dat later precies is, weet je niet. Het concept gaat uit van ‘eventually consistent’ in plaats van realtime consistent. Er is dus nooit één versie van de waarheid. Overigens wordt in dit soort gevallen vaak de stream als primaire waarheid gebruikt. Logisch ook, zeker als je bedenkt dat het streaming platform schaalbaar, robuust en overal beschikbaar is.
Een ander facet waar je rekening mee moet houden, is de webservices-architectuur die ten grondslag ligt aan de applicaties die je realtime wilt laten reageren. Als je webwinkel bestaat uit honderd webservices die allemaal hun eigen data gebruiken, wil je er niet honderd databases onder leggen, dat wordt te duur. Je kunt wel de webservices gebruik laten maken van event streams, wat een veel goedkopere oplossing is. Dit betekent echter wel dat je gedistribueerde event streams creëert die uiteindelijk weer bij elkaar moeten komen. Dat is prima mogelijk, het lukt immers ook om de webservices zelf met elkaar te laten communiceren. Er moet wel goed over nagedacht worden.
Bijvoorbeeld over wat te doen bij een actie die honderd keer parallel wordt aangeboden maar slechts eenmaal tot resultaat mag leiden in het achterliggende landschap. Als een klant uit ongeduld honderd keer op de submit-knop kopen drukt, mag dat maar één transactie tot gevolg hebben. De services moeten op dat gedrag zijn gebouwd. Het zogenaamde ‘idem potent’-gedrag. Dat wordt niet standaard door het onderliggende event platform geregeld, dat is gewoon onderdeel van de service implementatie. Development-werk dus.
Complexiteit managen
Het feit dat parallel event gedreven een uitdaging is, is niet nieuw. Ik vergelijk het graag met het verbouwen van een huis. De aannemer komt om een offerte te maken en schat de klus in op duizend manuren. Hij kan een timmerman, stukadoor, loodgieter, elektricien en tegelzetter sturen, die allemaal ongeveer tweehonderd uur werk hebben. Dan zou de klus in theorie in vijf weken klaar kunnen zijn, maar de praktijk is dat ze op elkaar moeten wachten. De stukadoor kan immers pas beginnen als alle waterleidingen en elektriciteitskabels zijn weggewerkt. En de tegelzetter kan pas aan het werk als het stucwerk klaar is. De klus zal dus minimaal tien weken duren.
Stel dat de opdrachtgever als harde eis stelt dat het binnen drie weken af moet zijn. Dan kun je meer mensen inhuren, maar dat betekent dat de afstemming – die met vijf werklui al complex was – nog vele malen ingewikkelder wordt. Niet onmogelijk, maar wel lastig. De kans dat er in de afstemming wat fout gaat, met rework en vertraging tot gevolg, is erg groot. Voor één bouwbegeleider is het eigenlijk niet meer te overzien, je zult een heel leger bouwbegeleiders nodig hebben. Iemand voor de woonkamer, iemand voor de keuken, iemand voor de badkamer en ga maar door. Die moeten onderling ook weer afstemmen. Je wilt immers niet in je net afgetimmerde keuken ineens nog een buis van het toilet in de badkamer naar beneden krijgen. Je voegt dus extra lagen toe die op hun beurt voor extra complexiteit zorgen. Een ding is zeker: de kosten pakken veel hoger uit dan wanneer je akkoord was gegaan met tien weken. En de kans dat je concessies moet doen, neemt significant toe.
Zo is het met webservices ook. Het is niet zo ingewikkeld om een webservice te bouwen die goed samenwerkt met vier andere webservices. Het al een stuk ingewikkelder om honderd webservices te laten samenwerken. En het wordt helemaal complex als die webservices ook nog eens via event streams realtime data van elkaar krijgen die ze realtime moeten verwerken. Net zoals met de bouw van een huis neemt de foutkans navenant toe met de complexiteit. Kortom, al je monolithische applicaties opknippen in microservices en die combineren met event streams is een mooi concept. Maar let er wel op dat je het niet teveel fragmenteert. Anders heb je, bij wijze van spreken, al die werklui tegelijkertijd in je huis rondlopen.
Eventually (in)consistent
Microservices combineren met event streams betekent ook dat het concept ‘eventually consistent’ vergaande consequenties heeft. Zoals gezegd wordt de realtime actie niet eerst in een database weggeschreven. Er gebeuren veel acties tegelijkertijd waarbij de services elkaar onderling op de hoogte houden zonder dat er één versie van de waarheid is. Natuurlijk, als je heel goed over de architectuur nadenkt en alle maatregelen neemt die nodig zijn – lees: je huurt tien bouwopzichters in die een heel procedurehandboek volgen om ervoor te zorgen dat ze binnen hun domein en onderling goed afstemmen – kun je dit wel realiseren. Maar dat brengt hoge kosten bij de implementatie van de services met zich mee. En kostenbesparing was juist een van de redenen om met microservices te gaan werken. De vraag is dus hoe hoog de uiteindelijke kostenbesparing gaat zijn als je in je berekeningen ook het managen van de complexiteitskosten meeneemt.
Een ander aspect is dat we moeten accepteren dat de databases in bepaalde mate ‘eventually inconsistent’ zijn, simpelweg omdat je van tevoren weet dat er bij de afstemming altijd wel iets tussen wal en schip valt. Dat is misschien ook niet zo erg, mits je van te voren maar goede afspraken maakt welke fouten zeker niet gemaakt mogen worden. Dat maakt dus dat je heel goed moet nadenken over: in welke gevallen is het niet zo heel erg dat mijn data niet consistent zijn en in welke gevallen is het een ramp?
Begin klein met Kafka-as-a-service
Wat kun je doen om de consequenties te leren doorzien? Ervaring opdoen, maar dan klein. En dat kan, want steeds meer partijen bieden Kafka-as-a-service. Je betaalt dan bijvoorbeeld per transactie. Tevens bieden deze platformen meer functionaliteit dan de standaard Kafka-omgeving. Dit geeft je de mogelijkheid om met esp te spelen en te onderzoeken: wat kan ik ermee? Hoe zorg ik ervoor dat de data consistent blijven? Wat doe ik in geval van failure? En wat als zo’n failure leidt tot ‘eventually inconsistent’? Op deze manier bouw je stapje voor stapje aan je esp-ervaring.
Frenk Ochse, integratiespecialist bij Conclusion Virtual Sciences