
Artem Denisov ( , )
Badoo er verdens største datingside. Vi har i øjeblikket omkring 330 millioner registrerede brugere på verdensplan. Men hvad der er meget vigtigere i forbindelse med vores samtale i dag, er, at vi gemmer omkring 3 petabyte af brugerbilleder. Hver dag uploader vores brugere omkring 3,5 millioner nye billeder, og læsebelastningen er ca 80 tusinde anmodninger i sekundet. Det er ret meget for vores backend, og nogle gange kan det være svært.

Jeg vil tale om designet af dette system, der gemmer og leverer billeder generelt, og jeg vil give en udviklers perspektiv på det. Der vil være et kort tilbageblik på, hvordan det udviklede sig, hvor jeg vil skitsere de vigtigste milepæle, men jeg vil kun tale mere detaljeret om de løsninger, som vi bruger i øjeblikket.
Lad os nu komme i gang.

Det bliver som sagt et tilbageblik, og lad os for at starte et sted tage det mest banale eksempel.

Vi har en fælles opgave, vi skal acceptere, opbevare og levere billeder af brugere. I denne form er opgaven generel, vi kan bruge hvad som helst:
- moderne cloud storage,
- en kasseløsning, som der også er mange af nu;
- Vi kan sætte flere maskiner op i vores datacenter og sætte store harddiske på dem og gemme billeder der.
Badoo bor historisk - både nu og dengang (på det tidspunkt, hvor det lige dukkede op) - på sine egne servere, inde i vores egne datacentre. Derfor var denne mulighed optimal for os.

Vi tog lige et par maskiner, kaldte dem "fotos", og vi fik en klynge, der gemmer billeder. Men det ser ud som om der mangler noget. For at alt dette skal fungere, skal vi på en eller anden måde bestemme, på hvilken maskine, hvilke billeder vi vil gemme. Og her er der ingen grund til at opdage Amerika.

Vi tilføjer et felt til vores lager med brugeroplysninger. Dette vil være skæringsnøglen. I vores tilfælde kaldte vi det place_id, og dette sted-id peger på det sted, hvor brugernes billeder er gemt. Vi laver kort.
På det første trin kan dette endda gøres manuelt - vi siger, at et billede af denne bruger med et sådant sted vil lande på sådan en server. Takket være dette kort ved vi altid, hvornår en bruger uploader et billede, hvor det skal gemmes, og vi ved, hvor vi skal levere det fra.
Dette er en absolut triviel ordning, men den har ganske betydelige fordele. Det første er, at det som sagt er enkelt, og det andet er, at vi med denne tilgang nemt kan skalere horisontalt ved blot at levere nye biler og tilføje dem til kortet. Der er ikke andet at gøre.
Sådan var det for os i nogen tid.

Det var et sted omkring 2009. De leverede biler, de leverede...
Og på et tidspunkt begyndte vi at bemærke, at denne ordning havde visse ulemper. Hvad er ulemperne?
Først og fremmest er det begrænset kapacitet. Vi kan ikke passe så mange harddiske på én fysisk server, som vi gerne vil. Og dette blev med tiden og efterhånden som datasættet voksede et klart problem.
Og for det andet. Dette er en atypisk konfiguration af maskiner, da sådanne maskiner er svære at genbruge i andre klynger, de er ret specifikke, dvs. de skal være svage i ydeevne, men samtidig have en stor harddisk.
Det hele var i 2009, men i princippet er disse krav stadig relevante i dag. Vi har et retrospektiv, så i 2009 var alt rigtig dårligt med det her.
Og det sidste punkt er prisen.

Prisen var meget høj dengang, og vi måtte kigge efter nogle alternativer. Dem. Vi skulle på en eller anden måde bedre udnytte både pladsen i datacentrene og de fysiske servere, hvor alt dette var placeret. Og vores systemingeniører startede en stor undersøgelse, hvor de gennemgik en masse forskellige muligheder. De så også på klyngefilsystemer som PolyCeph og Lustre. Der var præstationsproblemer og en del hård brug. De nægtede. Vi forsøgte at montere hele datasættet via NFS på hver maskine for på en eller anden måde at skalere det. Læsning gik heller ikke godt; vi prøvede forskellige løsninger fra forskellige leverandører.
Og til sidst besluttede vi os for at bruge det, der kaldes et Storage Area Network.

Det er store SHD'er, der er specielt designet til lagring af store mængder data. Det er hylder med diske, der er monteret på de endelige outputmaskiner via optik. At. vi har en pulje af maskiner, ganske små, og disse SHD'er, som er gennemsigtige for vores sendelogik, dvs. for vores nginx eller hvem der ellers serverer anmodninger om disse billeder.
Denne beslutning havde indlysende fordele. Dette er SHD. Det er designet til at gemme billeder. Dette virker billigere end blot at installere harddiske i maskinerne.
Det andet plus.

