Der er ikke så længe til at GOTO-konferencen starter, så i øjeblikket sidder jeg og gransker programmet. Der er 2 spor der har særlig interesse for mig og for en gangs skyld, ligger de ikke samtidig. De to spor er henholdsvis mandagens microservice-spor og tirsdagens Machine Learning-spor.
Årsagen er, at det griber godt ind i det jeg arbejder med i øjeblikket: Vi er nemlig ved bygge et nyt system fra bunden. De enkelte dele af systemet er centeret om maskinindlæringsopgaver og bygges op omkring en microservice-arkitektur. De enkelte maskinlæringsalgoritmer skal kunne blive løbende trænet. Vi modtager i omegnen af 1-2 milliarder datapunkter om dagen, som skal fødes ind i systemet, så de knap 1000 modeller kan trænes. Samtidig skal modellerne løse et tilsvarende antal opgaver dagligt. Da det er et krav at systemet kører 24/7, skal systemet skrues sammen på en måde, så en enkelt fejl i et hjørne af systemet, ikke kan påvirke andre dele. Der skal altså etableres vandtætte skotter mellem services.
Enter microservices.
En af løfterne ved microservices er, at man kan have netop vandtætte skotter mellem sine services. Det kræver dog, at man holder tungen lige i munden, når man designer dem. Hvis man designer dem “traditionelt”, kan man ende med services der har f.eks. et REST API, og ender man der har man tabt. Så er der nemlig introduceret en hård kobling mellem services, og er den ene nede, påvirker dette de services som den kaldes af. De kaldende services skal nu have fejlhåndtering der er specifik for den services som kaldes, og den hårde kobling er etableret. Man kan vel sige at de vandtætte skotter er utætte. Det er det vi vil gerne vil undgå.
For at undgå at services lækker ind i hinanden, prøver vi at skifte fra et univers af kommandoer – create, read, update, delete – til et univers af events. Events har den fordel, at de udtrykker fakta – hændelser som er sket – i modsætning til commands, som er et udtryk for en hensigt om at få noget til at ske.
I event-verdenen betyder dette, at når service #1 har modtaget data og beriget det, kalder den ikke service #2 med updateModel(data). Den lægger blot en besked på en kø om at data er opdateret, og en URL til data. Service #2 lytter efter denne besked, og når beskeden modtages, indlæser den det nye data og opdaterer sin model. På den måde kan vi deploye de to services individuelt og de har ingen indbyrdes afhængighed. Hvis service #1 er nede, kommer der ingen events og service #2 er idle. Hvis service #2 er nede, fortsætter service #1 blot med at lægge beskeder, som vil blive behandlet når service #2 engang kommer op igen. Alt er godt – særligt når man har mere end 2 services i et system som gerne skal køre 24/7.
Denne arkitektur fungerer rigtig godt, men stiller nogle krav til f.eks. overvågning, da det er sværere at opdage hvis en service er nede. Systemet som helhed fungerer jo stadig. Det øger også kompleksiteten i de tilfælde, hvor man skal finde ud af hvor langt en given opgave er nået. Derudover er der også et sikkerhedsaspekt som skal overvejes.
Dette er alt sammen noget, som jeg håber vil blive uddybet i microservice-sporet på konferencens dag nr. 2.