Om att flytta från Redis till Redis-kluster

Om att flytta från Redis till Redis-kluster

När det kommer till en produkt som har utvecklats i mer än ett decennium är det inte alls förvånande att hitta föråldrad teknik i den. Men vad händer om du om sex månader måste hålla belastningen 10 gånger högre, och kostnaden för fall kommer att öka hundratals gånger? I det här fallet behöver du en cool Highload Engineer. Men i avsaknad av en piga anförtrodde de mig att lösa problemet. I den första delen av artikeln kommer jag att berätta hur vi gick från Redis till Redis-kluster, och i den andra delen kommer jag att ge råd om hur du börjar använda klustret och vad du ska vara uppmärksam på när du använder det.

Teknikval

Är det så illa? separata Redis (fristående redis) i en konfiguration av 1 master och N slavar? Varför kallar jag det föråldrad teknik?

Nej, Redis är inte så illa... Det finns dock några brister som inte går att ignorera.

  • För det första stöder inte Redis mekanismer för återställning efter ett huvudfel. För att lösa detta problem använde vi en konfiguration med automatisk överföring av VIPs till en ny master, ändrade rollen för en av slavarna och bytte resten. Denna mekanism fungerade, men den kunde inte kallas en pålitlig lösning. För det första uppstod falsklarm, och för det andra var det engångsbruk, och efter drift krävdes manuella åtgärder för att ladda fjädern.

  • För det andra, att bara ha en mästare ledde till problemet med skärning. Vi var tvungna att skapa flera oberoende kluster "1 master och N slavar", sedan manuellt distribuera databaserna mellan dessa maskiner och hoppas att en av databaserna i morgon inte skulle svälla så mycket att den skulle behöva flyttas till en separat instans.

Vad är alternativen?

  • Den dyraste och rikaste lösningen är Redis-Enterprise. Detta är en boxad lösning med full teknisk support. Trots att det ser idealiskt ut ur teknisk synvinkel passade det inte oss av ideologiska skäl.
  • Redis-kluster. Out of the box finns stöd för master failover och sharding. Gränssnittet skiljer sig nästan inte från den vanliga versionen. Det ser lovande ut, vi pratar om fallgroparna senare.
  • Tarantool, Memcache, Aerospike och andra. Alla dessa verktyg gör ungefär samma sak. Men var och en har sina egna brister. Vi bestämde oss för att inte lägga alla våra ägg i en korg. Vi använder Memcache och Tarantool för andra uppgifter, och när vi ser framåt kommer jag att säga att det i vår praktik var fler problem med dem.

Specifikationer för användning

Låt oss ta en titt på vilka problem vi historiskt har löst med Redis och vilken funktionalitet vi använde:

  • Cache innan förfrågningar till fjärrtjänster som 2GIS | Golang

    GET SET MGET MSET "SELECT DB"

  • Cache före MYSQL | PHP

    GET SET MGET MSET SCAN "KEY BY PATTERN" "SELECT DB"

  • Huvudlagringen för tjänsten att arbeta med sessioner och förarkoordinater | Golang

    GET SET MGET MSET "SELECT DB" "ADD GEO KEY" "GET GEO KEY" SCAN

Som du kan se, ingen högre matematik. Vad är då svårigheten? Låt oss titta på varje metod separat.

metod
beskrivning
Funktioner i Redis-kluster
beslutet

FÖRSTÄLL
Skriv/läs nyckel

MGET MSET
Skriv/läs flera nycklar
Nycklarna kommer att finnas på olika noder. Färdiga bibliotek kan utföra flera operationer endast inom en nod
Ersätt MGET med en pipeline av N GET-operationer

VÄLJ DB
Välj den bas vi ska arbeta med
Stöder inte flera databaser
Lägg allt i en databas. Lägg till prefix till nycklar

SCAN
Gå igenom alla nycklar i databasen
Eftersom vi har en databas är det för dyrt att gå igenom alla nycklar i klustret
Behåll en invariant inom en nyckel och gör en HSCAN på denna nyckel. Eller vägra helt

GEO
Operationer med en geonyckel
Geonyckeln är inte skärrad

NYCKEL EFTER MÖNSTER
Söker efter en nyckel efter mönster
Eftersom vi har en databas kommer vi att söka över alla nycklar i klustret. För dyr
Avvisa eller bibehåll det invarianta, som i fallet med SCAN