Dette er, at kapaciteten er blevet meget større, det vil sige, at vi kan indpasse meget mere opbevaring i et meget mindre rum.
Men der var også nogle ulemper, som viste sig ret hurtigt. Efterhånden som antallet af brugere og belastningen på dette system voksede, begyndte der at opstå problemer med ydeevnen. Og problemet her er ret indlysende - enhver SHD designet til at gemme mange fotos på et lille rum lider normalt af intensiv læsning. Dette gælder faktisk for enhver cloud storage eller noget andet. Lige nu har vi ikke et ideelt lager, der ville være uendeligt skalerbart, du kan proppe hvad som helst i det, og det ville håndtere aflæsninger meget godt. Især tilfældige aflæsninger.

Ligesom det er tilfældet med vores billeder, fordi billeder er anmodet om inkonsekvent, og dette påvirker i høj grad deres ydeevne.
Selv ifølge dagens tal, hvis vi har et sted mere end 500 RPS for fotos på maskinen, som lageret er tilsluttet, begynder problemerne. Og det var slemt nok for os, for antallet af brugere vokser, tingene bliver kun værre. Dette skal på en eller anden måde optimeres.
For at optimere besluttede vi på det tidspunkt naturligvis at se på belastningsprofilen - hvad sker der generelt, hvad skal optimeres.

Og her spiller alt i vores hænder.
Jeg sagde allerede i det første slide: Vi har 80 tusinde anmodninger pr. sekund til læsning med kun 3,5 millioner uploads pr. dag. Det vil sige, at dette er en forskel på tre størrelsesordener. Det er indlysende, at læsning skal optimeres, og det er næsten klart hvordan.
Der er endnu en lille pointe. Tjenestens specifikationer er sådan, at en person registrerer sig, uploader et billede, begynder derefter aktivt at se på andre mennesker, kan lide dem og vises aktivt til andre mennesker. Så finder han en partner eller finder ikke en partner, som det sker, og holder op med at bruge tjenesten i et stykke tid. I dette øjeblik, når han bruger det, er hans billeder meget varme - de er efterspurgte, de bliver set af mange mennesker. Når han stopper med at gøre dette, falder han hurtigt ud af den intense eksponering, han havde før for andre mennesker, og hans billeder bliver praktisk talt aldrig efterspurgt.

Dem. Vi har et meget lille hot datasæt. Men samtidig er der rigtig mange ønsker om det. Og den åbenlyse løsning her er at tilføje cache.
LRU cache vil løse alle vores problemer. Hvad gør vi?

Vi tilføjer endnu en forholdsvis lille en foran vores store lagerklynge, som kaldes photocaches (photocache). Det er dybest set kun en caching proxy.
Hvordan fungerer det indefra? Her er vores bruger, her er opbevaring. Alt er som før. Hvad tilføjer vi mellem dem?

Det er bare en maskine med en fysisk lokal disk, der er hurtig. Det er med SSD, lad os sige. Og på denne disk er der gemt noget lokal cache.
Hvordan ser det ud? Brugeren sender en anmodning om et billede. NGINX leder efter det i den lokale cache først. Hvis ikke, laver den blot et proxy_pass til vores lager, downloader billedet derfra og giver det til brugeren.
Men dette er meget banalt, og det er ikke klart, hvad der sker indeni. Det virker sådan noget.

Cachen er logisk opdelt i tre lag. Når jeg siger "tre lag", betyder det ikke, at der er en form for komplekst system der. Nej, disse er blot tre mapper i filsystemet:
- Dette er en buffer, hvor billeder, der lige er downloadet fra proxyen, placeres.
- Dette er en hot cache, der gemmer billeder, der i øjeblikket aktivt anmodes om.
- Og en kold cache, hvor billeder gradvist skubbes ud af den varme cache, når der kommer færre forespørgsler til dem.
For at dette skal virke, skal vi på en eller anden måde administrere denne cache, vi skal omarrangere billederne i den osv. Dette er også en meget primitiv proces.

Nginx skriver ganske enkelt til RAMDisk access.log for hver anmodning og angiver stien til det foto, det lige har serveret (relativ sti, selvfølgelig), og hvilken partition det blev serveret af. Dem. der kan stå "foto 1" og derefter enten buffer eller hot cache, eller cold cache eller proxy.
Afhængigt af dette skal vi på en eller anden måde beslutte, hvad vi skal gøre med billedet.
Vi har en lille dæmon kørende på hver maskine, som konstant læser denne log og gemmer statistik om brugen af bestemte fotos i sin hukommelse.

