Q: Én serviceserver, én database, operation: forespørg brugerens nuværende saldo, træk 3% af den nuværende saldo fra som håndteringsgebyr
Synkroniseret lås DB-lås
Q: To serviceservere, én database, operation: forespørg brugerens aktuelle saldo, træk 3% af den aktuelle saldo som håndteringsgebyr Distribuerede låse
Hvilken slags distribueret lås har vi brug for? Den kan sikre, at i en distribueret applikationsklynge kan den samme metode kun udføres af én tråd på én maskine ad gangen.
Hvis denne lås er en reentranst-lås (undgå deadlocks)
Denne lås er bedst til at være en blokeringslås (overvej, om du vil have denne i henhold til din virksomheds behov)
Denne lås er bedst at være en fair lock (overvej, om du vil have denne eller ej, alt efter forretningsbehov)
Der findes meget tilgængelige funktioner til erhvervelse og frigivelseslås
Ydelsen af opkøbs- og frigivelseslåsene er bedre
1. Distribuerede låse baseret på databaser
Distribuerede låse baseret på tabelbaserede implementeringer
Når vi vil låse en metode, udfør følgende SQL: indsæt i methodLock(method_name,desc) værdier ('method_name','desc')
Fordi vi har lavet en unikhedsbegrænsning på method_name, hvis flere forespørgsler sendes til databasen samtidig, vil databasen sikre, at kun én operation kan lykkes, og så kan vi antage, at tråden, der med succes har opnået metodelåsen, kan udføre indholdet.
Når metoden udføres, og du vil frigive låsen, skal du udføre følgende SQL: slette fra methodLock, hvor method_name ='method_name'
Denne simple implementering ovenfor har følgende problemer:
- Denne lås afhænger af databasens tilgængelighed, som er et enkelt punkt og vil gøre forretningssystemet utilgængeligt, når databasen bliver lagt på pause.
- Denne lås har ingen udløbstid, og når oplåsningsoperationen fejler, forbliver låseposten i databasen, og andre tråde kan ikke længere få fat i låsen.
- Denne lås kan kun være ikke-blokerende, fordi indsættelsesoperationen af data direkte vil rapportere en fejl, når indsættelsen fejler. Tråde, der ikke får låse, vil ikke komme ind i køen og skal igen udløse låseopkøbsoperationen for at få låsen igen.
- Låsen er ikke-re-re-intrant, og den samme tråd kan ikke få låsen igen, før den er frigivet. Fordi dataene i dataene allerede eksisterer.
- Denne lås er en uretfærdig lås, og alle trådene, der venter på låsen, konkurrerer om låsen ved held.
Selvfølgelig kan vi også løse ovenstående problemer på andre måder.
- Er databasen et enkelt punkt? Byg to databaser, og dataene vil blive synkroniseret i begge retninger. Når du har lagt på, skifter du hurtigt til backup-biblioteket.
- Ingen udløbstid? Lav bare en planlagt opgave for at rydde op i timeout-dataene i databasen med jævne mellemrum.
- Ikke-blokerende? Lav en while-loop, indtil indsættelsen lykkes og derefter returnerer succes.
- Ikke-reentrant? Tilføj et felt til databasetabellen for at registrere værtsinformation og trådinformation for den maskine, der aktuelt får låsen, og næste gang du får låsen, skal du først forespørge databasen; hvis værtsinformationen og trådoplysningerne for den nuværende maskine kan findes i databasen, kan du direkte tildele låsen til ham.
- Uretfærdigt? Opret en anden mellemtabel til at registrere alle tråde, der venter på låsen, og sorter dem efter oprettelsestidspunkt, og kun den først oprettede kan få fat i låsen
Distribuerede låse baseret på eksklusive låse
Ud over at tilføje og slette poster i datatabellen kan distribuerede låse også implementeres ved hjælp af de låse, der følger med dataene.
Vi bruger også den databasetabel, vi lige har oprettet. Distribuerede låse kan implementeres gennem eksklusive låse på databaser. Den MySQL-baserede InnoDB-motor kan bruge følgende metoder til at implementere lock-up-operationer:
Hvis du tilføjer opdatering efter forespørgselssætningen, vil databasen tilføje en eksklusiv lås til databasetabellen under forespørgselsprocessen. Når en eksklusiv lås tilføjes til en post, kan andre tråde ikke længere tilføje en eksklusiv lås til posten på den pågældende linje.
Vi kan tænke, at tråden, der opnår den eksklusive lås, kan opnå den distribuerede lås, og når låsen er opnået, kan metodens forretningslogik udføres og derefter låses op gennem følgende metoder:
public void unlock(){ connection.commit(); }
via connection.commit(); operation for at åbne låsen.
Denne metode kan effektivt løse de ovennævnte problemer med manglende evne til at frigøre låsen og blokere den.
Blokerer låse? For update-sætningen returneres straks efter vellykket udførelse og forbliver blokeret, indtil den lykkes.
Tjenesten er slukket efter låsen, kan ikke frigives? På denne måde frigør databasen låsen af sig selv, efter at tjenesten er nede.
Det løser dog stadig ikke direkte problemet med database-single point, reentrancy og fair locking.
For at opsummere måden at bruge databasen til at implementere distribuerede låse, som begge er afhængige af en tabel i databasen, er den ene at afgøre, om der er en lås ved at eksistere poster i tabellen, og den anden er at implementere distribuerede låse gennem databasens eksklusive lås.
Fordele ved distribueret låsning i databaser
Direkte med hjælp fra databasen er det nemt at forstå.
Ulemper ved implementering af distribuerede låse i databaser
Der vil opstå forskellige problemer, og hele løsningen vil blive mere og mere kompleks i processen med at løse problemet.
Driften af databasen kræver visse overhead, og der skal tages hensyn til ydelsesproblemer.
2. Distribuerede låse baseret på cache
Sammenlignet med den databasebaserede distribuerede låseløsning vil den cache-baserede implementering yde bedre med hensyn til ydeevne.
Der findes mange modne caching-produkter i øjeblikket, herunder Redis, memcached osv. Her tager vi Redis som eksempel for at analysere metoden med at bruge cache til at implementere distribuerede låse.
Der findes mange relaterede artikler på internettet om implementering af distribuerede låse baseret på Redis, og hovedimplementeringsmetoden er at bruge Jedis.setNX-metoden.
Der er også flere problemer med ovenstående implementering:
1. Enkeltpunktsproblem.
2. Denne lås har ingen udløbstid; når oplåsningsoperationen fejler, vil låseposten være i redis hele tiden, og andre tråde kan ikke længere få fat i låsen.
3. Denne lås kan kun være ikke-blokerende, og den vil vende direkte tilbage uanset succes eller fiasko.
4. Denne lås er ikke-re-indførende; efter en tråd har fået låsen, kan den ikke få låsen igen, før den frigiver låsen, fordi nøglen, der bruges, allerede findes i redis. setNX-operationer kan ikke længere udføres.
5. Denne lås er uretfærdig, alle ventende tråde starter setNX-operationer samtidig, og heldige tråde kan få låsen.
Selvfølgelig er der også måder at løse det på.
- I dag understøtter mainstream caching-tjenester klyngeudrulning for at løse enkeltpunktsproblemer gennem klyngedannelse.
- Ingen udløbstid? SetExpire-metoden redis understøtter indkommende udløbstid, og dataene slettes automatisk efter tidspunktet er nået.
- Ikke-blokerende? mens de gentagne gange blev henrettet.
- Er det ikke muligt at genindtræde? Når en tråd har fået låsen, gem den aktuelle hostinformation og trådinformationen, og tjek om du ejer den nuværende lås, før du får den næste gang.
- Uretfærdigt? Sæt alle ventende tråde i en kø, før en tråd får en lås, og erhverv derefter låsen på en first-in, first-out-basis.
Synkroniseringspolitikken for redis-klyngen tager tid, og det er muligt, at tråd A får en lås efter at have sat NX korrekt, men denne værdi er ikke blevet opdateret til serveren, hvor tråd B udfører setNX, hvilket vil forårsage samtidighedsproblemer.
Salvatore Sanfilippo, forfatteren til redis, foreslog Redlock-algoritmen, som implementerer distribueret låsehåndtering (DLM), der er mere sikker og pålidelig end en enkelt node.
Redlock-algoritmen antager, at der findes N redis-noder, som er uafhængige af hinanden, generelt sat til N=5, og at disse N noder kører på forskellige maskiner for at opretholde fysisk uafhængighed.
Trinene i algoritmen er som følger:
1. Klienten får den aktuelle tid i millisekunder. 2. Klienten forsøger at opnå låsen af N noder (hver node får låsen på samme måde som cachelåsen nævnt tidligere), og N noder får låsen med samme nøgle og værdi. Klienten skal sætte interface-adgangstimeouten, og interfacetimeout-timeouten skal være meget kortere end lock-timeouten, for eksempel er låsens automatisk frigivelsestid 10 sekunder, og interface-timeouten er sat til cirka 5-50 ms. Dette giver dig mulighed for at gå ud så hurtigt som muligt, når du får adgang til en redis-node, efter den er nede, og reducerer den normale brug af låsen. 3. Klienten beregner, hvor lang tid det tager at opnå låsen, ved at trække den opnåede tid fra trin 1 med den aktuelle tid, men kun når klienten har mere end 3 noder af låsen, og tiden til at opnå låsen er kortere end låsens timeout-tid, får klienten den distribuerede lås. 4. Klientens tid til at erhverve låsen er den satte låsetidsudeladning minus den tid, der bruges på at få låsen, beregnet i trin 3. 5. Hvis klienten ikke kan opnå låsen, vil klienten slette alle låsene én efter én. Ved hjælp af Redlock-algoritmen kan det garanteres, at den distribuerede låseservice stadig kan fungere, når op til 2 noder hænges, hvilket i høj grad forbedrer tilgængeligheden sammenlignet med den tidligere databaselås og cachelås.
Dog skrev en distribueret ekspert en artikel "How to do distributed locking", hvor han stillede spørgsmålstegn ved korrektheden af Redlock.
Eksperten nævnte, at der er to aspekter at overveje, når man overvejer distribuerede låse: ydeevne og korrekthed.
Hvis du bruger en højtydende distribueret lås, og korrektheden ikke er nødvendig, er det tilstrækkeligt at bruge en cachelås.
Hvis du bruger en meget pålidelig distribueret lås, skal du tage hensyn til strenge pålidelighedsproblemer. Redlock, derimod, opfylder ikke korrektheden. Hvorfor ikke? Eksperter nævner flere aspekter.
I dag bruger mange programmeringssprog virtuelle maskiner med GC-funktioner; i Full GC stopper programmet med at behandle GC, nogle gange tager Full GC lang tid, og selv programmet har et par minutters forsinkelse; artiklen nævner eksemplet HBase, HBase nogle gange GC i et par minutter, hvilket får leasingen til at gå ud på tid. For eksempel får klient 1 i figuren nedenfor en lås og er ved at behandle en delt ressource, og når den er ved at behandle en delt ressource, sker fuld GC, indtil låsen udløber. På denne måde får klient 2 låsen igen og begynder at arbejde på den delte ressource. Når klient 2 behandler, fuldfører klient 1 fuld GC og begynder at behandle delte ressourcer, så begge klienter behandler delte ressourcer.
Eksperter gav en løsning, som vist i figuren nedenfor, det ligner MVCC, bring et token til låsen, token er konceptet version, hver gang operationslås er færdig, tilføjes tokenet 1, bring tokenet ved behandling af delte ressourcer, kun den specificerede version af tokenet kan håndtere den delte ressource.
Eksperten sagde også, at algoritmen er afhængig af lokal tid, og at Redis bruger getTimeOfDay-metoden til at få tiden i stedet for det monotone ur, når nøgleudløb håndteres, hvilket også fører til tidsunøjagtigheder. For eksempel, i et scenarie, har to klient 1 og klient 2 5 redis-noder (A, B, C, D og E).
1. Klient 1 opnår med succes låsen fra A, B og C, og opnår låsenetværkets timeout fra D og E. 2. Uret for node C er unøjagtigt, hvilket forårsager låsetimeout. 3. klient 2 får med succes låsen fra C, D og E, og opnår låsenetværkets timeout fra A og B. 4. På denne måde får både klient 1 og klient 2 en lås. For at opsummere de to punkter, eksperter siger om Redlocks manglende tilgængelighed:
1. GC og andre scenarier kan opstå når som helst, hvilket får klienten til at opnå en lås, og behandlingstimeouten får en anden klient til at få låsen. Eksperter gav også en løsning til at bruge selv-inkrementerende tokens. 2. Algoritmen er afhængig af lokal tid, og uret vil være unøjagtigt, hvilket resulterer i, at to klienter får låse samtidig. Derfor konkluderer eksperterne, at Redlock kun kan fungere normalt inden for begrænset netværksforsinkelse, afgrænset programafbrydelse og begrænset clockfejlområde, men grænserne for disse tre scenarier kan ikke bekræftes, så eksperter anbefaler ikke at bruge Redlock. For scenarier med høje korrekthedskrav anbefaler eksperter Zookeeper, som senere vil blive diskuteret med Zookeeper som distribueret lås.
Svar fra forfatteren til Redis
Redis-forfatteren svarede ved at skrive en blog efter at have set ekspertens artikel. Forfatteren takkede høfligt eksperten og udtrykte derefter sin uenighed med ekspertens synspunkt.
REDIS-forfatterens diskussion om brugen af tokens til at løse lock-timeout-problemet kan opsummeres i følgende fem punkter:
Punkt 1, brugen af distribuerede låse er generelt sådan, at du ikke har nogen anden måde at kontrollere delte ressourcer på, eksperter bruger tokens til at sikre behandlingen af delte ressourcer, og så er der ikke behov for distribuerede låse. Punkt 2: For tokengenerering, for at sikre pålideligheden af tokens opnået af forskellige klienter, har tjenesten, der genererer tokens, stadig brug for distribuerede låse for at sikre tjenestens pålidelighed. Punkt 3, for den måde eksperter siger, at selvinkrementerende tokens på, mener redis-forfatteren, at det er fuldstændig unødvendigt, hver klient kan generere en unik uuid som token og sætte den delte ressource til en tilstand, som kun klienten med uuiden kan håndtere, så andre klienter ikke kan behandle den delte ressource, før den klient, der får låsen, frigiver låsen. Som vist i figuren ovenfor, hvis klienten på token 34 sender GC under skriveprocessen og får låsen til at timeoute, kan en anden klient få låsen til token 35 og begynde at skrive igen, hvilket resulterer i en låsekonflikt. Derfor kan rækkefølgen af tokens ikke kombineres med delte ressourcer. Punkt 5, redis-forfatteren mener, at distribuerede låse i de fleste scenarier bruges til at håndtere opdateringsproblemer i ikke-transaktionelle scenarier. Forfatteren bør mene, at der er nogle scenarier, hvor det er svært at kombinere tokens til at håndtere delte ressourcer, så man er nødt til at stole på låse for at låse ressourcer og behandle dem. Et andet urproblem, som eksperter taler om, giver også forfatterne til Redis en forklaring. Hvis tiden det tager at erhverve låsen er for lang og overstiger den standard timeout-tid for låsen, kan klienten ikke få låsen på nuværende tidspunkt, og der vil ikke foreslås eksempler fra eksperter.
Personlige følelser
Det første problem, jeg opsummerer, er, at efter en klient har opnået en distribueret lås, kan låsen blive frigivet efter en timeout under klientens behandling. Tidligere, når man talte om timeouten sat af databaselåsen på 2 minutter, hvis en opgave optager en ordrelås i mere end 2 minutter, kan det andet handelscenter opnå denne ordrelås, så de to handelscentre kan behandle den samme ordre på samme tid. Under normale omstændigheder behandles opgaven på sekunder, men nogle gange er timeouten, der sættes ved at joine en RPC-anmodning, for lang, og der er flere sådanne timeout-anmodninger i en opgave, så det er sandsynligt, at den automatiske oplåsningstid overskrides. Hvis vi skriver i Java, kan der være Full GC i midten, så efter låsen er låst op efter lock-timeout, kan klienten ikke opfatte det, hvilket er en meget alvorlig sag. Jeg tror ikke, det er et problem med selve låsen, så længe en distribueret lås nævnt ovenfor har karakteristika for timeout-frigivelse, vil sådan et problem opstå. Hvis du bruger lock-timeout-funktionen, skal klienten sætte lock-timeout og handle derefter i stedet for at fortsætte med at behandle den delte ressource. Redlocks algoritme returnerer den låsetid, som klienten kan besætte, efter klienten har erhvervet låsen, og klienten skal behandle denne tid for at stoppe opgaven efter denne tid.
Det andet problem er, at distribuerede eksperter ikke forstår Redlock. En vigtig funktion i Redlock er, at tiden til at erhverve låsen er den samlede tid, låsen som standard går til timeout minus den tid, det tager at få låsen, så den tid, klienten behandler den, er relativ, uanset lokal tid.
Set fra dette synspunkt kan korrektheden af Redlock være fuldt ud garanteret. Omhyggelig analyse af Redlock, sammenlignet med redis af en node, er hovedfunktionen ved Redlock højere pålidelighed, hvilket er en vigtig egenskab i nogle scenarier. Men jeg synes, Redlock har brugt for mange penge på at opnå pålidelighed.
- For det første skal 5 noder implementeres for at gøre Redlock mere pålidelig.
- Derefter skal du anmode om 5 noder for at få låsen, og gennem Future-metoden kan du først anmode til 5 noder samtidig og derefter samle svarresultatet, hvilket kan forkorte svartiden, men det tager stadig længere tid end en enkelt-node redis-lås.
- Derefter, fordi mere end 3 af de 5 noder skal opnås, kan der opstå en låsekonflikt, det vil sige, at alle har opnået 1-2 låse, og som følge heraf kan ingen få låsen, dette problem, låner forfatteren af Redis essensen af flådealgoritmen, gennem kollisionen på tilfældige tidspunkter kan konflikttiden reduceres betydeligt, men dette problem kan ikke undgås særlig godt, især når låsen erhverves for første gang, så tidsomkostningen ved at erhverve låsen stiger.
- Hvis 2 af de 5 noder er nede, vil låsens tilgængelighed blive kraftigt reduceret; først og fremmest skal du vente på, at resultaterne af disse to nedlagte noder går ud på timeout, før du vender tilbage, og der er kun 3 noder, og klienten skal få fat i låsene på alle 3 noder for at have låsen, hvilket også er sværere.
- Hvis der er en netværkspartition, kan der opstå en situation, hvor klienten aldrig kan få låsen.
Efter at have analyseret så mange grunde mener jeg, at det mest kritiske punkt i Redlocks problem er, at Redlock kræver, at klienterne sikrer konsistens i skrivningerne, og at backend-noder er fuldstændig uafhængige, og alle klienter skal operere disse 5 noder. Hvis der er en leder blandt 5 noder, kan klienten synkronisere lederens data, så længe klienten får låsen fra lederen, så der ikke opstår problemer som partitionering, timeouts og konflikter. Derfor mener jeg, at brugen af en distribueret koordineringstjeneste med stærk konsistens bedre kan løse problemet for at sikre korrektheden af distribuerede låse.
Spørgsmålet opstår igen, hvor lang tid skal jeg sætte udløbstiden? Hvordan man sætter ugyldiggørelsestiden er for kort, og låsen frigives automatisk, før metoden udføres, så der vil opstå samtidighedsproblemer. Hvis det tager for lang tid, kan andre tråde, der får låsen, måtte vente længe.
Dette problem eksisterer også med brugen af databaser til at implementere distribuerede låse.
Den nuværende mainstream-tilgang til dette problem er at sætte en kort timeout-tid for hver opnået lås og starte en tråd for at opdatere låsetimeout-tiden hver gang den er ved at nå timeouten. Afslut denne tråd samtidig med, at du frigør låsen. For eksempel bruger redisson, den officielle distribuerede låsekomponent i redis, denne løsning.
Fordele ved at bruge caching til at implementere distribuerede låse God præstation.
Ulemper ved at bruge caching til at implementere distribuerede låse Implementeringen er for ansvarlig, der er for mange faktorer at tage højde for.
Distribuerede låse baseret på Zookeeper-implementering
Distribuerede låse baseret på midlertidigt ordnede noder i Zookeeper.
Den generelle idé er, at når hver klient låser en metode, genereres en unik øjeblikkelig ordnet node i mappen for den specificerede node, der svarer til metoden på zookeeper. Måden at afgøre, om man skal få en lås, er enkel; du skal kun bestemme den med det mindste serienummer i den ordnede node. Når låsen frigives, slet blot den øjeblikkelige node. Samtidig kan det undgå problemet med deadlocks forårsaget af servicenedetid, som ikke kan frigives.
Lad os se, om Zookeeper kan løse de tidligere nævnte problemer.
- Låsen vil ikke åbne? Brug af Zookeeper kan effektivt løse problemet med, at låse ikke bliver frigivet, fordi når man opretter en lås, opretter klienten en midlertidig node i ZK, og når klienten får låsen og pludselig hænger den (sessionsforbindelsen brydes), vil den midlertidige node automatisk blive slettet. Andre kunder kan få låsen igen.
- Låse uden blokering? Når noden ændres, vil Zookeeper underrette klienten, og klienten kan kontrollere, om den node, den har oprettet, er det mindste ordinaltal blandt alle noderne.
- Kan du ikke komme ind igen? Når klienten opretter en node, skriver den direkte værtsinformationen og trådinformationen fra den aktuelle klient til noden, og næste gang du vil have låsen, kan du sammenligne den med dataene i den nuværende mindste node. Hvis informationen er den samme som din egen, kan du direkte hente låsen, og hvis den er anderledes, oprette en midlertidig sekventiel node til at deltage i køen.
Spørgsmålet opstår igen, vi ved, at Zookeeper skal implementeres i klynger, vil der opstå problemer med datasynkronisering som i Redis-klynger?
Zookeeper er en distribueret komponent, der garanterer svag konsistens, dvs. eventuel konsistens.
Zookeeper anvender en datasynkroniseringsprotokol kaldet Quorum Based Protocol. Hvis der er N Zookeeper-servere i Zookeeper-klyngen (N er normalt ulige, 3 kan opfylde datapålidelighed og have høj læse- og skriveydelse, og 5 har den bedste balance mellem datapålidelighed og læse- og skriveydelse), synkroniseres en skriveoperation af brugeren først til N/2 + 1 servere og returneres derefter til brugeren, hvilket får brugeren til at skrive succesfuldt. Datasynkroniseringsprotokollen baseret på Quorum Based Protocol bestemmer den konsistens af styrke, som Zookeeper kan understøtte.
I et distribueret miljø er datalagring, der opfylder stærk konsistens, stort set ikke-eksisterende, og det kræver, at alle noder opdateres synkront, når dataene fra én node opdateres. Denne synkroniseringsstrategi optræder i master-slave synkron replikationsdatabase. Denne synkroniseringsstrategi har dog for stor indflydelse på skriveydelsen og ses sjældent i praksis. Fordi Zookeeper skriver N/2+1 noder synkront, og N/2 noder ikke opdateres synkront, er Zookeeper ikke stærkt konsistent.
Brugerens dataopdateringsoperation garanterer ikke, at efterfølgende læsninger vil læse den opdaterede værdi, men vil til sidst vise konsistens. At ofre konsistens betyder ikke fuldstændig at ignorere dataenes konsistens, ellers er dataene kaotiske, så uanset hvor høj systemets tilgængelighed er, uanset hvor god fordelingen er, er det uden værdi. At ofre konsistens er netop det, at stærk konsistens i relationelle databaser ikke længere er nødvendig, men så længe systemet kan opnå endelig konsistens.
Et enkelt spørgsmål? Brug af Zookeeper kan effektivt løse et enkelt punktproblem, ZK implementeres i klynger, så længe mere end halvdelen af maskinerne i klyngen overlever, kan tjenesten leveres til omverdenen.
Retfærdighedsproblemer? Brug af Zookeeper kan løse problemet med fair locks, de midlertidige noder, som klienten opretter i ZK, er ordnede, og hver gang låsen frigives, kan ZK underrette den mindste node om at få låsen, hvilket sikrer retfærdighed.
Spørgsmålet opstår igen, vi ved, at Zookeeper skal implementeres i klynger, vil der opstå problemer med datasynkronisering som i Redis-klynger?
Zookeeper er en distribueret komponent, der garanterer svag konsistens, dvs. eventuel konsistens.
Zookeeper anvender en datasynkroniseringsprotokol kaldet Quorum Based Protocol. Hvis der er N Zookeeper-servere i Zookeeper-klyngen (N er normalt ulige, 3 kan opfylde datapålidelighed og have høj læse- og skriveydelse, og 5 har den bedste balance mellem datapålidelighed og læse- og skriveydelse), synkroniseres en skriveoperation af brugeren først til N/2 + 1 servere og returneres derefter til brugeren, hvilket får brugeren til at skrive succesfuldt. Datasynkroniseringsprotokollen baseret på Quorum Based Protocol bestemmer den konsistens af styrke, som Zookeeper kan understøtte.
I et distribueret miljø er datalagring, der opfylder stærk konsistens, stort set ikke-eksisterende, og det kræver, at alle noder opdateres synkront, når dataene fra én node opdateres. Denne synkroniseringsstrategi optræder i master-slave synkron replikationsdatabase. Denne synkroniseringsstrategi har dog for stor indflydelse på skriveydelsen og ses sjældent i praksis. Fordi Zookeeper skriver N/2+1 noder synkront, og N/2 noder ikke opdateres synkront, er Zookeeper ikke stærkt konsistent.
Brugerens dataopdateringsoperation garanterer ikke, at efterfølgende læsninger vil læse den opdaterede værdi, men vil til sidst vise konsistens. At ofre konsistens betyder ikke fuldstændig at ignorere dataenes konsistens, ellers er dataene kaotiske, så uanset hvor høj systemets tilgængelighed er, uanset hvor god fordelingen er, er det uden værdi. At ofre konsistens er netop det, at stærk konsistens i relationelle databaser ikke længere er nødvendig, men så længe systemet kan opnå endelig konsistens.
Om Zookeeper opfylder kausal konsistens afhænger af, hvordan klienten er programmeret.
Praksisser, der ikke opfylder kausal konsistens
- Proces A skriver et stykke data til Zookeepers /z og returnerer det succesfuldt
- Proces A informerer proces B om, at A har ændret dataene i /z
- B læser dataene fra Zookeepers /z
- Da serveren for Zookeeperen, der er forbundet til B, måske ikke er opdateret med A's skrevne data, vil B heller ikke kunne læse A's skrevne data
Praksisser, der opfylder kausal konsistens
- Proces B lytter efter dataændringer i /z på Zookeeper
- Proces A skriver et datastykke til Zookeepers /z, og før det returnerer succesfuldt, skal Zookeeper kalde lytteren, der er registreret på /z, og lederen vil underrette B om dataændringen
- Efter at hændelsesresponsmetoden for proces B er besvaret, tager den de ændrede data, så B vil helt sikkert kunne få den ændrede værdi
- Kausal konsistens refererer her til den kausale konsistens mellem Leder og B, det vil sige, lederen underretter dataene om en ændring
Den anden begivenhedslyttemekanisme er også den metode, der bør bruges til korrekt at programmere Zookeeper, så Zookeeper bør opfylde den kausale konsistens
Derfor, når vi implementerer distribuerede låse baseret på Zookeeper, bør vi bruge praksissen med at opfylde kausal konsistens, det vil sige, at trådene, der venter på låsen, lytter til ændringerne i Zookeepers lås, og når låsen frigives, vil Zookeeper underrette den ventende tråd, der opfylder betingelserne for fair lock.
Du kan bruge Zookeepers tredjepartsbiblioteksklient direkte, som indkapsler en reentrant lock-tjeneste.
Distribuerede låse implementeret med ZK synes at passe præcis til det, vi forventede af en distribueret lås i begyndelsen af denne artikel. Det er den dog ikke, og den distribuerede lås, som Zookeeper implementerer, har faktisk en ulempe, nemlig at ydeevnen måske ikke er så høj som caching-tjenesten. For hver gang i processen med at skabe og frigive en lås, skal øjeblikkelige noder dynamisk oprettes og ødelægges for at realisere låsefunktionen. Oprettelse og sletning af noder i ZK kan kun udføres via lederserveren, og derefter deles dataene med alle følgermaskiner.
Fordele ved at bruge Zookeeper til at implementere distribuerede låse Effektivt løse enkeltpunktsproblemer, ikke-genindtrædelsesproblemer, ikke-blokeringsproblemer og låsefejl i at frigive. Det er relativt nemt at implementere.
Ulemper ved at bruge Zookeeper til at implementere distribuerede låse Ydelsen er ikke så god som ved at bruge cache til at implementere distribuerede låse. En forståelse af principperne i ZK er nødvendig.
Sammenligning af de tre muligheder
Set fra et letforståeligt perspektiv (fra lavt til højt) Database > Cache > Zookeeper
Set fra implementeringskompleksitetens perspektiv (fra lav til høj) Zookeeper > cache > databaser
Fra et præstationsperspektiv (fra højt til lavt) Caching > Zookeeper >= database
Fra et pålidelighedsperspektiv (fra højt til lavt) Zookeeper > cache > databaser
|