Jeppe Cramon

  • Det er ved at være længe siden jeg sidst bloggede. Del 5 af min Microservice artikel serie er i støbeskeen.

    I sidste uge deltog jeg som taler ved µService Conference i London.

    Videoen fra mit foredrag og <a href="http://www.slideshare.net/jeppec/microservices-soa-reminded-of-what-it-was-supposed-to-deliver&quot; […]

  • Jeg er ret enig – mobile websites mangler tit funktionalitet og mobile applikationer giver for mig mest mening hvis de er vel byggede og det er noget jeg vil bruge tit. Ellers er websites klart at foretrække. Jeg har beskrevet min tanker her http://qed.dk/jeppe-cramon/2014/09/25/mine-take-away-punkter-fra-torsdagen-goto-cph-2014-program/

    /Jeppe

  • Keynote
    Russ Olsen holdt den bedste keynote jeg nogensinde har hørt. Titlen var “To the moon” og var fortællingen om rum kapløbet – “Et svært, men arbitrært mål, med en arbitrær deadline”. Lige som når vi laver […]

  • Keynote
    Tim Bray startede GotoCph 2014 med en lille opsang om at vi skal gøre mere for at få flere kvindelige software udviklere, så vi undgår en monokultur. Jeg er enig med Tim, men lige som ham ved jeg heller ikke hvordan vi skal sikre det. Et godt første træk er at være opmærksom på problemet (det tror jeg nu de fleste var i forvejen) og være med til at ændre holdninger gennem dialog. Dernæst kom Tim ind på udfordringer med at mere og mere rykker fra browseren over til mobile applikationer. Det er næsten ved at være nået til et punkt, hvor hver gang man besøger en hjemmeside har de travlt med at fortælle, at de har en applikation, som man kan bruge i stedet for. Hvis der er tale om en meget bedre oplevelse i gennem applikationen (det er det sjældent) og samtidigt en hjemmeside jeg bruger ofte kunne jeg overveje at bruge en dedikeret applikation. Men forestil dig en verden hvor vi har installeret en applikation for hver en hjemmeside vi kunne finde på at bruge. Madness 😉 Opdatering af applikationer er også et andet issue. Med en web applikation tager det sekunder/minutter på Android tager det timer og på iOS dage til uger.
    How I Learned to Stop Worrying and Love the Flow af Viktor Klang
    Et rigtig fint foredrag der startede med at forklare forskellen med Collections og Streams. Dernæst kom Viktor ind på hvordan de havde arbejdet frem til en standard for reactive protocols. Viktor viste nogle overbevisende demoer med Akka Stream (der er en af implementationerne af Reactive Streams standarden). Der mangler lige mht. subscription delen, men det kan skyldes at standarden bevidst ikke definerer de sprog specifikke API’er, så måske der kommer mere. Hvis du bygger microservices og/eller reaktive løsninger er Reactive Streams interessant at kigge på.
    Patterns for scalability and availability in (trading) systems af Michel André
    Dette foredrag havde flere deltagere end der var plads til, så der var en del af os der måtte bruge gulvpladsen 😉 Da den obligatoriske reklame snak var overstået, viste foredraget sig at være ganske interessant og i god tråd med det Reactive Manifesto. Michel forklarede på god vis hvor de har løst latenstids udfordringerne ved at undlade at lave databasen indgå direkte i håndteringen af handler. I stedet for indgår den reaktivt på baggrund af event hændelser. Alt i alt er fint foredrag.
    Fast Delivery af Adrian Cockcroft
    Et rigtig fint indlæg af Adrian, hvor han fortalte om Netlfix tilgang til produkudvikling, DevOps og Microservices og hvordan man gennem tiderne havde sagt at det ikke kan virke og senere at det kun ville virke for Netflix fremtil i dag hvor flere forsøger at gå i samme retning. Adrian kom ikke detaljeret ind på Microservices ud over at sige at man bør læse om Bounded Context i Domain Driven Design bogen af Eric Evans, da en Microservice bør alignes med en Bounded Context. Jeg er enig i den betragtning, men jeg synes samtidig at der mangler noget mere guidance, så vi undgår microservices der kalder microservices, der kalder microservices. Men med tiden skal det nok komme. Hvis du er nysgerrig kan du læse mere i min blog serie om Microservices.
    Deep Dive into the Big Data Landscape – Part I og Part II af Dean Wampler og Eva Andreasson
    Foredraget var som angivet i to dele. Først fik vi en god brush up til Big Data af Eva. Mit nøgle take away point var at Big Data ikke kun handler om at have store data. Selv om man kun have en 100 GB database kan man godt få foredele ud af Hadoop platformen og dens mange (sjovt) navngivne underprojekter som Pig, Hive, Spark, Shark, etc. I anden del fik vi en walkthrough af Hadoop Map/Reduce, Spark og SparkSQL af Dean Wampler med tilhørende eksempel kode. Selv om kode i præsentationer er udfordrende fik Dean fint vist hvordan rå Map/Reduce i Hadoop er meget verbose og hvordan underprojekterne kan hjælp med læsbarheden og performance.
    Afslutnings keynote af Andrew Sorensen
    Andrews keynote var helt fantastisk.Han viste hvordan han med sit eget LISP/Scheme like sprog (med flere features end jeg kan liste eller huske) kunne lave musik ved brug af simple funktionelle funktioner (som foldl). Musikken ændrede sig gennem runtime ændringer til funktioner, lambdaer, konstanter. Meget imponerende. Andrew viste også hvordan de visuelt (3D) simulrerer elektromagnetiske partikler i sproget og som afslutning en meget imponerende interaktiv skærm (med 8 stk 50-55″ full touch skærme plus 3 projektorer) i universitets bygning. 3D simuleringen var interaktiv og kunne påvirkes gennem touch skærmene. Alt i alt meget imponerende.

  • Goto Copenhagen 2014 torsdag program plan afdækkede jeg mine favorit foredrag fra torsdagens program og de udfordringer det gav mht. at vælge.

    Nu er jeg nået til fredagens program og jeg vil godt have lov at klage! 😉
    Hvis torsdagen var udfordrende mht. at vælge foredrag, så er fredagen helt umulig.
    Specielt eftermiddagen er tæt spækket med rigtig spændende foredrag, så det bliver ikke nemt at vælge.

    Læs med og giv gerne dit bud på kandidater 🙂
    10:20
    Setting a Good Example – How to improve your SbE, BDD and ATDD artefacts af David Evans

    Jeg er har anvendt og set Specification by Example (SbE/BDD/ATDD) anvendt med varierende success.
    I de tilfælde hvor man kan samarbejdede med forretningen om at skrive specifikationerne og de brugte dem som kommunikations middel og levende dokumentation har det fungeret rigtig godt.
    I andre tilfælde har jeg oplevet at afkoblingen fra tekst specifikationen, hen over test-driveren, har været for tung i forhold til den værdi man får. I de tilfælde kunne en in-language DSL være mere givtig.

    Det kunne det være super interessant at lære mere om god anvendelse fra en med endnu mere erfaring.

    The Future of C# af Mads Torgersen

    Jeg har de sidste 2 år kodet i både Java, Scala og C# og jeg må sige at jeg er blevet glad for C# der på mange måder virker som en god middelvej mellem Java og Scala.
    Det der har imponeret mig med C# er hvordan de har formået at videreudvikle sproget (i modsætning til Java). Det vil derfor være interessant at høre mere om hvor C# er på vej hen.

    Da de fleste software projekter fejler eller kommer dårligt fra land pga. uklare krav falder mit valgSetting a Good Example.
    11:30
    Big data, bad analogies af Mark Madsen

    Det virker som om gammel viden nemt går tabt og (vi) nye generationer genopfinder  ting der viser sig at være omtrent det samme som det man brugte i 60’erne/70’erne, etc.
    Bret Victor har tidligere holdt et foredrag om “The future of programming” der mege tydeligt viste hvor kort vi er kommet indenfor software udvikling.
    Appetizeren for Mark’s foredrag lyder som en oplysnings rejse i data persistens, som jeg er sikker på vil være lærerig og relevant for nutidens problemer.

    Look, no Mocks! Functional TDD with F# af Mark Seemann

    Mark er altid en garant for et interessant foredrag. Jeg har været til at par foredrag om F# og det virker som et rigtig godt sprog med nogle meget interessante konstruktions pricipper kombineret med en funktionel tilgang. Det kunne være rigtig interessant at se hvordan TDD mesteren tackler Mocks og unit testing med F#.

    I denne sammenhæng tror jeg at Big Data, bad analogies vinder, men det er et close call.
    13:20
    Responding in a timely manner – Microseconds in HFT or milliseconds in web apps, its all the the same design principles af Martin Thompson

    Jeg var blæst væk da jeg første gang så et foredrag med Martin. Han er utrolig skarp, men det der imponerede mig mest var hans indsigt i mechanical sympathy og samt viden om hvordan en moderne computer virker (L1, L2, L3 caches, Lock free algorithms, etc.) kombineret med det rigtige design (f.eks. gennem anvendelse af DDD) kan gøre en utrolig stor forskel på hvor godt ens løsning performer og skalerer.

    Event-sourcing af Greg Young

    EventSourcing er blevet populært igen. Da jeg hørte om det for knap 5 år siden var det helt nyt for mig, men det var kun fordi jeg ikke kunne min software historik. Eventsourcing/eventlogging princippet stammer tilbage fra 60’erne (så vidt jeg husker) og danner fundamentet fra hvordan mange transaktionelle systemer (f.eks. databaser) fungerer.
    Greg har været en stor inspirations kilde og er det tætteste vi kommer en Eventsourcing/Eventstore guru’en. Hvis I ikke har hørt om Eventsourcing vil jeg klart anbefale at se Gregs foredrag, som jeg har set ved en tidligere lejlighed.

    Da jeg har set Gregs foredrag tidligere vælger jeg at tage ind og se Responding in a timely manner – Microseconds in HFT or milliseconds in web apps, its all the the same design principles.
    14:40 og 15:50
    Nu går det helt galt. Der er 3, for mig, afsindig spændende foredrag der alle er delt op i 2 dele og dermed strækker sig fra 14:40 og til 16:40.

    Deep Dive into the Cloud Native Open Source with NetflixOSS – Part I af Adrian Cockcroft

    NetFlix har opensourcet en masse af de frameworks/libraries/tools som de selv bruger når de bygger deres microservices. Jeg har ikke haft tid til at lære dem alle at kende, så dette foredrag vil være en oplagt mulighed.

    Where’s Captain Kirk. Charting a Course Through Enterprise Architecture – Part I af Randy Shoup og Kevlin Henney

    Dette foredrag virker meget relevant og interessant. Enterprise Architecture er en underlig størrelse. Enterprise Arkitekter virker ofte som en gruppe mennesker med visioner der konstant løber ind i øretæver fra “forretningen” og fra IT organisationen. Det er et faktum at de fleste store organisationer lever i et mere eller mindre ordnet spaghetti kaos af systemer (monolitter), services, orkestreringer og services busser. Uanset hvad man gør virker det som om at kaos bare øges og alle er mere eller mindre utilfredse.
    Kevlin Henney plejer at være god for nogle tankevækkende foredrag og jeg ville rigtig gerne høre mere om hans og Randy Shoups tag på Enterprise Architecture.

    What is a Reactive Application Part I af Martin ThompsonViktor KlangTodd Montgomery og Kresten Krab Thorup

    Jeg er en stor tilhænger af event drevne og reaktive applikationer. Foredragholderne er spitzen klasse inden for reaktive application og Actor systemer, så det er svært at finde nogen der har en bedre indsigt. Jeg håber de kommer ind på erfaringer fra gode og dårlige løsninger, så folk kan bruge foredragene til at afgøre hvornår reaktive systemer har deres berettigelse eller måske snarere hvornår de har den rette cost benefit.
    Gode råd søges
    Jeg har endnu ikke kunne vælge foredrag for de sidste to timeslots.
    Er der nogen der allerede har set disse foredrag eller lignende og som kan hjælpe med gode råd eller anbefalinger? 🙂

  • Goto Copenhagen 2014
    Jeg glæder mig til at deltage i GotoCon i København til september. Det er ved at være 8 år siden jeg sidst deltog. Sidste gang jeg deltog følte jeg at talere talte om det samme som sidste år […]

    • Jeg kan desværre ikke hjælpe dig med din konflikt mellem Eva og Dean og Jez. Jez og Eva var mine favorit-talere til sidste års GOTO Aarhus, så begge er gode bud.

      Jeg tager et smut på GOTO Aarhus og det er det samme program som GOTO København. På den første dag glæder jeg mig særligt til et gensyn med Mads Torgersen som skal snakke om C#s fremtid, selv om jeg også gerne ville se Reactive programming-foredraget samtidigt. Derefter holder jeg mig nok til det agile track, hvor jeg f.eks. får glæde af Kathrine Kirk, (QEDs) Aino Vonge Corry, Jez Humble og ikke mindst Pragmatic Programmer forfatteren Prag-Dave Thomas.

  • Jeppe Cramon commented on the post, Pas på afhængighederne, on the site Kristjan Wager 6 years ago

    Det er nogle rigtig gode pointer du har. En af mine kæpheste mht. system/service afhængigheder er at man bliver nød til både at kigge på hvordan system/service ansvarområderne (boundaries) SAMT ens arkitekturelle tilgang (f.eks. er valget af lagdelt integration – tit med en ESB i midten – virkelig det bedste?) – alt sammen med det mål for øje at…[Read more]

  • Hej Dann

    Beklager det sene svar, kommentar notificerings mekanismen virker ikke helt stabilt.

    Du beskriver et godt eksempel på data duplikering gennem events, som er et godt mønster at tage i anvendelse når man skal bryde monolitter op. Når man indfører events i en monolit ender events tit op med at blive lidt fattige mht. semantikken. Det…[Read more]

  • Nu skal jeg ikke tale for David, men efter min mening er en af udfordringerne med TDD at linien mellem hvornår der er tale om Test Driven Development og hvornår der er tale om Test Driven Design er mudret.
    At bruge TDD til at drive API design, etc. er rigtig fint. At bruge TDD til at give svar på arkitekturelle og stor skal design ud…[Read more]

  • Del 1 – Microservices: Det er ikke (kun) størrelsen der er vigtigt, det er (også) hvordan du bruger dem
    Del 2 – Microservices: Det er ikke (kun) størrelsen der er vigtigt, det er (også) hvordan du bruger dem
    Del 4 – Microservices: Det er ikke (kun) størrelsen der er vigtigt, det er (også) hvordan du bruger dem

    Micro services: Det er ikke (kun) størrelsen der er vigtigt, det er (også) hvordan du bruger dem – Del 2 diskuterede vi endnu en gang problemerne med at bruge (synkron) 2 vejs kommunikation mellem distribuerede (micro) services. Vi diskuterede også hvordan koblings problemerne ved 2 vejs kommunikation, kombineret med mikro services, reelt resulterer i, at vi har genopfundet distribuerede objekter. Vi diskuterede også hvordan kombinationen af 2 vejs kommunikation og manglenreliable messaging og transaktioner medfører kompleks kompensations logik i tilfælde af fejl.
    Efter en genopfriskning af de 8 fejlslutninger om distribueret computing undersøgte vi et alternativ til 2 vejs kommunikationer mellem services. Vi tog udgangspunkt i Pat Hellands “Life Beyond Distributed Transactions – An Apostate’s Opinion” (PDF format) der tager det standpunkt at Distribuerede transaktioner ikke er en løsning for koordinering af opdateringer mellem services. Vi diskuterede hvorfor distribuerede transaktioner er problematiske.

    I følge Pat Helland skal vi finde løsningen på vores problem ved at kigge på:

    Hvordan vi opsplitter vores data/services
    Hvordan vi identificerer vores data/services
    Hvordan vi kommunikerer mellem vores data/services

    Del 1. og 2. blev behandlet i Micro services: Det er ikke (kun) størrelsen der er vigtigt, det er (også) hvordan du bruger dem – Del 2 og kan opsummeres:

    Vores data skal samles i klumper kaldet entiteter eller aggregates (i DDD terminologi).
    Hver aggreate er unikt identificerbar ud fra en ID (kan f.eks. være en UUID/GUID).
    Disse aggregates skal være afgrænset i størrelse, således at de efter en transaktion er konsistente
    Tommelfinger reglen er: 1 usecase = 1 transaktion = 1 aggregate.

    I denne blog post vil vi kigge nærmere på punkt 3  “Hvordan vi kommunikerer mellem vores data/services”


    Hvordan bør vi kommunikere mellem vores data/services?
    Som vi har gennemgået flere gange før, medfører 2 vejs (synkron) kommunikation mellem vores services, hård kobling og andre ubehageligheder:

    Det medfører kommunikations mæssig kobling (data og logik ligger ikke altid i samme service)

    Dette medfører også kontraktuel, data og funktions mæssig kobling samt høj latens tid (pga. netværks kommunikation)

    Lagdelt kobling (persistens ligger ikke altid i samme service)
    Temporal kobling (vores service kan ikke fungere hvis den ikke kan kommunikere med de services den afhænger af)
    Det, at vores service afhænger af andre services underminerer dens autonomi og gør den mere skrøbelig
    Alt dette medfører også behovet kompleks kompensations logik pga. manglen på reliable messaging og transaktioner.

    Genbrugelige services, 2 vejs (synkron) kommunikation og kopling

    Genbrugelige services, 2 vejs (synkron) kommunikation og kopling


    Hvis løsningen ikke er synkron kommunikation, så må svaret vel være asynkron kommunikation?
    Ja, men det afhænger af …… 🙂
    Inden vi dykker ned i detaljerne om hvad det afhænger af, så lad os først kigge på karakteristika for synkron og asynkron kommunikation:

    kommunikations former

     

     

     

     

     

     

     

     

     

     

    Ud fra disse karakteristika kan vi kort kategorisere kommunikations formerne som følger:
    Synkron kommunikation er 2 vejs kommunikation

    synchronous-communication

     

     

     

     

     

     

    Det kommunikations mønster, der er visualiseret i tegningen ovenfor, kaldes Request/Response og er samtidigt den typiske implementations fundament for Remote Procedure Calls (RPC).
    I dette mønster sender en Afsender (Consumer) en Request besked til en Modtager (Provider). Mens Modtageren processerer request beskeden kan Afsenderen principielt ikke foretage sig andet end at vente* på at den modtager et Response eller en fejl (* her vil nogle nok pointere at consumeren kan benytte sig af asynkrone platform features således at den f.eks. kan udføre flere kald i parallel, etc. Dette løser desværre ikke den temporale kobling mellem afsender og modtager. Afsenderen kan typisk ikke vente særligt længe og ikke fortsætte sit arbejde FØR den har modtaget sit Response fra modtageren). Det typiske eksekverings flow for Request/Response eller RPC er visualiseret i tegningen nedenfor.

    Synchronous communication flow

    Synkron kommunikations flow

    Som det ses af tegningen er der en stærk kobling mellem afsender og modtager. Afsenderen kan ikke udføre sit arbejde hvis Modtageren er utilgængelig. Denne form for kobling kaldes temporal kobling eller runtime kobling og er noget vi bør minimere mellem services.
     Asynkron kommunikation er 1 vejs kommunikation
    asynchronous-communication

     

     

     

     

     

     

    Med asynkron kommunikation, sender Afsenderen (Sender) en besked til en Modtager (Receiver) over en transport kanal (Channel). Afsender venter kortvarigt på at kanalen bekræfter modtagelsen af beskeden (set med afsenderens øjne sker afsendelsen af beskeden til kanalen typisk synkront) hvorefter Senderen kan fortsætte sit arbejde. Dette er essensen af en vejs kommunikation og det typiske eksekverings flow er visualiseret nedenfor:

    Asynchronous communication flow

    Asynkron kommunikations flow

    Asynkron kommunikation kaldes også ofte for messaging. Transport kanalerne i asynkron kommunikation er ansvarlige for at modtage beskeden fra afsender og for at levere beskeden til modtageren (eller modtagerne). Transport kanalen overtager, så at sige, ansvaret for besked udvekslingen. Transport kanaler kan både være simple (f.eks. understøttet med Sockets ala 0MQ) eller avancerede distribuerede løsninger med durable Queues/Topics (f.eks. vha. ActiveMQ, HornetQ, MSMQ, Kafka, etc.). I forbindelse med messaging og asynkron kommunikation snakker man tit om forskellige garantier som den pågældende kanal tilbyder: Garanteret aflevering og Garanteret besked rækkefølge.
    Hvorfor er asynkron kommunikation så ikke hele løsningen?
    Det er det reelt også, men er desværre ikkenemt som asynkront versus synkront. Det integrations mønstret der benyttes mellem vores services der afgør den reelle koblings grad. Er der tale om ægte asynkron 1 vejs kommunikation så er vi i mål mht. de fleste tilfælde.

    Udfordringen er nemlig at 2 vejs kommunikation kommer i flere afskygninger:

    Remote Procedure Call (RPC) – synkron kommunikation
    Request / Response – synkron kommunikation
    Request / Reply – også kendt som synkron over asynkron kommunikation.

    Jeg har flere gange set projekter der benyttede Request / Reply (synkron over asynkron) for at sikre at deres services ikke var temporalt koblede. Djævlen er som altid i detaljen.
    Set fra Afsenderen (Consumer) er der, for de fleste anvendelser af Request/Reply, ikke stor forskel på graden af temporal kobling mellem RPC, Request/Response eller Request/Reply, da de alle er varianter af 2 vejs kommunikations, der tvinger vores Afsender til at må ventesvar før den kan fortsætte:
    RPC - Request-Response vs Request-Reply

    Så hvad er konklusionen?
    Konklusionen er, at 2 vejs kommunikation mellem services er roden til mange problemer og specifikt til problemer der ikke bliver mindre af at vi gør vores services mindre (microservices).
    Vi har set at asynkron kommunikation kan bryde den temporale kobling mellem vores services, men KUN hvis det foregår som ægte 1-vejs kommunikation.

    Vores løsning :)

    Vores løsning 🙂

    Spørgsmålet er så, hvordan designer man services (eller microservices) der som udgangspunkt kun behøver asynkron 1 vejs kommunikation mellem hinanden (kommunikation mellem UI og services er en anden sag, hvilket vi snart kommer ind på)?

    I næste blog post vil vi kigge på hvordan vi kan splitte vores services op og hvordan de kan kommunikere med hinanden via asynkron 1 vejs kommunikation.
    Appendiks over besked garantier
    Garanteret aflevering

    Garanteret aflevering dækker over sandsynligheden for at en besked fra en Afsender vil blive modtaget af Modtageren.
    At Most Once
    Med denne afleveringsgaranti vil en Modtager modtage en besked 0 eller 1 gang. Afsenderen garanterer at beskeder kun afsendes én gang. Såfremt modtageren ikke er tilgængelig eller i stand til at gemme data relateret til beskeden (f.eks. pga. en fejl), vil beskeden ikke blive gensendt.
    At Least Once
    Med denne afleveringsgaranti bliver beskeder modtaget 1 eller flere gange (altså mindst én gang). Beskeden vil blive gensendt indtil at kanalen har modtaget en kvittering for modtagelse fra Modtageren, hvorfor beskeden kan blive modtaget mere end én gang. Manglende kvittering kan f.eks. skyldes at modtageren ikke er tilgængelig eller fejler. Gentagen aflevering af samme besked kan håndteres ved at gøre modtagerens håndtering af beskederne idempotent (idempotens beskriver den kvalitet for en operation, hvor resultat og tilstand ikke ændrer sig, selv om operationen bliver udført mere end 1 gang).
    Exactly Once
    Denne afleveringsgaranti sørger for at beskeden modtages præcist én gang. Såfremt modtageren ikke er tilgængelig eller ikke er i stand til at gemme data relateret til beskeden (f.eks. pga. en fejl), vil beskeden blive gensendt indtil en kvittering på modtagelse er blevet modtaget. Forskellen fra ”At least once” er, at leveringsmekanismen er styret gennem en koordinerende protokol, der sikrer at duplikerede beskeder bliver ignoreret.

    Nogle af de protokoller der benyttes til implementere Exactly Once afleveringsgaranti er WS-ReliableMessaging og forskellige implementationer af 2 Phase Commit.

    En anden måde at opnå den samme egenskab på,  er at benytte idempotente operationer i kombination med At Least Once garantien.

    Implementering af Idempotence kræver næsten altid, at der er en unik identifier/message ID på hver besked, som Modtager kan udnytte til at verificere om besked allerede er modtaget og behandlet. Den unikke identifier kan f.eks. være en GUID eller timestamp. Enkelte operationer kan dog opfylde idempotence uden unik identifier f.eks. Sletning af en Aggregate.
    Garanteret beskedrækkefølge
    Garanteret beskedrækkefølge, også kendt som ”In order delivery” sikrer at beskeder modtages i sammen rækkefølge som de er afsendt. Garanteret beskedrækkefølge kan kombineres med ovenstående afleverings garantier.

    Hvor garanteret aflevering har fokus på aflevering af den enkelte besked, beskæftiger garanteret beskedrækkefølge sig med koblingen eller relationen mellem flere beskeder.

    Udfordringer omkring beskedrækkefølge opstår, hvis et eller flere af nedenstående forhold gør sig gældende for kanalen mellem Afsender og Modtager:

    Der er flere veje gennem kanalen (multipath) f.eks. introduceret på grund af clustering, load balancer og anden fejltolerance indbygget i netværk og infrastruktur.
    Dead letter queues. Hvis en besked placeres i en Dead Letter queue pga. problemer med at aflevere den giver det en udfordring med hvordan denne fejl skal håndteres og hvad der skal ske med efterfølgende beskeder ind til den fejlede besked er afleveret.
    Clustering hos Afsender eller Modtager giver den udfordring at beskeder ikke afleveres til kanalen i den rigtige rækkefølge eller at beskeder afleveres i den rigtige rækkefølge, men ikke behandles af modtager i samme rækkefølge.

    • Hej Dann

      Beklager det sene svar, kommentar notificerings mekanismen virker ikke helt stabilt.

      Du beskriver et godt eksempel på data duplikering gennem events, som er et godt mønster at tage i anvendelse når man skal bryde monolitter op. Når man indfører events i en monolit ender events tit op med at blive lidt fattige mht. semantikken. Det bedste man tit kan opnå er C(R)UD events (EntitiyCreated, EntityUpdated, EntityDeleted events), så derfor plejer jeg at anbefale at sende så mange data med som muligt,så længe at hver opdatering ikke fylder for mange kB. På den måde kan modtageren selv afgøre om den ønsker at bruge event’en til noget uden først at skulle lave et synkront kald tilbage. Mange af fordelene ved data duplikering med events kan gå tabt hvis hver service, der lytter, ender med at lave kald tilbage.
      En udfordring med mange monolitter er, at de er centreret omkring databasen og database modellen. Det kan derfor være svært at afgøre hvor meget man skal sende med (her tænker jeg på associationer). Der kan være tilfælde hvor data fylder adskillige MB. I disse tilfælde bør man sende nok data med til at en service kan afgøre om den vil have flere detaljer, hvilket den så kan opnå ved at bruge forskellige læse operationer i servicen.

      Mht. competing consumers så mener jeg ikke “read after event received” løser rækkefølge problemet (idempotens problemet).
      Det er ikke utænkeligt at samme entitet opdateres hurtigt i streg. Hvis to forskellige consumers (C1 og C2), der begge deler samme database med duplikerede data, modtager en EntityUpdated event hver (vi kan kalde dem E1 og E2), vil de hver i sær forsøge at læse seneste data. Med latens tid, transaktions belastning på serveren er det ikke utænkeligt at C1, der har modtaget E1, læser data før den 2. data opdatering bliver udført.
      C1 læser de data der var klar på tidspunkt T1. MENS read transaktionen for C1 (og dermed data for E1) er igang med at blive læst, bliver den anden opdatering udført (her antager jeg isolations niveau READ_COMMITTED der er det mest normale) og E2 bliver afsendt på tidspunkt T2. E2 bliver modtaget af C2 der går igang med at læse de data, der var aktuelle på tidspunktet T2. C2’s læse transaktion går hurtigere end C1’s læse transaktion, så C2 når at opdaterer databasen med data for T2 og afslutter sit arbejde inden C1 bliver færdig.
      Note: Reelt kan overhalende/forsinkede opdateringer også ske i C1 eller i C1/C2’s database, så det løser ikke problemet at hæve isolations niveauet.

      Nu er C1 færdig med at læse data for T1 og den går igang med at opdatere C1/C2’s fælles database med disse data. C1 har nu effektivt overskrevet den opdatering C2 lige havde udført; og dermed er C1 og C2’s fællesdatabase inkonsistent, fordi den indeholder de data der var aktuelle på T1 og ikke T2.

      Den eneste måde at håndtere det på er, som du selv foreslår, at sende et opdaterings timestamp eller sekvensnummer med (i både event’en og i data der evt. bliver læst via en læse service operation); som tillader dig at sørge for at alle opdateringen til C1/C2’s database kan ske idempotent. Sekvensnummeret skal også indgå i C1 og C’2 fælles database for de duplikerede data, således at du blot kan udføre en UPDATE xxx WHERE Id=yyy AND SequenceNo = Tx. Det vil redde dig når opdateringerne sker i forkert rækkefølge.

      /Jeppe

  • Del 1 – Microservices: Det er ikke (kun) størrelsen der er vigtigt, det er (også) hvordan du bruger dem
    Del 3 – Microservices: Det er ikke (kun) størrelsen der er vigtigt, det er (også) hvordan du bruger dem
    Del 4 – Microservices: Det er ikke (kun) størrelsen der er vigtigt, det er (også) hvordan du bruger dem

    English version: http://www.tigerteam.dk/2014/micro-services-its-not-only-the-size-that-matters-its-also-how-you-use-them-part-2/

    Micro services: Det er ikke (kun) størrelsen der er vigtigt, det er (også) hvordan du bruger dem – Del 1 diskuterede vi at anvendelsen af antal linier kode er en meget dårligmålestok for om en Service har den rette størrelse og helt ubrugelig til at vurdere om en service har det rigtige ansvar.

    Vi diskuterede også problemerne ved anvendelse af 2 vejs (synkron) kommunikation mellem vores services medfører hård kobling og andre ubehageligheder:

    Det medfører kommunikations mæssig kobling (data og logik ligger ikke altid i samme service)

    Dette medfører også kontraktuel, data og funktions mæssig kobling samt høj latens tid (pga. netværks kommunikation)

    Lagdelt kobling (persistens ligger ikke altid i samme service)
    Temporal kobling (vores service kan ikke fungere hvis den ikke kan kommunikere med de services den afhænger af)
    Det at vores service afhænger af andre services underminerer dens autonomi og gør den mere skrøbelig
    Alt dette medfører også behovet kompleks kompensations logik pga. manglen på reliable messaging og transaktioner.

    Genbrugelige services, 2 vejs (synkron) kommunikation og kopling

    Genbrugelige services, 2 vejs (synkron) kommunikation og kopling

    Hvis vi kombinerer (synkron) 2 vejs kommunikation med små/mikro services, f.eks. efter tesen 1 klasse = 1 service, er vi reelt sendt tilbage til 1990’erne med Corba og J2EE og distribuerede objekter. Desværre ser det ud til at nye generationer af udviklere, der ikke oplevede distribuerede objekter og derfor heller ikke var med til at indse hvor dårlig ideen var, er igang med at gentage historien. Denne gang blot med nye teknologier, f.eks. HTTP i stedet for RMI eller IIOP.
    Jay Kreps opsummerede den nuværende Microservice tilgang, med anvendelse af 2 vejs kommunikation, meget rammende:

    Jay Kreps - Microservice == distributed objects for hipsters (what could possibly go wrong?)

    Jay Kreps – Microservice == distributed objects for hipsters (what could possibly go wrong?)

    Blot fordi at Microservices benytter HTTP, JSON og REST får ikke ulemperne ved remote kommunikation til at forsvinde. Ulemperne, som nybegyndere indenfor distribueret nemt overser, er opsummeret i de 8 fejlslutninger om distribueret computing (8 fallacies of distributed computing):

    De tror:

    Netværket er pålideligt
    Men, en hver der har prøvet miste forbindelsen til en server eller til internettet  fordi netværks routere, switche, Wifi forbindelser, etc. er mere eller mindre upålidelige. Selv i et perfekt setup, vil man kunne opleve nedbrud i netværks udstyr fra tid til anden – se blot Netværksfejl hos IBM skyld i Dankort-kaosFejlen fundet: Firewalls lagde Post Danmarks netværk ned i 11 timer eller Nedbrud i CSC’s netværk lammer Skats tastselv-service
    Latenstid er nul
    Hvad man nemt overser er at det er meget dyrere at lave et netværkskald end at lave et tilsvarende in-process kald. Båndbredden er også mere begrænset og latenstiden måles i milli-sekunder istedet for nano-sekunder over netværket. Jo flere kald der skal udføres sekventielt desto værre bliver den samlede latenstid
    Båndbredden er uendelig
    I virkeligheden er netværks båndbredden, selv på et 10 GBit netværk, er meget lavere end hvis samme kald blev foretaget in-memory/in-process. Desto flere data og kald der bliver foretaget og jo mindre vores services bliver, desto flere kald vil det medføre, desto større indflydelse har det på den ledige båndbredde
    Netværket er sikkert
    Jeg behøver vel blot at sige NSA? 😉
    Topologi ændres ikke
    Virkeligheden er anderledes. Services der er deployet til produktion vil opleve at miljøet løbende ændrer sig. Gamle servere bliver opgraderet eller flyttet (skifter evt. IP adresse), netværks udstyr bliver skiftet eller rekonfigureret, firewalls ændrer konfiguration, etc.
    Der er én administrator
    I enhver større installation vil der være flere administratorer: Netværks administratorer, Windows admin, Unix admin, DB admin, etc.
    Transport omkostningerne er nul
    Et simpelt eksempel på at dette er en fejlslutning er eksempelvis omkostningerne ved at serialisere/deserialisere fra den interne repræsentation til/fra JSON/XML/…
    Netværket er homogen
    De fleste netværk består af forskellige fabrikater af netværks udstyr, understøtter forskellige protokoller, kommunikerer med computere med forskellige operativ systemer, etc.

    Gennemgangen af de 8 fejlslutninger om distribueret computing er langt fra fuldstændig. Hvis du er nysgerrig har Arnon Rotem-Gal-Oz lavet en grundig gennemgang (PDF format).
    Hvad er alternativet til 2 vejs (synkron) kommunikation mellem services?
    Svaret kan bla. findes i Pat Hellands “Life Beyond Distributed Transactions – An Apostate’s Opinion” (PDF format).
    I sin artikel fortæller diskutterer Pat at “voksne” ikke benytter Distribuerede transaktioner til koordinering af opdateringer på tværs af transaktions skel (f.eks. på tværs af databaser, services, applikationer, etc.). Der er mange gode grunde til ikke at benytte distribuerede transaktioner, her i blandt:

    Transaktioner låser ressourcer, mens de er aktive
    Services er autonome, så hvis en anden service, gennem Distribuerede transaktioner, får lov at låse resourcer i din service er det en klar overtrædelse af autonomien
    En service kan IKKE forventes at afslutte sin processering inden for et bestemt tidsinterval – det ligger så at sige i autonomien, servicen bestemmer selv. Dvs. at det svageste led (Service) i en kæde af opdateringer bestemmer styrken af kæden.
    Låsning holder andre transaktioner fra at fuldføre deres job
    Låsning skalere ikke (hvis en given transaktion tager 200 ms og f.eks. holder en tabel lås, så kan servicen max skaleres til 5 samtidige transaktioner i sekundet – og det hjælper ikke at sætte flere maskiner op da de ikke får låsen til at vare kortere tid)
    2 phase/3 phase/X phase commit distribuerede transaktioner er skrøbelig per design.
    Så selv om de på bekostning af performance (X phase er en dyr protokol) løser problemet med opdateringer på tværs af transaktions skel, så er der rigtig mange scenarier hvor en X phase transaktion bliver efterladt i en ukendt tilstand (f.eks. hvis en 2 phase commit bliver afbrudt under commit fasen, således at alle har prepared, nogen har committet mens andre endnu ikke har. Hvis en af servicerne fejler eller er utilgængelig i forbindelse med commit fasen, så efterlades du på dybt vand uden er båd – se nedenstående tegning for forløbet af en 2 phase commit)

    2 fase commit protokol flow

    2 fase commit protokol flow

    Hvis løsningen ikke er distribuerede transaktioner, hvad er så løsningen?

    Løsningen skal findes i tre dele:

    Den ene del er hvordan vi opsplitter vores data/services 
    Hvordan vi identificerer vores data/services
    Samt hvordan vi kommunikerer mellem vores data/services

    Hvordan opsplitter vi vores data/services og identificerer dem?
    I følge Pat Helland skal data samles i klumper kaldet entiteter. Disse entiteter skal være afgrænset i størrelse, således at de efter en transaktion er konsistente.
    Dette kræver, at en entitet ikke er større end at den kan være på een maskine (for på tværs af maskiner bliver vi ellers nød til at benytte distribuerede transaktioner for at sikre konsistens, og det er jo det vi gerne ville undgå i første omgang). Det kræver også at entiteten ikke er for lille, i forhold til de usecases der benytter entiteten. Ellers vil den samlede usecase kræve interaktion med flere entiteter og så vil opdateringen på tværs af entiteter ikke være konsistent efter en transaktion, med mindre man igen brugte distribuerede transaktioner.
    Tommelfinger reglen er: en transaktion involverer kun een entitet.

    Lad os tage et eksempel fra den virkelige verden:
    På et tidligere projekt blev jeg stillet overfor et skole eksempel på hvordan misforståede genbrugs idealer og mikro opsplitning er ødelæggende for en service stabilitet, transaktionalitet, lav kobling samt latens tiden.

    Kundens tanke var sikre maksimal genbrug for to domæne koncepter, hhv. juridiske enheder (legal entity i diagrammet) og adresser, hvor adresser principielt var alt der kunne bruges til at adresse en juridisk enhed (og alt andet på jorden), så som hjemme adresse, arbejds adresse, email, telefon nummer, mobil nummer, GPS lokation, etc.
    For at sikre genbrugeligheden og koordineringen af opdateringer og læsninger, var man nød til at introducere en task service, her kaldet “Legal Entity Task Service”, der skulle koordinere arbejdet mellem data servicerne “Legal Entity Micro Service” og “Address Micro Service”. Man kunne også have valgt at lade “Legal Entity Micro Servicen” overtage rollen af Task service, men det løser ikke transaktionalitets problemet som vi skal diskuttere nu.

    For at oprette en jurdisk enhed, f.eks. en person eller et firma, skal der først oprettes en juridisk enhed i “Legal Entity Micro Service” og en til flere Adresser i “Address Micro Service” (afhængigt af hvor mange der var defineret i de data der blev givet til CreateLegalEntity() metoden i “Legal Entity Task Service”). For hver Adresse der bliver oprettet skal den AddressId, som bliver returneret fra CreateAddress() metoden i “Address Micro Service”, associeres med den LegalEntityId der blev returneret fra CreateLegalEntity() metoden i “Legal Entity Micro Service” ved at kalde AssociateLegalEntityWithAddress() i “Legal Entity Micro Service”.

    Dårlige microservices - Oprettelses scenario

    Dårlige microservices – Oprettelses scenario

    Fra sekvens diagrammet ovenfor er det tydeligt at der er tale om en høj grad af kobling (på alle niveauer). Hvis “Address Micro service” ikke svarer kan man ikke oprette nogen Juridiske enheder. Latenstiden i en sådan løsning er også høj pga. de mange remote kald. Noget af latenstiden kan minimeres ved at udføre flere af kaldene parallelt, men det er igen suboptimering af en grundlæggende forkert løsning og vores transaktions problem er stadig det samme:
    Så længe blot en enkel af CreateAddress() eller AssociateLegalEntityWithAddress() kaldene fejler står vi med et grimt problem. Vi har oprettet en Jurdisk enhed og nu er en af CreateAddress() kaldene gået galt. Vi står med et inkonsistent system. Ikke alle data er blevet oprettet og associeret.
    Det kan også være at vi har fået oprettet vores JuridiskeEnhed og alle Adresserne, men har ikke fået associeret alle Adresserne med den juridiske enhed. Igen har vi et inkonsistent system.
    Denne form for orkestrering placerer en stor byrde på CreateLegalEntity() metoden i “Legal Entity Task Service”. Den skal nu være ansvarlig for at gen-forsøge fejlede kald eller rydde op (også kendt som kompensation). Måske fejler en af oprydnings kaldende og hvad gør man så? Hvad nu hvis CreateLegalEntity() metoden i “Legal Entity Task Service” er igang med at gen-forsøge et af kaldene eller igang med at rydde op og den fysiske server den kører på bliver slukket? Har udvikleren husket at implementere CreateLegalEntity() metoden (i “Legal Entity Task Service”) så den kan huske hvor langt den var og derfor kan genoptage sit arbejde når serveren bliver startet. Har udvikleren af CreateAddress()  eller AssociateLegalEntityWithAddress() metoderne sørget for at de implementeret idempotent, således at metoderne kan gen-forsøges flere gange uden at risikere dobbelt oprettelse eller dobbelt association?
    Transaktionalitets problemet kan løses ved at kigge på usecasen og reevaluere genanvendelses tesen
    Designet af den LegalEntity (Juridiske Enhed) og Adresse servicen opstod efter at et team arkitekter havde designet en logisk kanonisk model og ud fra den havde afgjort hvad der var genbrugeligt og dermed services. Problemet er at en kanonisk data model slet ikke tager hensyn til hvordan dataene bliver brugt, altså de usecases der involverer disse data. Grunden til at det er et problem, er at den måde data’ene bliver ændret/oprettet direkte bestemmer vores transaktions grænser, også kendt som vores konsistens grænser. Data der bliver ændret sammen i en transaktion/usecase hører som udgangspunkt også sammen data mæssigt og ejerskabs mæssigt.
    Vores tommelfinger reglen udvides derfor til: 1 usecase = 1 transaktion = 1 entitet.

    Den anden fejl de begik var at se den Juridisk enheds adresse som en generel adresse og bagefter ophøje adresse til en service. Man kan sige at deres genanvendeligheds fokus gjorde, at alt der lugtede af adresse med vold og magt skulle placeres i Adresse servicen. Tesen var at hvis alle bruge denne Adresse service og hvis nu f.eks. by navnet eller postkoden for en by/by-del ændrede sig, så kunne man rette det, dette ene sted. Det sidste var måske en valid grund til at centralisere, men det havde store omkostninger for alt andet.

    Data modellen så nogen lunde sådan ud i løsningen (mange detaljer er udeladt):

    Dårlig micro service - data model

    Dårlig micro service – data model

    Som det fremgår af modellen er associationen mellem LegalEntity og Address en Shared directed association, hvilket indikerer at to LegalEntities kan dele en Address. Sådan forholdt det sig aldrig, så associationen var reelt en komposition (composite) association, hvilket indikerer et parent-child forhold; der er f.eks. ingen grund til at gemme en addresse for en LegalEntity efter at denne er slettet (igen en composite association). Parent-child forholdet viser at LegalEntity og Address hører tæt sammen, de oprettes sammen, de ændres sammen og de bruges sammen.
    Det betyder at der ikke er tale om to entiteter, men der i mod een entitet LegalEntity (vores omdrejningpunkt) med Addresse objekter tæt knyttet. Det er her Pat Hellands Entitets navngivning med fordel kan udvides/beriges af Domain Driven Designs (DDD) mere rige sprog, der inkluderer:

    Entity – der beskriver et objekt der er defineret ud fra dens identitet (og ikke dens data) – f.eks. en Juridisk enhed (en Person har et CPR nummer, et firma har et CVR nummer)
    Value Object – der beskriver et objekt der er defineret ud fra dens data og ikke dens identitet, f.eks. en Adresse, Navn, Email adresse. Et value objekt har som nævnt ikke nogen identitet, to Value objekter af samme type med samme værdier er ens (equal). Et Value objekt eksisterer aldrig alene, den indgår altid i en sammenhæng med en Entitet, som Value objektet så at sige beriger gennem dens data.
    Aggregate – der beskriver en samling/klynge af sammenhængende (coherent) objekter med komplekse associationer. En Aggregate benyttes til at sikre invarianter og garantere konsistens for sammenhængen af objekter. En Aggregate benyttes bla. til overordnet låsning og transaktionel konsistens i forbindelse med distribuerede systemer.

    En Aggregate vælger en Entity til at være rod (root) og den kontrollerer adgangen til objekter inden i Aggregaten. Denne kaldes en Aggregate Root.
    En Aggregate er unik identificerbar gennem en ID
    Andre Aggregater referer til hinanden via deres ID – der anvendes ALDRIG memory pointers eller Join tabeller (dette vender vi tilbage til i næste blog post)

    Ud fra denne beskrivelse kan vi afgøre at det Pat Helland kalder en Entitet i DDD jargon hedder en Aggregate. DDD’s sprog er mere rigt, så derfor vil jeg fremover benytte DDD’s navngivning. Hvis du er mere interesseret i Aggregates kan jeg anbefale Gojko Adzic’s artikel.

    Ud fra en vores usecase analyse (LegalEntity og Adresse oprettes og ændres sammen) og med anvendelsen af DDD’s jargon (LegalEntity er en AggregateRoot og en Entitet, samt Address er et value objekt) kan vi nu redesigne data modellen (også kendt som domæne modellen):

    LegalEntity Microservice - bedre model

    LegalEntity Microservice – bedre model

    Med ovenstående design er AddressId’en forsvundet fra Address, da den ikke har behov for det eftersom at der er tale om et Value objekt.
    Vores LegalEntity har stadig sin LegalEntityId og det er den vi refererer til når vi kommunikerer med LegalEntity microservicen.
    Efter model redesignet har vi gjort Adresse servicen overflødig og tilbage har vi kun Legal Entity Micro servicen:

    Bedre LegalEntity Microservice

    Bedre LegalEntity Microservice

    Med dette design er vores transaktionalitets problem helt forsvundet, da der kun er een service at tale med i dette eksempel.
    Der er meget der stadig kan forbedres her og vi har heller ikke dækket hvordan man kommunikerer mellem services så vi sikre koordinering og konsistens mellem services når vi har processer/usecases der går på tværs af aggregates/services.

    Denne blog post er allerede ved at være for lang, så jeg vil vente med at dække dette til næste blog post.

    Indtil da, som altid er jeg interesseret i feedback og tanker 🙂

  • Java 8 er tæt på at blive frigivet, 18/3-2014 er datoen hvor Java endelig får Lambda expressions og nye API’er der gør det nemmere at anvende funktionelle principper. I anden sammenhæng har jeg produceret en […]

  • Jeg er enig i at en synkron løsning hvor alt sker sekventielt er nemmere at implementere og forstå. Og nogen gange er det også den løsning der er bedst. Typen af løsning, levetiden, time to market er alle med til […]

  • Jeg var også meget varm fortaler for sprog X og framework Y da jeg var yngre. Som tiden går og man modnes begynder man at se mønstre gentage sig – man kan forledes nemt til at afvise nye tiltag med “det har vi […]

  • Del 2 – Microservices: Det er ikke (kun) størrelsen der er vigtigt, det er (også) hvordan du bruger dem
    Del 3 – Microservices: Det er ikke (kun) størrelsen der er vigtigt, det er (også) hvordan du bruger dem
    Del 4 – Microservices: Det er ikke (kun) størrelsen der er vigtigt, det er (også) hvordan du bruger dem

    Nu er vi endelig nået frem til den spændende udvikling jeg hintede til i SOA – Hierarki eller organisk vækst?
    I sidste blog post SOA: synkron kommunikation, data ejerskab og kobling gennemgik vi de 4 Principper for Service Orientation og fokuserede specifikt på Service ansvars afgrænsning og autonomi problemerne med (synkron) 2 vejs kommunikation mellem Services. Med den viden er vi godt rustet til emnet for denne blogpost.

    Emnet, som titlen indikerer, er micro services, der på mange måder er et modsvar til monolitiske arkitekturer. Lige som for SOA har Micro services desværre heller ikke nogen klar definition. Det eneste man kan blive enige om er, at de er små og de er individuelt deployerbare. Tommelfinger reglen er 10-100 linier kode (for sprog med minimal ceremoni og excl. frameworks og libraries – selv om det sidste er til diskussion blandt puristerne). Antal linier kode er efter min mening en horribel måle stok til at afgøre om en (micro) service har den rette størrelse eller for den sags skyld er en god service.
    Der mangler generelt nogle gode retnings linier for at designe micro services mht. ansvarsområde (størrelsen) og integrations form (hvordan man bruger dem). Uden disse retnings linier bliver det svært at adskille skidt fra kanel og man kan nemt fristes til at påstå at den udskældte lagdelte SOA (se tegningen nedenfor) også overholder micro service tommelfinger reglen (og så ved vi godt at nogle vil fristes til at krydse micro services af på deres liste og sige at dem har de også, uden at kigge nærmere på hvad micro services handler om og dermed aldrig komme i nærheden at designe ordentlige micro services).

    Så er services i en klassisk lagdelt SOA reelt microservices?

    Er lagdelt SOA også en microservice arkitektur?

    Er lagdelt SOA også en microservice arkitektur?

    Entity/Data Services er tynde services der har omtrent samme rolle som en Repository/Data-Access-Object fra klassisk lagdelt OO kode. En Entity service er en tynd skal oven på en (typisk) relationel database. Alt efter sprog og framework kan et (REST/Web) Service eksponeret Repository implementeres på 10 til ca. 300 liniers kode.
    Micro service størrelses regel overholdt – CHECK

    Task services er tynde services der koordinerer/orkestrerer kald til flere Entity services. Alt efter framework/library og omfang af data konvertering kan det implementeres med 10 til 1000 linier kode.
    Micro service størrelses regel overholdt – CHECK til omtrent check

    Proces Services er tynde til semi tynde services der koordinerer kald mellem flere Task services. Der er typisk lidt mere arbejde i koordineringen, da der typisk er behov for både at konvertere data, håndtere kompensationer i tilfælde af opdaterings fejl samt behov for lange transaktioner. Alt efter framework og library (f.eks. BPEL og en ESB) kan en process service implementeres på 100 til nogle tusinde liniers kode.
    Micro service størrelses regel overholdt – omtrent CHECK

    Som vi diskuterede i SOA: synkron kommunikation, data ejerskab og kobling er (synkron) 2 vejs kommunikation, som anvendes i lagdelt SOA, dybt problematisk mht. Service ansvars-afgrænsing og service autonomi. Blot behovet for kompensationer i process og tildels task services involverer en del kompleksitet. Et andet problem er kontraktuel og temporal stabilitet. Hvis blot én enkelt service er nede, er der intet eller meget lidt der fungerer. Latens tiden (tiden fra en service bliver kaldt til der er svar) er typisk også høj, da der skal kommunikeres med mange services over en netværks protokol.

    Udelukkende ud fra reglen om at Micro services indeholder få linier kode kan man med tilnærmelse sige at Entity/Task/Process Services alle er microservices. Det viser, med al tydelighed, at anvendelsen af linier kode til at afgøre om en service er en micro service eller for den sags skyld en god service er elendig!

    Latens tiden bliver ikke mindre hvis vi dekomponerer vores services yderlige og laver rigtige micro services og bagefter lader dem kommunikere 2 vejs. Hvis omdrejnings punktet for micro services udelukkende er størrelse og ikke anvendelses formen er det ikke svært at forestille sig et stjerne diagram af services: Vores applikation kalder en service der igen kalder en masse små (genbrugelige) services, der potentielt kalder en andre services, der igen kalder andre services. Cirkulære kald bliver også svære at undgå.

    Micro services stjerne 2 vejs (synkron) kommunikations diagram. Service kalder services der kalder services, etc.

    Micro services stjerne 2 vejs (synkron) kommunikations diagram. Service kalder services der kalder services, etc.


    I vores forsøg på at dekomponere vores services har vi fået lavet dem meget små (f.eks. ansvarlig for få data attributter). Det skaber nemt den udfordring at de individualle services for behov for at snakke med hinanden for at kunne udføre en opgave. De bliver så at sige misundelige på hinandens data og funktionalitet.
    Et af målene med service orientering var at sikre genbrug. Hvordan sikrer man højest mulig genbrug? Lav alle service så små at de kan genbruges i så mange forskellige sammenhænge som muligt.

    Logikken er fin, problemet er blot at hver gang vi har genbrug har vi også kobling. Et af de andre mål med service orientering var at sikre en løs kobling så vi nemt kan kan ændre i vores services for at følge med forretningen.
    SOA: synkron kommunikation, data ejerskab og kobling diskutterede vi at (synkron) 2 vejs kommunikation medfører nogle ret hårde former for kobling der ikke er ønskværdige:

    Kommunikations mæssig kobling (data og logik ligger ikke altid i samme service)
    Lagdelt kobling (sikkerhed, persistens ligger ikke i samme service)
    Temporal kobling (vores service kan ikke fungere hvis den ikke kan kommunikere med de services den afhænger af)

    Kobling har den side effekt at den skaber kaskade effekter: Når en service ændrer sin kontrakt bliver det noget ALLE services der er afhængige af servicen skal forholde sig til. Når en service er utilgængelig er alle services der afhænger af servicen reelt også utilgængelige. Når en service fejler i forbindelse med en data opdatering bliver alle andre services der er involveret i samme koordinerede process/opdatering også nød til at forholde sig til den fejlede opdatering (process kobling):

    Skete fejlen inden servicen modtog beskeden og udførte opdateringen eller skete der efter?

    Skete fejlen inden servicen modtog beskeden og udførte opdateringen eller skete det efter?

    I eksemplet ovenfor udfører en klient, som kunne være en anden service, et kald mod en service. Da kommunikationen er 2 vejs foregår kaldet ved at klienten sender et Request besked til Servicen. Servicen modtager Requestet og udfører en eller anden form for processering, f.eks. opdatering af en database. Efter endt processering sender Servicen en Response besked tilbage til klienten for at indikere resultatet. Kommunikationen foregår via netværket, f.eks. HTTP kald eller Kø beskeder. Netværk er langsomme og mindre pålidelige end de in-memory kald som vi er vant til fra vores monolitiske applikationer.

    Hvis klienten løber ind i en timeout eller anden form for netværks IO fejl er der typisk 2 årsager:

    Enten nåede Request beskeden ikke frem til Servicen, som derfor ikke opdaterede databasen.
    Eller også nåede Request beskeden frem og Servicen opdaterede databasen, men Response beskeden nåede aldrig tilbage til klienten.

    Manglen på Reliable Messaging gør at klienten ikke ved om Servicen har udført opgaven og den står nu med et problem: Hvad skal den gøre?

    Skal den forsøge at spørge Servicen om kaldet gik godt og i tilfælde af at det fejlede genprøve kaldet?
    Skal den blindt prøve kaldet igen?
    Skal den prøve at kompensere for kaldet?
    Eller skal den give op?

    Sidste reaktionen plejer at være den fremherskende løsning.

    Hvis klienten prøver kaldet igen skal Service operationen være implementeret så den kan håndtere flere ens kald/request beskeder og stadig kun udføre sin opdatering een gang (også kaldet idempotens).
    Hvis kaldet til Servicen var en del af en serie opdaterings kald til flere Services står vi med et større konsistens problem, da vi ikke har, kan eller bør benytte distribuerede transaktioner til at håndtere koordineringen af opdateringen. Som vi så i SOA: synkron kommunikation, data ejerskab og kobling er kompensations logikken ikke nødvendigvis triviel eller simpel at implementere med 2 vejs kommunikation:

    Transaktions kompensation ved synkron integration

    Transaktions kompensation ved (synkron) 2 vejs integration

    Forestil dig en ekstrem micro service arkitektur hvor hver service kun er ansvarlig for een attribute (f.eks. fornavn, efternavn, vej navn, vej nr, post nr, by, etc.). Med et sådan design bliver latens tiden et stort problem, stabiliteten kun værre og vores koordinerings og kompensations problem meget større. Der må mangle noget til at guide os til et bedre service design!

    I næste blog post skal vi se på hvordan man man kan integrere services i en distribueret verden og hvilken betydning det har for granulariteten af vores services og hvordan vi integrerer dem. Indtil da, ser jeg frem til jeres kommentarer, spørgsmål og ideer 🙂

    English version: http://www.tigerteam.dk/2014/micro-services-its-not-only-the-size-that-matters-its-also-how-you-use-them-part-1/

  • Hej Rasmus,

    Når du snakker om siloer, hvilket granulerings niveau har du i tankerne?

    For mig kan en silo kan være en aggregate (en samling af samhørende objekter mht. transaktionalitet og konsistens) eller […]

  • Det er en rigtig interessant problemstilling du bringer op, specielt fordi der er mange aspekter der spiller ind.
    Det centrale spørgsmål er hvordan er projekt organiseringen mht. de forskellige systemer og […]

  • Hej Rasmus,

    Kan du ikke uddybe pkt 4 “Arbejd gerne i siloer” lidt mere – jeg synes du diskutterer både for og imod (eller også læser jeg den forkert) ?

    /Jeppe

  • Hej Steen. Mange tak 🙂

  • Load More