Han samler bare der, holder styr på tingene og laver med jævne mellemrum følgende. Han flytter aktivt efterspurgte billeder, som der kommer mange anmodninger om, til den varme cache, uanset hvor de befinder sig.

Billeder, der sjældent efterspørges, og som er blevet efterspurgt sjældnere, skubbes gradvist fra den varme cache til den kolde cache.

Og når vi løber tør for plads i cachen, begynder vi bare at slette alt fra den kolde cache vilkårligt. Og dette fungerer i øvrigt godt.
For at billedet skal gemmes med det samme ved proxy til bufferen, bruger vi proxy_store-direktivet og bufferen er også en RAMDisk, det vil sige for brugeren virker det meget hurtigt. Dette vedrører selve cachingserverens interne dele.
Tilbage står spørgsmålet om, hvordan man fordeler anmodninger på tværs af disse servere.
Lad os sige, at der er en klynge på tyve lagermaskiner og tre caching-servere (sådan skete det).

Vi skal på en eller anden måde bestemme, hvilke anmodninger der er til hvilke billeder og hvor vi skal lande.
Den mest almindelige mulighed er Round Robin. Eller gør det ved et uheld?
Dette har naturligvis en række ulemper, fordi vi vil bruge cachen meget ineffektivt i en sådan situation. Forespørgsler vil lande på nogle tilfældige maskiner: her er det cache, på naboen er det der ikke længere. Og hvis alt dette virker, vil det fungere meget dårligt. Selv med et lille antal maskiner i klyngen.
Vi skal på en eller anden måde klart bestemme, hvilken server der skal lande hvilken anmodning.
Der er en banal måde. Vi tager hashen af URL'en eller hashen af vores sharding nøgle, som er i URL'en, og dividerer det ligeligt med antallet af servere. Vil det virke? Vilje.

Dem. vi har en 2% forespørgsel, for eksempel for nogle "example_url" vil den altid lande på serveren med indeks "XNUMX", og cachen vil konstant blive udnyttet bedst muligt.
Men der er et problem med omfordeling i sådan en ordning. Resharding - jeg mener at ændre antallet af servere.
Lad os sige, at vores caching-klynge ikke længere er på niveau, og vi beslutter at tilføje en anden maskine.
Lad os tilføje.

Nu er alt deleligt ikke med tre, men med fire. Så næsten alle de nøgler, vi havde før, næsten alle URL'erne lever nu på andre servere. Hele cachen blev ugyldig på blot et øjeblik. Alle anmodninger faldt på vores lagerklynge, den blev syg, der var lammelsesangreb og utilfredse brugere. Det vil jeg ikke gøre.
Denne mulighed passer heller ikke os.
At. hvad skal vi gøre? Vi skal på en eller anden måde bruge cachen effektivt, konsekvent lande den samme anmodning på den samme server, men stadig være modstandsdygtige over for resharding. Og der er sådan en løsning, det er ikke så svært. Det kaldes konsekvent hashing.

Hvordan ser det ud?

Vi tager en funktion fra sharding-tasten og spreder alle dens værdier på en cirkel. Dem. ved punkt 0 konvergerer dens minimums- og maksimumværdier. Dernæst placerer vi alle vores servere på den samme cirkel på omtrent følgende måde:

Hver server er defineret af et punkt, og den sektor, der går med uret til den, betjenes derfor af denne vært. Når vi modtager forespørgsler, ser vi med det samme, at for eksempel anmodning A har en hash som denne, og den betjenes af server 2. Forespørgsel B betjenes af server 3. Og så videre.

Hvad sker der i denne situation under omdeling?

Vi ugyldiggør ikke hele cachen, som før, og flytter ikke alle nøglerne, men vi flytter hver sektor en lille afstand, så så at sige, vores sjette server, som vi vil tilføje, passer ind i det frigjorte rum, og vi tilføjer det der.

I en sådan situation skifter tasterne naturligvis også. Men de glider meget svagere end før. Og vi ser, at vores første to nøgler forblev på deres servere, og cacheserveren blev kun ændret for den sidste nøgle. Dette fungerer ret effektivt, og hvis du tilføjer nye værter trinvist, så er dette ikke et stort problem. Du tilføjer og tilføjer lidt efter lidt, venter til cachen er fuld igen, og alt fungerer fint.
Det eneste spørgsmål er tilbage, når der er afslag. Lad os antage, at en af vores biler er gået i stykker.