Redis vs Redis-kluster

Vad förlorar vi och vad vinner vi när vi byter till ett kluster?

  • Nackdelar: vi förlorar funktionaliteten i flera databaser.
    • Om vi ​​vill lagra logiskt orelaterade data i ett kluster måste vi göra kryckor i form av prefix.
    • Vi förlorar alla "bas" operationer, såsom SCAN, DBSIZE, CLEAR DB, etc.
    • Multioperationer har blivit mycket svårare att implementera eftersom det kan kräva tillgång till flera noder.
  • fördelar:
    • Feltolerans i form av master failover.
    • Sharding på Redis-sidan.
    • Överför data mellan noder atomärt och utan stillestånd.
    • Lägg till och omfördela kapacitet och laster utan stillestånd.

Jag skulle dra slutsatsen att om du inte behöver ge en hög feltolerans, så är det inte värt att flytta till ett kluster, eftersom det kan vara en icke-trivial uppgift. Men om du till en början väljer mellan en separat version och en klusterversion, bör du välja ett kluster, eftersom det inte är värre och dessutom kommer att lindra en del av huvudvärken

Förbereder för att flytta

Låt oss börja med kraven för att flytta:

  • Det ska vara sömlöst. Ett komplett servicestopp i 5 minuter passar oss inte.
  • Det ska vara så säkert och gradvis som möjligt. Jag vill ha lite kontroll över situationen. Vi vill inte dumpa allt på en gång och be över återställningsknappen.
  • Minimal dataförlust när du flyttar. Vi förstår att det kommer att vara mycket svårt att flytta atomärt, så vi tillåter viss desynkronisering mellan data i vanliga och klustrade Redis.

Klusterunderhåll

Strax innan flytten bör vi fundera på om vi kan stödja klustret:

  • Diagram. Vi använder Prometheus och Grafana för att plotta CPU-belastning, minnesanvändning, antal klienter, antal GET-, SET-, AUTH-operationer, etc.
  • Expertis. Föreställ dig att du imorgon kommer att ha ett enormt kluster under ditt ansvar. Om det går sönder kan ingen annan än du fixa det. Om han börjar sakta ner kommer alla att springa mot dig. Om du behöver lägga till resurser eller omfördela belastningen, kom tillbaka till dig. För att inte bli grå vid 25 är det lämpligt att ta hand om dessa fall och kontrollera i förväg hur tekniken kommer att bete sig under vissa åtgärder. Låt oss prata om detta mer i detalj i avsnittet "Expert".
  • Övervakning och varningar. När ett kluster går sönder vill du vara den första att veta om det. Här begränsade vi oss till ett meddelande om att alla noder returnerar samma information om klustrets tillstånd (ja, det händer olika). Och andra problem kan upptäckas snabbare genom varningar från Redis kundtjänst.

korsning

Hur vi ska flytta:

  • Först och främst måste du förbereda ett bibliotek för att arbeta med klustret. Vi tog go-redis som grund för Go-versionen och ändrade den lite för att passa oss själva. Vi implementerade Multi-metoder genom pipelines och korrigerade också en aning reglerna för att upprepa förfrågningar. PHP-versionen hade fler problem, men vi bestämde oss så småningom på php-redis. De introducerade nyligen klusterstöd och det ser bra ut enligt vår mening.
  • Därefter måste du distribuera själva klustret. Detta görs bokstavligen i två kommandon baserat på konfigurationsfilen. Vi kommer att diskutera inställningen mer i detalj nedan.
  • För gradvis förflyttning använder vi torrläge. Eftersom vi har två versioner av biblioteket med samma gränssnitt (en för den vanliga versionen, den andra för klustret) kostar det ingenting att skapa en wrapper som fungerar med en separat version och parallellt duplicera alla förfrågningar till klustret, jämför svar och skriv avvikelser i loggarna (i vårt fall i NewRelic). Således, även om klusterversionen går sönder under utrullningen, kommer vår produktion inte att påverkas.
  • Efter att ha rullat ut klustret i torrt läge kan vi lugnt titta på grafen över svarsavvikelser. Om felfrekvensen sakta men säkert rör sig mot någon liten konstant så är allt bra. Varför finns det fortfarande avvikelser? Eftersom inspelning i en separat version sker lite tidigare än i klustret, och på grund av mikrofördröjning, kan data divergera. Allt som återstår är att titta på avvikelseloggarna, och om de alla förklaras av postens icke-atomicitet, då kan vi gå vidare.
  • Nu kan du byta torrläge i motsatt riktning. Vi kommer att skriva och läsa från klustret och duplicera det till en separat version. För vad? Under nästa vecka skulle jag vilja observera klustrets arbete. Om det plötsligt visar sig att det finns problem vid toppbelastning, eller om vi inte tagit hänsyn till något, har vi alltid en nödåterställning till den gamla koden och aktuella data tack vare torrläge.
  • Allt som återstår är att inaktivera torrläge och demontera den separata versionen.

