Det finns några problem med korspostningar på grund av dialekten för markdown i det ursprungliga inlägget. Speciellt de diagram som inte finns i det ursprungliga inlägget visas inte. Så kolla originalet också om du är intresserad. Jag tycker att originalet är mer begripligt
HBase-uppgradering ovanpå Event Sourcing och CQRS-arkitektur på 3 veckor
TL;DR
- Vi använde en blågrön distributionsstrategi för HBase-versionsuppgraderingen ovanpå Event Sourcing och CQRS-arkitektursystemet.
- Implementeringsmetoden fungerade ganska bra och tog bara tre veckor totalt att uppnå projektets mål. Den här upplevelsen var ny och spännande för oss. Så jag vill dela det :)
Om databasuppgradering
En databasuppgradering är alltid besvärlig och när du har att göra med sådana omständigheter i produktionsscenarier skulle du vara supernervös (jag skulle säga 100 gånger jämfört med andra produktionsoperationer som du har att göra med) .
Denna känsla är svår att dela med människor som inte har erfarenhet eller exponering i att driva databasmiljöer. Och jag tror att 99,9% av människorna skulle hålla med om du har erfarenheten och har gått igenom svåra tider i att hantera databasrelaterade operationer. Det är riskabelt och det kostar mycket, men uppgraderingen i sig betyder inte att det ger nytt värde till produkten och även om det inte prioriteras i många fall om det inte finns någon brådskande anledning.
Samtidigt är det en enorm dold risk om databasen blir "oberobar" och hur man hanterar detta problem har varit ett ämne överallt, många utvecklare och operatörer har kämpat med sådana situationer
Uppgraderingsmetod
I allmänhet skulle du ha två val.
rullande uppgradering
Den ena är en rullande uppgradering. Uppgradera databasversionen en efter en på ett sekventiellt sätt.
Jag hittade en bra förklaring här. Läs detta om du inte är bekant med ordet.
Vad menas med en rullande uppgradering inom mjukvaruutveckling?
-
Fördelar
- Data finns på ett ställe. Så du behöver inte tänka på hur du synkroniserar data mellan olika kluster och hur du garanterar att synkroniseringen fungerar perfekt.
-
Nackdelar
- När uppgraderingen är klar finns det inget enkelt sätt att återställa. Så om uppgraderingen utlöser prestandaproblem på något sätt, skulle du ha stora problem.
- Den långvariga databasen har något oväntat tillstånd som du inte kan reproducera i testmiljön. Ibland behöver man ta itu med problemet när det kommer till produktion. Och den möjligheten gör dig riktigt nervös.
blågrön distribution
Den andra är en blågrön utplacering. I det här fallet måste du tillhandahålla det uppgraderade databasklustret separat och byta applikation för att använda den nya någon gång.
Vänligen kolla det här blogginlägget om du inte är bekant med ordet "blågrön utbyggnad".
BlueGreenDeployment
Jag tror att det här tillvägagångssättet är utbrett vid implementering av webbapplikationer, men om du byter ut ordet "router" mot "applikation" och "webserver" till "databas", kan samma tillvägagångssätt användas för databasuppgradering.
-
Fördelar
- Du rör inte den löpande produktionsdatabasen under uppgraderingen. Det gör ditt liv mycket enkelt jämfört med rullande uppgraderingsmetod.
- Du kan enkelt återgå till det gamla klustret när något oväntat problem inträffar. Och du kan också distribuera förfrågningarna gradvis så att du kan minimera omfattningen om du har några problem (för att göra detta, som i "Nackdelar", måste du dock synkronisera data från nytt kluster till gammalt kluster)
- På grund av faktorn ovan kan du förkorta belastningstestningen på testmiljön något och kan fortsätta med projektet snabbt.
-
Nackdelar
- Du måste se till att data synkroniseras mellan båda databasklustren. Inte bara från gammalt kluster till det nya klustret, utan också från nytt kluster till gammalt kluster om du vill ha ett enkelt sätt att återgå efter uppgraderingen. Men ömsesidig datareplikering är ganska svårt i många fall. Det kan vara möjligt att skriva till två kluster vid varje operation, men du måste förbereda dig när endast ett kluster är nere och operationen till endast det klustret misslyckas. Den hanteringen skulle vara riktigt komplicerad.
- Du måste ha dubbelstora servrar när du kör båda klustren. Det kommer att kosta lite pengar och kan vara svårt om ditt system inte är på molninfrastruktur.
Vårt tillvägagångssätt
I grund och botten är vårt tillvägagångssätt blågrönt utplacering. Och eftersom vi har Kafka framför som event sourcing-buss, var det mycket lättare att hantera datasynkroniseringsproblemet i "Nackdelar" som anges ovan.
Aktuell arkitektur
Låt mig först presentera den grundläggande arkitekturen. Btw, vi kallar hela chattmeddelande-undersystemet "Falcon". Det är därför falkikonen finns i diagrammet.
- när en slutanvändare postar ett chattmeddelande lägger write-api meddelandedata in i Kafka
- read-model-updater ("rmu" i korthet) hämtar data från Kafka, konverterar den till read-model och lägger den i HBase
- när en slutanvändare läser chattmeddelanden, läs-api hämta meddelandedata från HBase
Jag förklarar inte varför vi väljer CQRS i det här inlägget. Så vänligen kolla bilderna nedan om du vill veta i detalj eller om du inte är bekant med konceptet CQRS.
Kafka Summit SF 2017 - Världsomspännande skalbara och motståndskraftiga meddelandetjänster med Kafka och Kafka Streams
Världsomspännande skalbara och motståndskraftiga meddelandetjänster av CQRS och Event Sourcing med Akka, Kafka Streams och HBase
Databasuppgraderingsflöde
Nu ska jag förklara hur vi gjorde databasuppgraderingen ovanpå den här arkitekturen
Steg 1: Förbered nya kluster och gör initial återställning från säkerhetskopia.
Steg 2: Förbered en annan konsument (rmu2 i detta diagram) för att synkronisera data från Kafka till ett nytt databaskluster. Du kommer att spela om gamla Kafka-händelser med början före den första återställningen. Se till att du implementerar idempotens på din konsument. Jag menar, systemet måste fungera korrekt även om samma händelse konsumeras mer än en gång.
Steg 3: När den nya konsumenten(rmu2) har kommit ikapp med de senaste Kafka-meddelandena, förbered en annan läs-api som hämtar data från det nya databasklustret. Och skicka förfrågningar till nya läs-api gradvis.
Det skulle finnas en viss tillståndsskillnad mellan det gamla klustret och det nya klustret även om datasynkroniseringen är klar på ett par millisekunder. Vi hade ett litet problem på grund av denna skillnad, så du måste bekräfta och köra en bedömningskontroll för att se vilken typ av problem som kan utlösas genom skillnaden mellan kluster och din applikationslogik. Eller om du har några bra lager framför read-api för att distribuera begäran enligt användarattribut eller något (t.ex. routing via Nginx eller Envoy som proxy), kan du bara ställa in rätt regel där och skillnaden kan hanteras effektivt och det kommer inte att vara ett problem.
Och i efterhand av det här projektet märkte vi att om du kan spegla förfrågningarna från befintliga api till nya api, kan du göra belastningstesten med produktionstrafik utan att påverka slutanvändarna.
Steg 4: Byt till ny läs-api 100 % och stäng av gamla kluster och applikationer när du är säker på att allt fungerar perfekt.
Varför jag tycker att det här tillvägagångssättet är bättre
Låt mig förklara skillnaden med den normala blågröna metoden. Ett problem i vanlig blågrönt är att du måste se till att data synkroniseras på båda klustren, helst inte bara före uppgraderingen utan även efter uppgraderingen. I detta tillvägagångssätt, istället för att använda replikeringsfunktioner som databasen tillhandahåller, tillämpas databasuppdateringarna separat via applikationen som vi skriver och förbereder. Detta tillvägagångssätt ger oss många fördelar.
För det första, eftersom de fungerar separat, behöver du inte bry dig om hur data synkroniseras på varje fas. Speciellt kommer du att behöva lite extra (och ganska tuff i de flesta fall) ansträngning för att synkronisera data från det nya klustret till det gamla klustret om du vill ha ett enkelt sätt att återgå efter uppgraderingen. Men i det här tillvägagångssättet arbetar de bara självständigt. Så du kan bara återgå till att använda gamla om något oväntat problem börjar hända efter uppgraderingen.
För det andra behöver du inte bry dig om versionskompatibiliteten mellan gamla kluster och nya kluster. Om du använder klusterdatasynkroniseringsfunktioner som databasen tillhandahåller, skulle det finnas vissa versionsbegränsningar och kompatibilitetsproblem som kan uppstå i vissa edge-fall. Men i detta tillvägagångssätt, allt du behöver göra är att förbereda oberoende applikationer som lägger in data i varje databas. Jag tror att det är problemet man kan lösa mycket lättare i de flesta fall. Och i teorin kan du inte bara uppdatera databasversionen utan också byta det nya klustret till ett helt annat (t.ex. DynamoDB) med samma tillvägagångssätt. I så fall kan du inte använda säkerhetskopieringsdata för den första installationen och behöver förbereda ett första datamigreringsprogram. Det kommer att ta lite tid, men jag tror att det är rimligt att ta itu med.
Slutsats
CQRS och event sourcing ämnen diskuteras ofta i mjukvaruarkitektur. Ur en operativ synvinkel ökar infrastrukturens komplexitet och driftskostnad att ha ett lager till som händelsebuss. Ärligt talat gillade jag inte det här tillvägagångssättet så mycket från den uppfattningen tidigare. Men vi märkte att det också förändrar hur vi driver infrastrukturen och ger oss lugnet i databasdrift. Och ja, jag är jättekul med CQRS och event sourcing nu :)
Nästa utmaning
Du kanske undrar vad vi skulle uppgradera Kafka (event sourcing bus)? Ja, det blir vår nästa utmaning. Jag hoppas att det finns ett bättre tillvägagångssätt än normal rullande uppgradering och blågrön utbyggnad. Ingenjörslivet fortsätter!