Og vi ønsker ikke rigtig at regenerere dette kort i øjeblikket, ugyldiggøre en del af cachen og så videre, hvis for eksempel maskinen genstartede, og vi på en eller anden måde er nødt til at servicere anmodninger. Vi har simpelthen en backup-fotocache på hvert websted, der fungerer som en erstatning for enhver maskine, der i øjeblikket er nede. Og hvis en af vores servere pludselig bliver utilgængelig, går trafikken dertil. Naturligvis har vi ingen cache der, dvs. det er koldt, men i det mindste bliver brugeranmodninger behandlet. Er det et kort interval, så oplever vi det ganske roligt. Der er simpelthen mere belastning på opbevaring. Hvis dette interval er langt, kan vi allerede tage en beslutning, om vi vil fjerne denne server fra kortet eller ej, eller måske erstatte den med en anden.
Dette handler om caching-systemet. Lad os se på resultaterne.
Det ser ud til, at der ikke er noget kompliceret her. Men denne metode til at administrere cachen gav os en hitrate på omkring 98%. Dem. Af disse 80 tusinde forespørgsler i sekundet når kun 1600 lagrene, og det er en helt normal belastning, de kan klare det roligt, vi har altid en reserve.
Vi placerede disse servere i tre af vores DC'er og fik tre tilstedeværelsespunkter - Prag, Miami og Hong Kong.

At. De er mere eller mindre lokale for hvert af vores målmarkeder.
Og som en fin bonus fik vi denne caching proxy, hvor CPU'en faktisk er inaktiv, fordi den ikke rigtig er nødvendig for at levere indholdet. Og der, ved hjælp af NGINX+ Lua, implementerede vi en masse hjælpelogik.

For eksempel kan vi eksperimentere med webp eller progressiv jpeg (disse er effektive moderne formater), se hvordan det påvirker trafikken, træffe nogle beslutninger, aktivere for visse lande osv.; lav dynamisk ændring af størrelse eller beskær fotos på farten.
Dette er en god use case, når du for eksempel har en mobilapplikation, der viser billeder, og mobilapplikationen ikke ønsker at spilde klientens CPU ved at anmode om et stort billede og derefter ændre størrelsen på det til en vis størrelse, så det passer ind i visningen. Vi kan blot dynamisk angive nogle parametre i URL'en i UPort betinget, og fotocachen vil ændre størrelsen på selve billedet. Som regel vil den vælge størrelsen, som vi fysisk har på disken, så tæt som muligt på den anmodede, og nedskalere den til specifikke koordinater.
Forresten har vi gjort tilgængelige for offentligheden videooptagelser fra de sidste fem år af konferencen for udviklere af højbelastningssystemer . Se, lær, del og abonner på .
Vi kan også tilføje en masse produktlogik der. For eksempel kan vi tilføje forskellige vandmærker ved hjælp af URL-parametre, sløring eller pixelering af billeder. Det er, når vi vil vise et billede af en person, men vi ønsker ikke at vise hans ansigt, det fungerer godt, det hele er implementeret her.
Hvad fik vi? Vi har tre tilstedeværelsespunkter, god hitrate, og vi har ikke nogen CPU inaktiv på disse maskiner. Han er nu selvfølgelig blevet vigtigere end før. Vi skal have mere kraftfulde biler på vores maskiner, men det er det værd.
Det drejer sig om levering af fotografier. Alt her er helt klart og tydeligt. Jeg tror, jeg ikke har opdaget Amerika, næsten alle CDN'er fungerer på denne måde.
Og højst sandsynligt kan en sofistikeret lytter have et spørgsmål: hvorfor ikke bare tage og ændre alt til CDN? Det ville være nogenlunde det samme, alle moderne CDN'er kan gøre dette. Og det er der en række grunde til.
Den første er fotos.

Dette er et af nøglepunkterne i vores infrastruktur, og vi har brug for så meget kontrol over det som muligt. Hvis det er en tredjepartsleverandørløsning, og du ikke har kontrol over det, bliver det ret svært at leve med, når du har et stort datasæt, og når du har et meget stort flow af brugeranmodninger.
Lad mig give dig et eksempel. Nu, på vores infrastruktur, for eksempel i tilfælde af nogle problemer eller underjordiske banker, kan vi gå hen til bilen og få en snak der, så at sige. Vi kan tilføje en samling af nogle målinger, som kun vi har brug for, vi kan på en eller anden måde eksperimentere, se, hvordan det påvirker graferne, og så videre. Lige nu bliver der indsamlet en masse statistik om denne caching-klynge. Og vi ser med jævne mellemrum på det og studerer nogle anomalier i lang tid. Hvis det var på CDN-siden, ville det være meget sværere at kontrollere. Eller hvis der for eksempel sker en form for ulykke, ved vi, hvad der skete, vi ved, hvordan vi skal leve med det, og hvordan vi overvinder det. Dette er den første konklusion.
Den anden konklusion er også ret historisk, fordi systemet har været under udvikling i lang tid, og der var mange forskellige forretningskrav på forskellige stadier, og de passer ikke altid ind i CDN-konceptet.
Og en pointe, der følger af den forrige –