Expertis

Först, kortfattat om klusterdesignen.

För det första är Redis en nyckel-värde butik. Godtyckliga strängar används som nycklar. Tal, strängar och hela strukturer kan användas som värden. Det finns väldigt många av de senare, men för att förstå den allmänna strukturen är detta inte viktigt för oss.
Nästa abstraktionsnivå efter nycklar är slots (SLOTS). Varje nyckel tillhör en av 16 383 platser. Det kan finnas hur många nycklar som helst i varje fack. Således är alla nycklar uppdelade i 16 383 disjunkta uppsättningar.
Om att flytta från Redis till Redis-kluster

Därefter måste det finnas N masternoder i klustret. Varje nod kan ses som en separat Redis-instans som vet allt om andra noder inom klustret. Varje huvudnod innehåller ett antal luckor. Varje slot tillhör endast en huvudnod. Alla platser måste fördelas mellan noder. Om några platser inte tilldelas kommer nycklarna som är lagrade i dem att vara oåtkomliga. Det är vettigt att köra varje masternod på en separat logisk eller fysisk maskin. Det är också värt att komma ihåg att varje nod bara körs på en kärna, och om du vill köra flera Redis-instanser på samma logiska maskin, se till att de körs på olika kärnor (vi har inte provat detta, men i teorin borde det fungera) . I huvudsak ger masternoder regelbunden sharding, och fler masternoder tillåter skriv- och läsbegäranden att skalas.

Efter att alla nycklar är fördelade bland luckorna, och luckorna är utspridda bland masternoderna, kan ett godtyckligt antal slavnoder läggas till varje masternod. Inom varje sådan master-slavlänk kommer normal replikering att fungera. Slavar behövs för att skala läsbegäranden och för failover i händelse av masterfel.
Om att flytta från Redis till Redis-kluster

Låt oss nu prata om operationer som det skulle vara bättre att kunna göra.

