Papers we love: Reactors, channels and event streams for composable distributed programming

 
15 april 2017

Deze maand wil ik het over een paper hebben die ergens vorig jaar is gepubliceerd. Het onderwerp, de betrokkenen en het gebruikte platform zijn vrij high-profile, waardoor het me gelijk prikkelde. De paper heeft de (lange) titel Isolates, channels, and event streams for composable distributed programming.

Het idee wat hier besproken wordt is eigenlijk een soort voortborduursel op het actor model, specifiek zoals deze er in Akka uit ziet. De auteurs stellen dat wanneer je betrouwbare gedistribueerde systemen wilt bouwen dit model altijd een goede keuze is. Voordelen zijn bijvoorbeeld dat de uitgevoerde code location-transparent is — het maakt de software niet uit waar een node zit die een bericht verwerkt — en dat een actor serieel binnenkomende berichten verwerkt. Hiermee wordt een hele klasse aan concurrency bugs voorkomen.

Er worden echter ook enkele nadelen geconstateerd. De belangrijkste hebben allemaal te maken met composability van software: hergebruik door generieke componenten gezamenlijk te kunnen gebruiken. Omdat iedere actor een enkel entrypoint heeft waar berichten binnen komen (receive()) heeft dit tot gevolg dat dit een lange lijst wordt met (pattern matched) cases van berichten: wanneer moet wat worden afgehandeld? Daarnaast is het ook lastig om een specifieke combinatie van berichten af te wachten. Een actor A die zelf een bericht x moet versturen als hij berichten yen z heeft ontvangen vereist toch dat er wat maatwerk code moet worden geschreven die dit voor je doet. Dit is geen complexe code, maar er is ook geen rede om dit niet declaratief op te kunnen lossen.

De auteurs zagen dat veel systemen telkens maar weer dezelfde problemen aan het oplossen waren en stellen voor om, naast actors, een nieuw component genaamd Reactors (of Isolates uit de originele titel) te introduceren. Een reactor is eigenlijk een soort superset van de eigenschappen van een gewone actor, maar dan zonder de genoemde nadelen. Dit doen ze door drie primitieven te identificeren: reactorschannels en events. Een reactor is hier dus de ‘nieuwe actor’, of zoals de paper zegt een ‘concurrent computation and the associated program state’. Deze kan berichten versturen (‘events’ — om verwarring met ‘messages’ te voorkomen). Deze events hebben een transport nodig, dat is er in de vorm van een channel. Dit is een communicatielijn waar iedereen op kan schrijven (mits je een reference hebt) maar waar alleen de eigenaar uit kan lezen. Hiermee wordt dus een gestructureerde verwerking van events gegarandeerd, je weet precies wie er een bericht mag verwerken.

Een extra feature is dat een reactor ook meerdere channels kan hebben. Er kunnen er zoveel geopend worden als dat je wil. Hierdoor kan je dus onafhankelijke communicatielijnen tussen reactoren opstellen die hun werk kunnen doen door events heen en weer te sturen. Een belangrijk detail en voor mij hele grote pre is de type-safety van deze events en channels: beiden zijn getypeerd waardoor je dus gelijk de bekende voordelen van een type checker binnenhaalt. Daarnaast is er ook een andere toevoeging en dat is dat er naast de tell operator ! nu ook een nieuwe operater ? is die een event kan versturen naar een actor, en het antwoord hierop als future beschikbare stelt. Door deze toevoeging is een ‘async-await’ achtige manier van werken ook een stuk eenvoudiger geworden, iets wat weleens handig kan zijn.

De rest van de paper beschrijft stapsgewijs hoe er een aantal eenvoudige componenten kan worden opgebouwd die heel specifiek zijn (ze doen 1 heel klein ding zoals eenHeartBeatFailureDetector), maar toch gemakkelijk te combineren. De auteurs stellen dat je hierdoor veel gemakkelijker een gelaagder protocol kan opbouwen op een manier die veel meer hergebruik van individuele componenten realiseert. Mijn invulling is hierbij dat het meer gaat lijken op het gelaagde model a la OSI waarbij je in duidelijke en onafhankelijke lagen een protocol kunt definieren.

Ook worden er een paar nadelen aangewezen: efficiëntie (message passing is duurder als method calls), complexiteit (asynchrone processen zijn veel lastiger te analyseren) en type-safety. Dit laatste gaf ik net al aan als voordeel, maar het is ook een nadeel. Uiteindelijk kom je ook met reactors weer uit op het actor model, op die plek verlies je je type safety. Die kunnen immers berichten ontvangen en versturen van willekeurige types, waardoor je dus je garanties omtrent typering verlies. Desalniettemin zijn er in de tussenliggende stappen wel garanties die je door de compiler kunt afdwingen.

Enerzijds vind ik het concept wat hier wordt geschetst heel sterk. Ik heb zelf geen uitgebreide ervaring met Akka, maar ik ben wel groot fan van sterk getypeerde code. Nu weet ik dat er voor bepaalde (niche) usecases ook dingen als Typed Actors bestaan, maar zoals de documentatie al zegt zijn die zeker niet in alle situaties bruikbaar. De introductie van reactors lijkt hier een goede verbetering in te kunnen realiseren.

Daarnaast zie ik ook een paar punten die wellicht wat te lovend worden uitgekristalliseerd. Een daarvan is dat je dus combinators kunt loslaten op channels, en zo bijvoorbeeld events kunt transformeren. De standaard functie map() is hier dus een voorbeeld van. Daarnaast wordt er ook gewezen op scheduling-mogelijkheden, een manier om te bepalen hoe en waar een actor concreet wordt uitgevoerd. Nu ben ik redelijk goed bekend met Rx en mij bekroop het gevoel van ‘dit is gewoon Rx’. Gelukkig werd dit bij de related work sectie ook benoemd en wordt er zelfs gewezen op een verschil: Rx event streams zijn pull-based, de reactors push-based. Nu vind ik dat persoonlijk een beetje een semantische discussie op het moment dat je je Observables hot maakt, maargoed, daar verschillen de meningen misschien over. In ieder geval heb ik het idee dat niet direct veel academische waarde aan deze paper is (het zijn geen nieuwe ideeën). Aan de praktische kant wordt ik juist wel heel erg enthousiast: er worden hier duidelijke beperkingen van een wijd verspreid model aangekaart en er wordt een concrete verbetering voorgesteld. Dit is wat mij betreft een erg gave toevoeging en heeft hier mij ook gelijk zijn relevantie bewezen.


Over deze papers we love: binnen Sogyo hebben we de traditie dat we maandelijks een nieuwsbrief rondsturen. De nieuwsbrief gaat veel over interne feitjes, echter sinds februari 2015 verzorgd Kevin van der Vlist het topic: papers we love. Hij deelt met ons papers die interessant zijn om te lezen en ons kunnen inspireren. De topic is uitgegroeid tot een mooie verzameling die we ook graag hier willen delen.


Werken met ?
Kijk dan bij onze mogelijkheden voor zowel starters als ervaren engineers.


Categorieën: Gave Technologie