Dette skyldes, at vi har en masse specifik logik på fotocaches, som ikke altid er muligt at tilføje efter anmodning. Det er usandsynligt, at nogen CDN vil tilføje nogen tilpassede ting til dig på din anmodning. For eksempel kryptering af URL'er, hvis du ikke ønsker, at klienten skal kunne ændre noget. Du vil ændre URL'en på serveren og kryptere den, og derefter sende nogle dynamiske parametre her.
Hvilken konklusion kan man drage? I vores tilfælde er CDN ikke et særlig godt alternativ.

Og i dit tilfælde, hvis du har nogle specifikke forretningskrav, så kan du nemt selv implementere det, jeg viste dig. Og dette vil fungere godt med en lignende belastningsprofil.
Men hvis du har en generel løsning, og opgaven ikke er særlig specifik, kan du sagtens tage CDN. Eller hvis tid og ressourcer er meget vigtigere for dig end kontrol.

Og moderne CDN'er har næsten alt, hvad jeg har fortalt dig om nu. Bortset fra plus eller minus nogle funktioner.
Det handler om at forære billeder væk.
Lad os nu gå lidt frem i vores retrospektiv og tale om opbevaring.
Året 2013 var i gang.

Cachingservere er blevet tilføjet, ydeevneproblemer er forsvundet. Alt er fint. Datasættet vokser. I 2013 havde vi omkring 80 servere forbundet til lager og omkring 40 caching-servere i hvert datacenter. Dette er 560 terabyte data på hvert datacenter, det vil sige cirka en petabyte i alt.

Og efterhånden som datasættet voksede, begyndte driftsomkostningerne at stige kraftigt. Hvordan kom dette til udtryk?

I dette diagram, der er tegnet - med et SAN, med maskiner og caches tilsluttet - er der mange fejlpunkter. Hvis vi allerede havde håndteret fejlen i caching-servere tidligere, var alt mere eller mindre forudsigeligt og klart der, så var alt meget værre på lagersiden.
For det første selve Storage Area Network (SAN), som kan fejle.
For det andet forbindes den via optik til slutmaskinerne. Der kan være problemer med optiske kort, tændrør.

Selvfølgelig er der ikke så mange af dem som med selve SAN, men ikke desto mindre er disse også fejlpunkter.
Dernæst er selve maskinen, som er forbundet med lageret. Det kan også fejle.

I alt har vi tre fejlpunkter.
Ydermere er der ud over fejlpunkterne stor vedligeholdelse af selve lagerfaciliteterne.
Det er et komplekst flerkomponentsystem, og systemingeniører kan finde det svært at arbejde med.
Og det sidste, vigtigste punkt. Hvis nogen af disse tre punkter mislykkes, har vi en chance for at miste brugerdata, der ikke er nul, fordi filsystemet kan være beskadiget.

Lad os sige, at vores filsystem er beskadiget. For det første tager dens gendannelse lang tid - det kan tage en uge, hvis der er en stor mængde data. Og for det andet vil vi i sidste ende højst sandsynligt få en masse uforståelige filer, der på en eller anden måde skal matches med brugernes billeder. Og vi risikerer at miste data. Risikoen er ret høj. Og jo oftere sådanne situationer sker, og jo flere problemer der opstår i hele denne kæde, jo højere er denne risiko.
Det måtte der gøres noget ved. Og vi besluttede, at vi bare skulle sikkerhedskopiere dataene. Dette er faktisk en oplagt løsning og en god en. Hvad gjorde vi?

Sådan så vores server ud, da den før var forbundet til lageret. Dette er en hovedsektion, det er bare en blokenhed, som faktisk er en montering til fjernlagring via optik.
Vi har lige tilføjet et andet afsnit.

Vi satte et andet lager ved siden af det (heldigvis er det ikke så dyrt) og kaldte det en backup-partition. Den er også forbundet via optik og er placeret på samme maskine. Men vi skal på en eller anden måde synkronisere dataene mellem dem.
Her laver vi bare en asynkron kø i nærheden.

Hun har ikke særlig travlt. Vi ved, at vi ikke har mange rekorder. En kø er simpelthen en tabel i MySQL, hvor linjer som "vi skal tage backup af dette billede" er skrevet. Med enhver ændring eller upload kopierer vi fra hovedpartitionen til sikkerhedskopien asynkront eller blot med en baggrundsarbejder.
Og dermed har vi altid to sammenhængende afsnit. Selvom en del af dette system fejler, kan vi altid ændre hovedpartitionen med sikkerhedskopien, og alt vil fortsætte med at fungere.
Men på grund af dette øges læsebelastningen meget, for udover klienter, der læser fra hovedafsnittet, fordi de først ser på billedet der (det er nyere der), og derefter ser på backuppen, hvis de ikke fandt det (men NGINX gør det simpelthen), er et andet plus, at vores backup-system nu læser fra hovedafsnittet. Det er ikke, at det var en flaskehals, men jeg ønskede ikke at øge belastningen, i bund og grund, bare sådan.
Og vi tilføjede en tredje disk, som er en lille SSD, og vi kaldte den en buffer.