Vi kommer åt systemet via Redis-CLI. Eftersom Redis inte har en enda ingångspunkt kan du utföra följande operationer på någon av noderna. Vid varje punkt uppmärksammar jag separat möjligheten att utföra operationen under belastning.

  • Det första och viktigaste vi behöver är klusternodoperationen. Den returnerar tillståndet för klustret, visar en lista över noder, deras roller, slotdistribution, etc. Mer information kan erhållas med hjälp av klusterinformation och klusterplatser.
  • Det skulle vara trevligt att kunna lägga till och ta bort noder. För detta ändamål finns klusterträffar och klusterglömverksamheter. Observera att klusterforget måste tillämpas på VARJE nod, både master och repliker. Och klustermöten behöver bara anropas på en nod. Denna skillnad kan vara oroande, så det är bäst att lära sig om det innan du går live med ditt kluster. Att lägga till en nod görs säkert i strid och påverkar inte driften av klustret på något sätt (vilket är logiskt). Om du ska ta bort en nod från klustret bör du se till att det inte finns några luckor kvar på den (annars riskerar du att förlora åtkomst till alla nycklar på denna nod). Ta inte heller bort en master som har slavar, annars kommer en onödig röst på en ny master att utföras. Om noderna inte längre har slots så är detta ett litet problem, men varför behöver vi extra val om vi kan ta bort slavarna först.
  • Om du måste byta master- och slavpositioner med kraft, kommer kommandot för kluster-failover att fungera. När du kallar det i strid måste du förstå att befälhavaren kommer att vara otillgänglig under operationen. Vanligtvis sker omkopplingen på mindre än en sekund, men är inte atomär. Du kan förvänta dig att vissa förfrågningar till mastern kommer att misslyckas under denna tid.
  • Innan du tar bort en nod från klustret bör det inte finnas några spår kvar på den. Det är bättre att omfördela dem med kommandot cluster reshard. Slots kommer att överföras från en master till en annan. Hela operationen kan ta flera minuter, det beror på mängden data som överförs, men överföringsprocessen är säker och påverkar inte driften av klustret på något sätt. Således kan all data överföras från en nod till en annan direkt under belastning och utan att behöva oroa sig för dess tillgänglighet. Men det finns också finesser. För det första är dataöverföring förknippad med en viss belastning på mottagar- och avsändarnoderna. Om mottagarnoden redan är hårt belastad på processorn, bör du inte ladda den med att ta emot nya data. För det andra, så snart det inte finns en enda lucka kvar på den sändande mastern, kommer alla dess slavar omedelbart att gå till mastern till vilken dessa luckor överfördes. Och problemet är att alla dessa slavar kommer att vilja synkronisera data på en gång. Och du kommer att ha tur om det är partiell snarare än fullständig synkronisering. Ta hänsyn till detta och kombinera operationerna med att överföra slots och inaktivera/överföra slavar. Eller hoppas att du har tillräcklig säkerhetsmarginal.
  • Vad ska du göra om du under överföringen upptäcker att du har tappat bort dina slots någonstans? Jag hoppas att det här problemet inte påverkar dig, men om det gör det finns det en klusterfixoperation. Åtminstone kommer hon att sprida luckorna över noderna i en slumpmässig ordning. Jag rekommenderar att du kontrollerar dess funktion genom att först ta bort noden med distribuerade slots från klustret. Eftersom data i oallokerade platser redan är otillgängliga är det för sent att oroa sig för problem med tillgängligheten av dessa platser. Åtgärden kommer i sin tur inte att påverka distribuerade slots.
  • En annan användbar operation är monitor. Det låter dig se i realtid hela listan över förfrågningar som går till noden. Dessutom kan du greppa den och ta reda på om det finns den nödvändiga trafiken.

Det är också värt att nämna master failover-proceduren. Kort sagt, det finns, och enligt mig fungerar det utmärkt. Tro dock inte att om du kopplar ur nätsladden på en maskin med en masternod kommer Redis omedelbart att byta över och kunder kommer inte att märka förlusten. I min praktik sker bytet på några sekunder. Under denna tid kommer en del av datan att vara otillgänglig: befälhavarens otillgänglighet upptäcks, noder röstar på en ny, slavar växlas, data synkroniseras. Det bästa sättet att försäkra sig om att programmet fungerar är att genomföra lokala övningar. Höj klustret på din bärbara dator, ge det en minimal belastning, simulera en krasch (till exempel genom att blockera portarna) och utvärdera växlingshastigheten. Enligt min mening, först efter att ha spelat på detta sätt i en dag eller två kan du vara säker på att tekniken fungerar. Tja, eller hoppas att mjukvaran som hälften av Internet använder förmodligen fungerar.

konfiguration

