Spørsmål: Én tjenesteserver, én database, operasjon: spør brukerens nåværende saldo, trekk 3 % av den nåværende saldoen som håndteringsgebyr
Synkronisert lås DB-lås
Spørsmål: To tjenesteservere, én database, operasjon: spør brukerens nåværende saldo, trekk fra 3 % av den nåværende saldoen som håndteringsgebyr Distribuerte låser
Hva slags distribuert lås trenger vi? Den kan sikre at i en distribuert applikasjonsklynge kan samme metode bare kjøres av én tråd på én maskin samtidig.
Hvis denne låsen er en reentrant lock (unngå deadlocks)
Denne låsen er best å være en blokkeringslås (vurder om du vil ha denne i henhold til din bedrifts behov)
Denne låsen er best for å være en rettferdig lås (vurder om du vil ha denne eller ikke, avhengig av forretningsbehov)
Det finnes svært tilgjengelige anskaffelses- og låsefunksjoner
Ytelsen til anskaffelses- og frigjøringslåsene er bedre
1. Distribuerte låser basert på databaser
Distribuerte låser basert på tabellbaserte implementasjoner
Når vi vil låse en metode, kjør følgende SQL: sett inn i methodLock(method_name,desc) verdier ('method_name','desc')
Fordi vi har laget en unikhetsbegrensning på method_name, hvis flere forespørsler sendes til databasen samtidig, vil databasen sikre at bare én operasjon kan lykkes, da kan vi anta at tråden som fikk tak i metodelåsen og kan kjøre innholdet i metodens kropp.
Når metoden kjøres, hvis du vil frigjøre låsen, må du utføre følgende SQL: slette fra methodLock hvor method_name ='method_name'
Denne enkle implementeringen ovenfor har følgende problemer:
- Denne låsen avhenger av tilgjengeligheten til databasen, som er et enkelt punkt og vil føre til at forretningssystemet blir utilgjengelig når databasen blir lagt opp.
- Denne låsen har ingen utløpstid, og når opplåsingsoperasjonen mislykkes, vil låseposten forbli i databasen og andre tråder vil ikke lenger kunne hente låsen.
- Denne låsen kan bare være ikke-blokkerende, fordi innsettingsoperasjonen av data vil rapportere en feil direkte når innsettingen mislykkes. Tråder som ikke får låser, vil ikke komme inn i køen, og må utløse låseanskaffelsesoperasjonen på nytt for å få låsen på nytt.
- Låsen er ikke-reenterant, og den samme gjengen kan ikke få låsen igjen før den slippes. Fordi dataene i dataene allerede eksisterer.
- Denne låsen er en urettferdig lås, og alle trådene som venter på låsen konkurrerer om låsen ved flaks.
Selvfølgelig kan vi også løse de ovennevnte problemene på andre måter.
- Er databasen et enkelt punkt? Bygg to databaser, og dataene vil være synkronisert i begge retninger. Når du har lagt på, bytt raskt til backup-biblioteket.
- Ingen utløpstid? Bare gjør en planlagt oppgave for å rydde opp i timeout-dataene i databasen med jevne mellomrom.
- Ikke-blokkerende? Gjør en while-løkke til innsettingen lykkes og så returnerer suksess.
- Ikke-reenterant? Legg til et felt i databasetabellen for å registrere vertsinformasjonen og trådinformasjonen til maskinen som for øyeblikket får låsen, og neste gang du får låsen, spør databasen først, hvis vertsinformasjonen og trådinformasjonen til den nåværende maskinen finnes i databasen, kan du tilordne låsen direkte til ham.
- Urettferdig? Lag en annen mellomtabell for å registrere alle trådene som venter på låsen, og sorter dem etter opprettelsestid, og kun den først opprettede har lov til å få låsen
Distribuerte låser basert på eksklusive låser
I tillegg til å legge til og slette poster i datatabellen, kan distribuerte låser også implementeres ved hjelp av låsene som følger med dataene.
Vi bruker også databasetabellen vi nettopp har laget. Distribuerte låser kan implementeres gjennom eksklusive låser på databaser. Den MySQL-baserte InnoDB-motoren kan bruke følgende metoder for å implementere lock-up-operasjoner:
Hvis du legger til for oppdatering etter spørringssetningen, vil databasen legge til en eksklusiv lås i databasetabellen under spørringsprosessen. Når en eksklusiv lås legges til en post, kan ikke andre tråder lenger legge til en eksklusiv lås på posten på den linjen.
Vi kan tenke oss at tråden som får den eksklusive låsen kan få tak i den distribuerte låsen, og når låsen er oppnådd, kan forretningslogikken til metoden kjøres, og deretter låses opp gjennom følgende metoder:
public void unlock(){ connection.commit(); }
via connection.commit(); operasjon for å åpne låsen.
Denne metoden kan effektivt løse problemene nevnt ovenfor om manglende evne til å frigjøre låsen og blokkere den.
Blokkere låser? For update-setningen returneres umiddelbart etter vellykket kjøring og forblir blokkert til den lykkes.
Tjenesten nede etter lås, kan ikke frigjøres? På denne måten frigjør databasen låsen av seg selv etter at tjenesten går ned.
Likevel løser det fortsatt ikke direkte problemet med database-enkeltpunkt, reentrancy og fair locking.
For å oppsummere måten å bruke databasen på for å implementere distribuerte låser, som begge er avhengige av en tabell i databasen, er den ene å avgjøre om det finnes en lås ved å eksistere poster i tabellen, og den andre er å implementere distribuerte låser gjennom den eksklusive låsen i databasen.
Fordeler med distribuert låsing i databaser
Direkte med hjelp av databasen er det lett å forstå.
Ulemper ved å implementere distribuerte låser i databaser
Det vil oppstå ulike problemer, og hele løsningen vil bli mer og mer kompleks i prosessen med å løse problemet.
Driften av databasen krever en viss overhead, og ytelsesproblemer må vurderes.
2. Distribuerte låser basert på cache
Sammenlignet med den databasebaserte distribuerte låseløsningen, vil den cache-baserte implementeringen prestere bedre når det gjelder ytelse.
Det finnes mange modne caching-produkter for øyeblikket, inkludert Redis, memcached, osv. Her tar vi Redis som et eksempel for å analysere metoden for å bruke cache for å implementere distribuerte låser.
Det finnes mange relaterte artikler på Internett om implementering av distribuerte låser basert på Redis, og hovedimplementeringsmetoden er å bruke Jedis.setNX-metoden.
Det finnes også flere problemer med denne implementeringen:
1. Enkeltpunktsproblem.
2. Denne låsen har ingen utløpstid; når opplåsingsoperasjonen mislykkes, vil låseposten alltid være i reditt, og andre tråder kan ikke lenger få tak i låsen.
3. Denne låsen kan bare være ikke-blokkerende, og den vil returnere direkte uavhengig av suksess eller fiasko.
4. Denne låsen er ikke-reentrant, og etter at en tråd har fått tak i låsen, kan den ikke få låsen igjen før den slippes, fordi nøkkelen som brukes allerede eksisterer i redis. setNX-operasjoner kan ikke lenger utføres.
5. Denne låsen er urettferdig, alle ventende tråder starter setNX-operasjoner samtidig, og heldige tråder kan få låsen.
Selvfølgelig finnes det også måter å løse det på.
- I dag støtter vanlige caching-tjenester klyngedistribusjon for å løse enkeltpunktsproblemer gjennom klynging.
- Ingen utløpstid? setExpire-metoden i redis støtter innkommende utløpstid, og dataene slettes automatisk etter at tiden er nådd.
- Ikke-blokkerende? mens de ble henrettet gjentatte ganger.
- Er det ikke mulig å komme inn igjen? Etter at en tråd har fått tak i låsen, lagre informasjonen om nåværende verter og trådinformasjon, og sjekk om du er eier av den nåværende låsen før du henter den neste gang.
- Urettferdig? Legg alle ventende tråder i en kø før en tråd får en lås, og deretter får låsen på en først-inn, først-ut-basis.
Synkroniseringspolicyen til redis-klyngen tar tid, og det er mulig at tråd A får en lås etter å ha satt NX vellykket, men denne verdien er ikke oppdatert til serveren der tråd B kjører setNX, noe som vil forårsake samtidighetsproblemer.
Salvatore Sanfilippo, forfatteren av redis, foreslo Redlock-algoritmen, som implementerer distribuert låsehåndtering (DLM) som er sikrere og mer pålitelig enn en enkelt node.
Redlock-algoritmen antar at det finnes N redis-noder som er uavhengige av hverandre, vanligvis satt til N=5, og at disse N nodene kjører på forskjellige maskiner for å opprettholde fysisk uavhengighet.
Stegene i algoritmen er som følger:
1. Klienten får gjeldende tid i millisekunder. 2. Klienten prøver å få låsen av N noder, (hver node får låsen på samme måte som cache-låsen nevnt tidligere), og N noder får låsen med samme nøkkel og verdi. Klienten må sette interface-tilgangstimeout, og interface-timeout-tiden må være mye kortere enn låsetimeouten, for eksempel er låsens automatiske frigivelsestid 10 sekunder, og grensesnitttimeouten settes til omtrent 5-50 ms. Dette gjør at du kan gå ut så raskt som mulig når du får tilgang til en redis-node etter at den er nede, og reduserer normal bruk av låsen. 3. Klienten beregner hvor lang tid det tar å få låsen, ved å trekke fra tiden oppnådd i steg 1 med nåværende tid, men når klienten har mer enn 3 noder av låsen, og tiden det tar å få låsen er kortere enn timeout-tiden for låsen, får klienten den distribuerte låsen. 4. Tiden klienten tar for å få tak i låsen er den satt låsetiden minus tiden brukt på å få låsen beregnet i steg 3. 5. Hvis klienten ikke klarer å få tak i låsen, vil klienten slette alle låsene etter tur. Ved å bruke Redlock-algoritmen kan det garanteres at den distribuerte låsetjenesten fortsatt kan fungere når man henger opptil 2 noder, noe som i stor grad forbedrer tilgjengeligheten sammenlignet med den forrige databaselåsen og cache-låsen.
En distribuert ekspert skrev imidlertid en artikkel "How to do distributed locking" som stilte spørsmål ved riktigheten av Redlock.
Eksperten nevnte at det er to aspekter å vurdere når man vurderer distribuerte låser: ytelse og korrekthet.
Hvis du bruker en høyytelses distribuert lås og korrektheten ikke er nødvendig, er det tilstrekkelig å bruke en cache-lås.
Hvis du bruker en svært pålitelig distribuert lås, må du ta hensyn til strenge pålitelighetsproblemer. Redlock, derimot, oppfyller ikke korrektheten. Hvorfor ikke? Ekspertene lister opp flere aspekter.
I dag bruker mange programmeringsspråk virtuelle maskiner med GC-funksjoner, i Full GC stopper programmet å behandle GC, noen ganger tar Full GC lang tid, og selv programmet har noen minutters forsinkelse, artikkelen lister eksempelet HBase, HBase noen ganger GC i noen minutter, noe som fører til at leieavtalen går ut på tid. For eksempel, i figuren nedenfor, får klient 1 en lås og er i ferd med å behandle en delt ressurs, og når den skal behandle en delt ressurs, skjer Full GC inntil låsen utløper. På denne måten får klient 2 låsen igjen og begynner å jobbe med den delte ressursen. Når klient 2 behandler, fullfører klient 1 full GC og begynner å behandle delte ressurser, slik at begge klientene behandler delte ressurser.
Ekspertene ga en løsning, som vist i figuren nedenfor, det ser ut som MVCC, bring en token til låsen, token er konseptet versjon, hver gang operasjonslåsen er fullført, legges tokenet til 1, bringer tokenet når delte ressurser behandles, kun den angitte versjonen av tokenet kan håndtere den delte ressursen.
Eksperten sa også at algoritmen er avhengig av lokal tid, og at Redis bruker getTimeOfDay-metoden for å få tiden i stedet for den monotone klokken når nøkkelutløp håndteres, noe som også fører til tidsfeil. For eksempel, i et scenario har to klient 1 og klient 2 5 redis-noder (A, B, C, D og E).
1. Klient 1 får låsen fra A, B og C, og får låsenettverkets timeout fra D og E. 2. Klokken til node C er unøyaktig, noe som fører til låsetidsavbruddet. 3. Klient 2 får tak i låsen fra C, D og E, og får låsenettverkets timeout fra A og B. 4. På denne måten får både klient 1 og klient 2 en lås. For å oppsummere de to punktene ekspertene sier om Redlocks utilgjengelighet:
1. GC og andre scenarier kan oppstå når som helst, noe som fører til at klienten får en lås, og prosesseringstidsavbruddet gjør at en annen klient får låsen. Eksperter ga også en løsning for bruk av selvinkrementerende tokens. 2. Algoritmen er avhengig av lokal tid, og klokken vil være unøyaktig, noe som resulterer i at to klienter får låser samtidig. Derfor konkluderer ekspertene med at Redlock kun kan fungere normalt i begrenset nettverksforsinkelse, avbrutt programavbrudd og begrenset klokkefeilområde, men grensene for disse tre scenarioene kan ikke bekreftes, så eksperter anbefaler ikke bruk av Redlock. For scenarier med høye korrekthetskrav anbefaler eksperter Zookeeper, som senere vil bli diskutert med bruk av Zookeeper som distribuert lås.
Svar fra forfatteren av Redis
Redis-forfatteren svarte med å skrive en blogg etter å ha sett ekspertens artikkel. Forfatteren takket eksperten høflig, og uttrykte deretter sin uenighet med ekspertens syn.
REDIS-forfatterens diskusjon om bruk av tokens for å løse lock-timeout-problemet kan oppsummeres i følgende fem punkter:
Punkt 1, bruken av distribuerte låser er generelt at du ikke har noen annen måte å kontrollere delte ressurser på, eksperter bruker tokens for å sikre behandlingen av delte ressurser, da er det ikke behov for distribuerte låser. Punkt 2: For tokengenerering, for å sikre påliteligheten til tokens oppnådd av ulike klienter, trenger tjenesten som genererer tokens fortsatt distribuerte låser for å sikre tjenestens pålitelighet. Punkt 3, for måten eksperter sier at selvinkrementerende tokens på, mener redis-forfatteren at det er helt unødvendig, hver klient kan generere en unik uuid som token, og sette den delte ressursen til en tilstand som bare klienten med uuid kan håndtere, slik at andre klienter ikke kan behandle den delte ressursen før klienten som får tak i låsen frigjør den. Som vist i figuren over, hvis klienten til token 34 sender GC under skriveprosessen og får låsen til å gå ut på tid, kan en annen klient få låsen til token 35 og begynne å skrive på nytt, noe som resulterer i en låskonflikt. Derfor kan ikke rekkefølgen på tokens kombineres med delte ressurser. Punkt 5, redis-forfatteren mener at i de fleste scenarioer brukes distribuerte låser for å håndtere oppdateringsproblemer i ikke-transaksjonelle scenarioer. Forfatteren bør mene at det finnes noen situasjoner hvor det er vanskelig å kombinere tokens for å håndtere delte ressurser, så du må stole på låser for å låse ressurser og behandle dem. Et annet klokkeproblem som eksperter snakker om, Redis forfattere gir også en forklaring. Hvis tiden det tar å skaffe låsen er for lang og overstiger standard timeout-tiden for låsen, kan klienten ikke få tak i låsen nå, og det vil ikke foreligge eksempler fra ekspertene.
Personlige følelser
Det første problemet jeg oppsummerer er at etter at en klient har fått en distribuert lås, kan låsen bli frigjort etter en timeout under klientens behandling. Tidligere, når man snakket om timeout satt av databaselåsen på 2 minutter, hvis en oppgave opptar en ordrelås i mer enn 2 minutter, kan det andre handelssenteret få tak i denne ordrelåsen, slik at de to handelssentrene kan behandle samme ordre samtidig. Under normale omstendigheter behandles oppgaven på sekunder, men noen ganger er timeouten satt ved å bli med i en RPC-forespørsel for lang, og det finnes flere slike timeout-forespørsler i en oppgave, da er det sannsynlig at den automatiske opplåsingstiden vil bli overskredet. Hvis vi skriver i Java, kan det være Full GC i midten, så etter at låsen er låst opp etter låsens timeout, kan ikke klienten oppfatte den, noe som er veldig alvorlig. Jeg tror ikke dette er et problem med selve låsen, så lenge en distribuert lås nevnt ovenfor har egenskapene til timeout-frigjøring, vil et slikt problem oppstå. Hvis du bruker lås-timeout-funksjonen, må klienten sette lås-timeout og handle deretter, i stedet for å fortsette å behandle den delte ressursen. Redlocks algoritme returnerer låsetiden klienten kan bruke etter at klienten har fått låsen, og klienten må behandle denne tiden for å stoppe oppgaven etter denne tiden.
Det andre problemet er at distribuerte eksperter ikke forstår Redlock. En nøkkelfunksjon ved Redlock er at tiden det tar å skaffe låsen er den totale tiden låsen som standard går til timeout minus tiden det tar å få tak i låsen, slik at tiden det tar for klienten å behandle er relativ, uavhengig av lokal tid.
Fra dette perspektivet kan riktigheten til Redlock være godt garantert. Nøye analyse av Redlock, sammenlignet med redis av en node, er hovedfunksjonen Redlock gir høyere pålitelighet, noe som er viktig i noen scenarioer. Men jeg mener Redlock har brukt for mye penger for å oppnå pålitelighet.
- Først må 5 noder implementeres for å gjøre Redlock mer pålitelig.
- Deretter må du be om 5 noder for å få låsen, og gjennom Future-metoden kan du først be om 5 noder samtidig, og deretter samle svarresultatet, noe som kan forkorte responstiden, men det tar fortsatt lengre tid enn en enkeltnode redis-lås.
- Fordi mer enn 3 av de 5 nodene må oppnås, kan det oppstå en låskonflikt, det vil si at alle har oppnådd 1-2 låser, og som et resultat kan ingen få låsen, dette problemet låner Redis-forfatteren essensen av flåtealgoritmen, gjennom kollisjon på tilfeldig tidspunkt kan konflikttiden reduseres betydelig, men dette problemet kan ikke unngås særlig godt, spesielt når låsen oppnås for første gang, så tidskostnaden for å skaffe låsen øker.
- Hvis 2 av de 5 nodene er nede, vil tilgjengeligheten til låsen bli kraftig redusert, først må du vente på at resultatene fra disse to nedlagte nodene går ut før du kan returnere, og det er bare 3 noder, og klienten må få tak i låsene til alle 3 nodene for å ha låsen, noe som også er vanskeligere.
- Hvis det finnes en nettverkspartisjon, kan det oppstå en situasjon der klienten aldri vil klare å få tak i låsen.
Etter å ha analysert så mange grunner, tror jeg det mest kritiske poenget med Redlocks problem er at Redlock krever at klientene sikrer konsistens i skrivingene, og de 5 backend-nodene er helt uavhengige, og alle klientene må operere disse 5 nodene. Hvis det finnes en leder blant 5 noder, kan klienten synkronisere lederens data så lenge klienten får låsen fra lederen, slik at det ikke oppstår problemer som partisjonering, timeouts og konflikter. Derfor, for å sikre korrektheten av distribuerte låser, tror jeg bruk av en distribuert koordineringstjeneste med sterk konsistens kan løse problemet bedre.
Spørsmålet dukker opp igjen, hvor lang bør jeg sette utløpstiden? Hvordan man setter ugyldiggjøringstiden er for kort, og låsen frigjøres automatisk før metoden kjøres, da vil det oppstå samtidighetsproblemer. Hvis det tar for lang tid, kan andre tråder som får låsen måtte vente lenge.
Dette problemet finnes også med bruk av databaser for å implementere distribuerte låser.
Den nåværende vanlige tilnærmingen til dette problemet er å sette en kort timeout-tid for hver lås du oppnår, og starte en tråd for å oppdatere lås-timeout-tiden hver gang den er i ferd med å nå timeouten. Avslutt denne tråden samtidig som du slipper låsen. For eksempel bruker redisson, den offisielle distribuerte låsekomponenten i redis, denne løsningen.
Fordeler med å bruke caching for å implementere distribuerte låser God prestasjon.
Ulemper ved å bruke caching for å implementere distribuerte låser Implementeringen er for ansvarlig, det er for mange faktorer å ta hensyn til.
Distribuerte låser basert på Zookeeper-implementering
Distribuerte låser basert på Zookeeper midlertidig ordnede noder.
Hovedideen er at når hver klient låser en metode, genereres en unik øyeblikkelig ordnet node i katalogen til den spesifiserte noden som tilsvarer metoden på Zookeeper. Måten å avgjøre om du skal få en lås på er enkel, du trenger bare å finne den med det laveste serienummeret i den ordnede noden. Når låsen åpnes, sletter du bare den øyeblikkelige noden. Samtidig kan det unngå problemet med fastlåste situasjoner forårsaket av tjenestenedetid som ikke kan løses.
La oss se om Zookeeper kan løse problemene nevnt tidligere.
- Låsen vil ikke åpne? Bruk av Zookeeper kan effektivt løse problemet med at låser ikke blir frigitt, fordi når man oppretter en lås, vil klienten opprette en midlertidig node i ZK, og når klienten får tak i låsen og plutselig henger den (sesjonsforbindelsen brytes), vil den midlertidige noden automatisk bli slettet. Andre kunder kan få låsen igjen.
- Ikke-blokkerende låser? Når noden endres, vil Zookeeper varsle klienten, og klienten kan sjekke om noden den opprettet er det minste ordinalnummeret blant alle nodene.
- Kan du ikke komme inn igjen? Når klienten oppretter en node, skriver den direkte vertsinformasjonen og trådinformasjonen til den nåværende klienten til noden, og neste gang du vil ha låsen, kan du sammenligne den med dataene i den nåværende minste noden. Hvis informasjonen er den samme som din egen, kan du direkte hente låsen, og hvis den er annerledes, opprette en midlertidig sekvensiell node som deltar i køen.
Spørsmålet oppstår igjen, vi vet at Zookeeper må distribueres i klynger, vil det oppstå problemer med datasynkronisering som i Redis-klynger?
Zookeeper er en distribuert komponent som garanterer svak konsistens, altså til slutt konsistens.
Zookeeper benytter en datasynkroniseringsprotokoll kalt Quorum Based Protocol. Hvis det finnes N Zookeeper-servere i Zookeeper-klyngen (N er vanligvis oddetall, 3 kan oppfylle datapålitelighet og har høy lese- og skriveytelse, og 5 har best balanse mellom datapålitelighet og lese- og skriveytelse), synkroniseres en skriveoperasjon av brukeren først til N/2 + 1-servere, og returneres deretter til brukeren, slik at brukeren må skrive vellykket. Datasynkroniseringsprotokollen basert på Quorum Based Protocol bestemmer hvor konsekvent styrken Zookeeper kan støtte.
I et distribuert miljø er datalagring som oppfyller sterk konsistens i praksis ikke-eksisterende, og det krever at alle noder oppdateres synkront når dataene til én node oppdateres. Denne synkroniseringsstrategien finnes i master-slave synkron replikasjonsdatabasen. Denne synkroniseringsstrategien har imidlertid for stor innvirkning på skriveytelsen og sees sjelden i praksis. Fordi Zookeeper skriver N/2+1-noder synkront, og N/2 noder ikke oppdateres synkront, er ikke Zookeeper sterkt konsistent.
Brukerens dataoppdateringsoperasjon garanterer ikke at påfølgende lesninger vil lese den oppdaterte verdien, men vil til slutt vise konsistens. Å ofre konsistens betyr ikke å fullstendig ignorere konsistensen i dataene, ellers blir dataene kaotiske, så uansett hvor høy systemtilgjengeligheten er, uansett hvor god fordelingen er, er det uten verdi. Å ofre konsistens er bare at sterk konsistens i relasjonsdatabaser ikke lenger er nødvendig, men så lenge systemet kan oppnå endelig konsistens.
Et spørsmål med ett poeng? Bruk av Zookeeper kan effektivt løse et enkeltpunktsproblem, ZK distribueres i klynger, så lenge mer enn halvparten av maskinene i klyngen overlever, kan tjenesten leveres til omverdenen.
Rettferdighetsproblemer? Bruk av Zookeeper kan løse problemet med rettferdige låser, de midlertidige nodene som klienten oppretter i ZK er ordnet, og hver gang låsen frigjøres, kan ZK varsle den minste noden om å få tak i låsen, noe som sikrer rettferdighet.
Spørsmålet oppstår igjen, vi vet at Zookeeper må distribueres i klynger, vil det oppstå problemer med datasynkronisering som i Redis-klynger?
Zookeeper er en distribuert komponent som garanterer svak konsistens, altså til slutt konsistens.
Zookeeper benytter en datasynkroniseringsprotokoll kalt Quorum Based Protocol. Hvis det finnes N Zookeeper-servere i Zookeeper-klyngen (N er vanligvis oddetall, 3 kan oppfylle datapålitelighet og har høy lese- og skriveytelse, og 5 har best balanse mellom datapålitelighet og lese- og skriveytelse), synkroniseres en skriveoperasjon av brukeren først til N/2 + 1-servere, og returneres deretter til brukeren, slik at brukeren må skrive vellykket. Datasynkroniseringsprotokollen basert på Quorum Based Protocol bestemmer hvor konsekvent styrken Zookeeper kan støtte.
I et distribuert miljø er datalagring som oppfyller sterk konsistens i praksis ikke-eksisterende, og det krever at alle noder oppdateres synkront når dataene til én node oppdateres. Denne synkroniseringsstrategien finnes i master-slave synkron replikasjonsdatabasen. Denne synkroniseringsstrategien har imidlertid for stor innvirkning på skriveytelsen og sees sjelden i praksis. Fordi Zookeeper skriver N/2+1-noder synkront, og N/2 noder ikke oppdateres synkront, er ikke Zookeeper sterkt konsistent.
Brukerens dataoppdateringsoperasjon garanterer ikke at påfølgende lesninger vil lese den oppdaterte verdien, men vil til slutt vise konsistens. Å ofre konsistens betyr ikke å fullstendig ignorere konsistensen i dataene, ellers blir dataene kaotiske, så uansett hvor høy systemtilgjengeligheten er, uansett hvor god fordelingen er, er det uten verdi. Å ofre konsistens er bare at sterk konsistens i relasjonsdatabaser ikke lenger er nødvendig, men så lenge systemet kan oppnå endelig konsistens.
Om Zookeeper oppfyller kausal konsistens avhenger av hvordan klienten er programmert.
Praksiser som ikke tilfredsstiller kausal konsistens
- Prosess A skriver et datastykke til Zookeepers /z og returnerer det vellykket
- Prosess A informerer prosess B om at A har endret dataene i /z
- B leser dataene fra Dyrepasserens /z
- Siden serveren til Zookeeper som er koblet til B kanskje ikke har blitt oppdatert med A sine skrevne data, vil ikke B kunne lese A sine skriftlige data
Praksiser som oppfyller kausal konsistens
- Prosess B lytter etter dataendringer i /z på Zookeeper
- Prosess A skriver et datastykke til Zookeepers /z, og før det returnerer vellykket, må Zookeeper kalle lytteren registrert på /z, og lederen vil varsle B om dataendringen
- Etter at hendelsesresponsmetoden til prosess B er besvart, tar den de endrede dataene, så B vil definitivt kunne hente den endrede verdien
- Kausal konsistens refererer her til den kausale konsistensen mellom Leder og B, det vil si at lederen varsler dataene om en endring
Den andre hendelseslyttemekanismen er også metoden som bør brukes for å programmere Zookeeper riktig, så Zookeeper bør oppfylle den kausale konsistensen
Derfor, når vi implementerer distribuerte låser basert på Zookeeper, bør vi bruke praksisen med å tilfredsstille kausal konsistens, det vil si at trådene som venter på låsen lytter til endringene i låsen til Zookeeper, og når låsen frigjøres, vil Zookeeper varsle den ventende tråden som oppfyller fair lock-betingelsene.
Du kan bruke Zookeepers tredjeparts bibliotekklient direkte, som kapsler inn en reentrant lock-tjeneste.
Distribuerte låser implementert med ZK ser ut til å passe akkurat det vi forventet av en distribuert lås i begynnelsen av denne artikkelen. Men det er den ikke, og den distribuerte låsen implementert av Zookeeper har faktisk en ulempe, nemlig at ytelsen kanskje ikke er like høy som for caching-tjenesten. Fordi hver gang i prosessen med å lage og frigjøre en lås, må øyeblikkelige noder opprettes og ødelegges dynamisk for å realisere låsefunksjonen. Opprettelse og sletting av noder i ZK kan kun utføres via lederserveren, og deretter deles dataene med alle etterfølgermaskiner.
Fordeler med å bruke Zookeeper for å implementere distribuerte låser Løser effektivt enkeltpunktsproblemer, ikke-reentry-problemer, ikke-blokkeringsproblemer og låsefeil som ikke frigjøres. Det er relativt enkelt å implementere.
Ulemper ved å bruke Zookeeper for å implementere distribuerte låser Ytelsen er ikke like god som å bruke cache for å implementere distribuerte låser. En forståelse av prinsippene i ZK er nødvendig.
Sammenligning av de tre alternativene
Fra et perspektiv av forståelighet (fra lavt til høyt) Database > Cache > Zookeeper
Fra perspektivet implementeringskompleksitet (fra lav til høy) Zookeeper > cache > databaser
Fra et ytelsesperspektiv (fra høyt til lavt) Caching > Zookeeper >= database
Fra et pålitelighetsperspektiv (fra høyt til lavt) Zookeeper > cache > databaser
|