Hvordan fungerer det nu.
Brugeren uploader et billede til bufferen, hvorefter en hændelse smidt ind i køen om, at det skal kopieres til to partitioner. Det kopieres, og fotografiet lever på bufferen i nogen tid (lad os sige en dag), og først derefter downloades det derfra. Dette forbedrer brugeroplevelsen markant, fordi brugeren uploader et billede, som regel anmoder om straks at begynde at følge det, eller han selv opdaterer siden. Men det hele afhænger af den applikation, der uploader.
Eller for eksempel andre mennesker, som han begyndte at vise sig selv til, sender straks anmodninger efter dette billede. Det er ikke i cachen endnu, den første anmodning sker meget hurtigt. Grundlæggende det samme som med photocache. Langsom opbevaring spiller overhovedet ingen rolle i dette. Og når det er hentet om en dag, bliver det enten cachet på vores cachinglag, eller også bliver det højst sandsynligt ikke længere nødvendigt af nogen. Dem. Brugeroplevelsen her er blevet væsentligt forbedret takket være så simple manipulationer.
Nå, og vigtigst af alt: vi holdt op med at miste data.

Vi, lad os sige, stoppede potentielt miste data, fordi vi ikke rigtig mistede nogen. Men der var fare. Vi ser, at denne løsning selvfølgelig er god, men det er lidt ligesom at glatte over symptomerne på problemet i stedet for at løse det helt. Og der er stadig nogle problemer her.
For det første er der et fejlpunkt i form af selve den fysiske vært, som alt dette maskineri fungerer på, det er ikke gået nogen vegne.

For det andet er der stadig problemer med SAN'er, deres vanskelige vedligeholdelse forbliver osv. Det var ikke fordi det var en kritisk faktor, men jeg ville prøve at leve uden det på en eller anden måde.
Og vi lavede den tredje version (i det væsentlige den anden, faktisk) - reservationsversionen. Hvordan så det ud?
Dette er hvad det var -

Vores største problemer er, at det er en fysisk vært.
Først og fremmest fjerner vi SAN'er, fordi vi vil eksperimentere, vi vil bare prøve lokale harddiske.

Dette er allerede 2014-2015, og på det tidspunkt blev situationen med diske og deres kapacitet i én vært meget bedre. Vi besluttede, hvorfor ikke give det en chance.
Og så tager vi simpelthen vores backup-partition og flytter den fysisk til en separat maskine.

Således får vi følgende skema. Vi har to biler, der opbevarer de samme datasæt. De bakker hinanden fuldstændig op og synkroniserer data over netværket via en asynkron kø i samme MySQL.

Hvorfor det fungerer godt, er fordi vi har få poster. Dem. hvis skrivningen var sammenlignelig med læsningen, kunne vi få nogle netværksoverhead og problemer. Lidt skrivning, meget læsning - denne metode fungerer godt, dvs. vi kopierer billeder mellem disse to servere ret sjældent.
Hvordan det fungerer, hvis man ser lidt mere detaljeret på det.

Upload. Balanceren vælger simpelthen tilfældige værter med et par og laver en upload til det. Samtidig laver han naturligvis sundhedstjek, og sørger for, at bilen ikke falder ud. Dem. Den uploader kun billeder til en live-server, og gennem en asynkron kø bliver det hele kopieret til sin nabo. Med upload er alt ekstremt enkelt.
Opgaven er lidt mere kompliceret.

Lua hjalp os her, fordi det kan være svært at implementere sådan logik på vanilla NGINX. Først laver vi en anmodning til den første server, se om der er et billede der, fordi det potentielt kan uploades, for eksempel til en nabo, men er ikke ankommet her endnu. Hvis der er et billede der, er det godt. Vi giver det straks til klienten og cacherer det muligvis.

Hvis den ikke er der, laver vi blot en henvendelse til en nabo og modtager den med garanti derfra.

At. igen, vi kan sige: der kan være problemer med ydeevnen på grund af konstante rundrejser - et billede blev uploadet, det er ikke her, vi laver to anmodninger i stedet for én, det skulle fungere langsomt.
I vores situation går det ikke langsomt.