Ofta är konfigurationen det första du behöver för att börja arbeta med verktyget. Och när allt fungerar vill du inte ens röra konfigurationen. Det tar lite ansträngning att tvinga dig själv att gå tillbaka till inställningarna och gå igenom dem noggrant. I mitt minne hade vi minst två allvarliga fel på grund av ouppmärksamhet på konfigurationen. Var särskilt uppmärksam på följande punkter:

  • timeout 0
    Tid efter vilken inaktiva anslutningar stängs (i sekunder). 0 - stäng inte
    Inte alla våra bibliotek kunde stänga anslutningar korrekt. Genom att inaktivera den här inställningen riskerar vi att nå gränsen för antalet klienter. Å andra sidan, om det finns ett sådant problem, kommer automatisk avslutning av förlorade anslutningar att maskera det, och vi kanske inte märker det. Dessutom bör du inte aktivera den här inställningen när du använder beständiga anslutningar.
  • Spara xy & tillägg ja
    Sparar en RDB-ögonblicksbild.
    Vi kommer att diskutera RDB/AOF-frågor i detalj nedan.
  • stop-writes-on-bgsave-error no & slave-serve-stale-data ja
    Om den är aktiverad, om RDB-ögonblicksbilden går sönder, kommer mastern att sluta acceptera ändringsförfrågningar. Om anslutningen till mastern bryts kan slaven fortsätta att svara på förfrågningar (ja). Eller kommer att sluta svara (nej)
    Vi är inte nöjda med situationen där Redis förvandlas till en pumpa.
  • repl-ping-slave-period 5
    Через этот промежуток времени мы начнем беспокоиться о том, что мастер сломался и пора бы провести процедуру failover’a.
    Du måste manuellt hitta en balans mellan falska positiva resultat och att utlösa en failover. I vår praktik är detta 5 sekunder.
  • repl-backlog-storlek 1024mb & epl-backlog-ttl 0
    Vi kan lagra exakt så mycket data i en buffert för en misslyckad replik. Om bufferten tar slut måste du synkronisera helt.
    Övning tyder på att det är bättre att sätta ett högre värde. Det finns många anledningar till varför en replik kan börja släpa efter. Om det släpar, så kämpar din mästare troligen redan för att klara sig, och full synkronisering kommer att vara droppen.
  • maxklienter 10000 XNUMX
    Maximalt antal engångskunder.
    Enligt vår erfarenhet är det bättre att sätta ett högre värde. Redis hanterar 10k anslutningar bra. Se bara till att det finns tillräckligt med uttag på systemet.
  • maxmemory-policy volatile-ttl
    Regeln enligt vilken nycklar tas bort när den tillgängliga minnesgränsen nås.
    Det viktiga här är inte själva regeln, utan förståelsen för hur detta kommer att ske. Redis kan prisas för sin förmåga att fungera normalt när minnesgränsen är nådd.

RDB och AOF problem

Även om Redis själv lagrar all information i RAM, finns det också en mekanism för att spara data till disk. Mer exakt tre mekanismer:

  • RDB-snapshot - en komplett ögonblicksbild av all data. Ställ in med SAVE XY-konfigurationen och läser "Spara en fullständig ögonblicksbild av all data var X sekund om minst Y-nycklar har ändrats."
  • Enbart tilläggsfil - en lista över operationer i den ordning de utförs. Lägger till nya inkommande operationer till filen var X:e sekund eller varje Y-operation.
  • RDB och AOF är en kombination av de två föregående.

Alla metoder har sina fördelar och nackdelar, jag kommer inte att lista dem alla, jag kommer bara att uppmärksamma punkter som enligt min mening inte är uppenbara.

För det första måste du anropa FORK för att spara en RDB-ögonblicksbild. Om det finns mycket data kan detta hänga hela Redis under en period av några millisekunder till en sekund. Dessutom behöver systemet allokera minne för en sådan ögonblicksbild, vilket leder till behovet av att ha en dubbel tillgång på RAM på den logiska maskinen: om 8 GB tilldelas för Redis, bör 16 GB vara tillgängligt på den virtuella maskinen med Det.

För det andra finns det problem med partiell synkronisering. I AOF-läge, när slaven är återansluten, istället för partiell synkronisering, kan full synkronisering utföras. Varför detta händer kunde jag inte förstå. Men det är värt att komma ihåg detta.

Dessa två punkter får oss redan att fundera på om vi verkligen behöver dessa data på disken om allt redan är duplicerat av slavar. Data kan bara gå förlorade om alla slavar misslyckas, och detta är ett problem med "brand i DC". Som en kompromiss kan du föreslå att spara data endast på slavar, men i det här fallet måste du se till att dessa slavar aldrig kommer att bli en master under katastrofåterställning (för detta finns en slavprioritetsinställning i deras konfiguration). För oss själva funderar vi i varje specifikt fall på om det är nödvändigt att spara data på disken, och oftast är svaret "nej".

Slutsats

Sammanfattningsvis hoppas jag att jag kunde ge en allmän uppfattning om hur redis-cluster fungerar för dem som inte har hört talas om det alls, och även uppmärksammat några icke-uppenbara punkter för dem som har använt det under en lång tid.
Tack för din tid och som alltid är kommentarer om ämnet välkomna.

Källa: will.com

Lägg en kommentar