Vi indsamler en masse målinger for dette system, og den betingede hitrate for en sådan mekanisme er omkring 95%. Dem. forsinkelsen af denne backup er lille, og på grund af dette er vi praktisk taget garanteret, efter at billedet er blevet uploadet, at hente det første gang og ikke behøver at gå nogen steder to gange.
Så hvad fik vi ellers, der var rigtig fedt?
Tidligere havde vi primære backup-partitioner, og vi læste fra dem sekventielt. Dem. Vi søgte altid på den primære først og derefter på backup. Det var et træk.
Nu bruger vi læsning fra to maskiner på én gang. Vi distribuerer forespørgsler ved hjælp af Round Robin. I en lille procentdel af tilfældene fremsætter vi to anmodninger. Men samlet set har vi nu dobbelt så meget læsekapacitet, som vi havde før. Og belastningen blev stærkt reduceret både på sendemaskinerne og direkte på lagermaskinerne, som vi også havde dengang.
Angående fejltolerance. Det er faktisk det, vi primært kæmpede for. Med hensyn til fejltolerance fungerede alt godt her.

En bil går i stykker.

Intet problem! En systemingeniør vågner måske ikke engang om natten, han vil vente til morgenen, intet forfærdeligt vil ske.
Selvom køen svigter på grund af fejlen på denne maskine, er der heller ingen problemer, loggen vil blot samle sig først på den levende maskine, og derefter vil den nå køen, og derefter på den maskine, der vil blive sat i drift efter noget tid.

Det samme med vedligeholdelse. Vi slukker simpelthen for en af maskinerne, trækker den manuelt ud af alle pools, dens trafik stopper, vi laver noget vedligeholdelse, reparerer noget der, derefter tager vi den tilbage til service, og denne backup indhenter ret hurtigt. Dem. I løbet af en dag indhentes nedetiden for én bil inden for et par minutter. Det er virkelig for lidt. Hvad angår fejltolerance, gentager jeg, alt er fantastisk her.
Hvilke konklusioner kan der drages af denne ordning med redundans?
Vi opnåede fejltolerance.
Nem at betjene. Da maskinerne har lokale harddiske, er det meget mere bekvemt set ud fra et driftsmæssigt synspunkt for de ingeniører, der arbejder med det.
Vi fik dobbelt læsereserve.
Dette er en meget god bonus ud over fejltolerance.
Men der er også problemer. Nu har vi en meget mere kompleks udvikling af funktioner relateret til dette, fordi systemet efterhånden er blevet 100% konsistent.

Vi skal for eksempel i et eller andet baggrundsjob konstant tænke: "På hvilken server kører vi i øjeblikket?", "Er der virkelig et opdateret billede her?" osv. Det hele er selvfølgelig pakket ind, og for programmøren, der skriver forretningslogikken, er den gennemsigtig. Men ikke desto mindre dukkede dette store komplekse lag op. Men vi er klar til at affinde os med dette til gengæld for de frynsegoder, vi får fra det.
Og her opstår der igen en vis konflikt.
Jeg sagde oprindeligt, at det er dårligt at gemme alt på lokale harddiske. Og nu siger jeg, at vi kunne lide det.
Ja, faktisk har situationen ændret sig meget over tid, og nu har denne tilgang mange fordele. For det første får vi meget enklere betjening.
For det andet er det mere produktivt, fordi vi ikke har disse automatiske controllere, forbindelser til diskhylder.
Der er et kæmpe maskineri der, og det er blot nogle få diske, som er specifikt samlet i et raid her på maskinen.
Men der er også ulemper.

Dette er cirka 1,5 gange dyrere end at bruge SAN'er selv til dagens priser. Derfor besluttede vi ikke at konvertere hele vores store klynge til maskiner med lokale harddiske og besluttede at beholde hybridløsningen.
Halvdelen af vores maskiner arbejder med harddiske (nå, ikke halvdelen - sandsynligvis 30 procent). Og resten er gamle biler, der før havde den første backup-ordning. Vi har lige monteret dem igen, fordi vi ikke har brug for nye data eller noget, vi har bare flyttet monteringerne fra en fysisk vært til to.
Og vi fik et stort lager af læsestof, og vi udvidede det. Hvis vi tidligere har monteret et lager på én maskine, nu monterer vi for eksempel fire på ét par. Og det fungerer fint.
Lad os tage en kort opsummering af, hvad vi har opnået, hvad vi kæmpede for, og om det virkede.
Resultaterne af
Vi har brugere – hele 33 mio.
Vi har tre tilstedeværelsespunkter - Prag, Miami, Hong Kong.
De indeholder et caching-lag, som er en maskine med hurtige lokale diske (SSD), hvorpå simple maskiner fra NGINX, dets access.log og Python-dæmoner, som behandler alt dette og administrerer cachen, fungerer.
Hvis du ønsker, i dit projekt, hvis fotos ikke er lige så kritiske for dig, som de er for os, eller hvis afvejningskontrol er imod udviklingshastigheden og ressourceomkostninger for dig i den anden retning, så kan du nemt erstatte det med et CDN, moderne CDN'er gør dette godt.
Dernæst kommer lagerlaget, hvor vi har klynger af par af maskiner, der sikkerhedskopierer hinanden, og filer kopieres asynkront fra den ene til den anden, når der er en ændring.
Samtidig arbejder nogle af disse maskiner med lokale harddiske.
Nogle af disse maskiner er forbundet til SAN'er.

Og på den ene side er den mere praktisk at bruge og lidt mere produktiv, på den anden side er den praktisk med hensyn til placeringstæthed og pris pr. gigabyte.
Dette er et hurtigt overblik over arkitekturen af, hvad vi fik, og hvordan det hele udviklede sig.
Et par flere tips fra kaptajnen, meget enkle.
For det første, hvis du pludselig beslutter dig for, at du akut skal forbedre alt i din fotoinfrastruktur, så mål det først, for måske skal der ikke forbedres noget.

Lad mig give dig et eksempel. Vi har en klynge af maskiner, der sender billeder fra vedhæftede filer i chats, og ordningen fra 2009 virker der stadig, og ingen lider under det. Alle er glade, alle kan lide alt.
For at måle skal du først lægge en masse metrics op, se på dem og derefter beslutte, hvad du er utilfreds med, hvad der skal forbedres. Til at måle dette har vi et fedt værktøj kaldet Pinba.
Det giver dig mulighed for at indsamle statistik fra NGINX meget detaljeret for hver anmodning og svarkoder og tidsfordeling - hvad end du ønsker. Det har bindinger til alle mulige forskellige analysesystemer, og du kan så se det hele smukt.
Først målte vi, så forbedrede vi os.
Næste. Vi optimerer læsning med cache, skrivning med sharding, men det er en oplagt pointe.

Næste. Hvis du lige er begyndt at bygge dit system, er det meget bedre at tage billeder som uforanderlige filer. For du mister med det samme en hel klasse af problemer med cache-invalidering, med hvordan logikken skal finde den korrekte version af billedet, og så videre.

Lad os sige, at du har uploadet hundrede og derefter roteret det, så det var en fysisk anderledes fil. Dem. ingen grund til at tænke: nu vil jeg spare lidt plads, skrive til den samme fil, ændre versionen. Dette virker altid dårligt og giver en masse hovedpine senere.
Næste punkt. Om at ændre størrelse i farten.
Tidligere, når brugere uploadede et billede, klippede vi en hel masse størrelser på én gang til alle lejligheder, til forskellige klienter, og de ville alle være på disken. Nu har vi opgivet dette.
Vi har kun efterladt tre grundstørrelser: small, medium og large. Alt andet nedskalerer vi bare fra den størrelse, der er bag den, vi blev spurgt om i Uport, vi laver bare nedskaleringen og giver den til brugeren.
CPU'en i cachinglaget her er meget billigere, end hvis vi konstant regenererede disse størrelser på hvert lager. Lad os sige, at vi vil tilføje et nyt, det er et spørgsmål om en måned - at køre et script overalt, der ville gøre alt dette pænt uden at crashe klyngen. Dem. Hvis der er mulighed for at vælge nu, er det bedre at lave så få fysiske størrelser som muligt, men så der i det mindste er en vis fordeling, f.eks. tre. Og alt andet kan nemt ændres på farten ved hjælp af færdige moduler. Det hele er meget nemt og tilgængeligt nu.
Og inkrementel asynkron backup er god.
Som vores praksis har vist, fungerer denne ordning godt med forsinket kopiering af ændrede filer.

Det sidste punkt er også indlysende. Hvis du ikke har disse problemer i din infrastruktur nu, men der er noget, der kan gå i stykker, vil det helt sikkert gå i stykker, når der er lidt mere af det. Derfor er det bedre at tænke over det på forhånd og ikke opleve problemer. Jeg har alt.
Kontakter
»
»
Dette foredrag er et udskrift af en af de bedste foredrag, der blev givet på High Load Systems Developers Conference . Der er mindre end en måned tilbage til HighLoad++ 2017-konferencen.
Vi har den allerede klar , tidsplanen bliver i øjeblikket aktivt dannet.
I år fortsætter vi med at udforske emnet arkitektur og skalering:
- / Igor Vasiliev
- / Dmitry Egorov
- / Anatoly Plaskovsky
- / Roman Shekhovtsov, Alexey Gromatchikov
- / Philippe Delgado
Vi bruger også nogle af disse materialer i vores onlinekursus om udvikling af højbelastningssystemer. — er en kæde af særligt udvalgte breve, artikler, materialer, videoer. Vores lærebog indeholder allerede mere end 30 unikke materialer. Slut dig til os!
Kilde: www.habr.com
