Hvordan Yandex.Market-søgning fungerer, og hvad sker der, hvis en af ​​serverne fejler

Hej, mit navn er Evgeniy. Jeg arbejder i Yandex.Market-søgningsinfrastrukturen. Jeg vil fortælle Habr-samfundet om Markedets indre køkken – og jeg har meget at fortælle. Først og fremmest, hvordan markedssøgningen fungerer, processer og arkitektur. Hvordan håndterer vi nødsituationer: hvad sker der, hvis en server går ned? Hvad hvis der er 100 sådanne servere?

Du vil også lære, hvordan vi implementerer ny funktionalitet på en masse servere på én gang. Og hvordan vi tester komplekse tjenester direkte i produktionen, uden at det forårsager nogen gener for brugerne. Generelt hvordan markedssøgningen fungerer, så alle har det godt.

Hvordan Yandex.Market-søgning fungerer, og hvad sker der, hvis en af ​​serverne fejler

Lidt om os: Hvilket problem løser vi

Når du indtaster tekst, søger efter et produkt efter parametre eller sammenligner priser i forskellige butikker, sendes alle forespørgsler til søgetjenesten. Søgning er den største tjeneste på markedet.

Vi behandler alle søgeanmodninger: fra webstederne market.yandex.ru, beru.ru, Supercheck-tjenesten, Yandex.Advisor, mobilapplikationer. Vi inkluderer også produkttilbud i søgeresultaterne på yandex.ru.

Hvordan Yandex.Market-søgning fungerer, og hvad sker der, hvis en af ​​serverne fejler

Med søgetjeneste mener jeg ikke kun selve søgningen, men også en database med alle tilbud på Markedet. Skalaen er denne: mere end en milliard søgeanmodninger behandles om dagen. Og alt skal fungere hurtigt, uden afbrydelser og altid give det ønskede resultat.

Hvad er hvad: Markedsarkitektur

Jeg vil kort beskrive Markedets nuværende arkitektur. Det kan groft beskrives af nedenstående diagram:
Hvordan Yandex.Market-søgning fungerer, og hvad sker der, hvis en af ​​serverne fejler
Lad os sige, at en partnerbutik kommer til os. Han siger, at jeg vil sælge et legetøj: denne onde kat med en knirker. Og endnu en sur kat uden en knirker. Og bare en kat. Så skal butikken udarbejde tilbud, som Markedet søger efter. Butikken genererer en speciel xml med tilbud og kommunikerer stien til denne xml gennem affiliate-grænsefladen. Indekseringsprogrammet downloader derefter med jævne mellemrum denne xml, kontrollerer for fejl og gemmer alle oplysningerne i en enorm database.

Der er mange sådanne gemte xml'er. Et søgeindeks oprettes fra denne database. Indekset gemmes i internt format. Efter oprettelse af indekset uploader Layout-tjenesten det til søgeservere.

Som følge heraf vises en vred kat med en squeaker i databasen, og kattens indeks vises på serveren.

Jeg vil fortælle dig, hvordan vi søger efter en kat i delen om søgearkitektur.

Markedssøgningsarkitektur

Vi lever i en verden af ​​mikrotjenester: hver indkommende anmodning market.yandex.ru forårsager en masse underforespørgsler, og snesevis af tjenester er involveret i deres behandling. Diagrammet viser kun nogle få:

Hvordan Yandex.Market-søgning fungerer, og hvad sker der, hvis en af ​​serverne fejler
Forenklet anmodningsbehandlingsskema

Hver tjeneste har en vidunderlig ting - sin egen balancer med et unikt navn:

Hvordan Yandex.Market-søgning fungerer, og hvad sker der, hvis en af ​​serverne fejler

Balanceren giver os større fleksibilitet i håndteringen af ​​tjenesten: Du kan for eksempel slukke for servere, hvilket ofte er nødvendigt for opdateringer. Balanceren ser, at serveren ikke er tilgængelig og omdirigerer automatisk anmodninger til andre servere eller datacentre. Når du tilføjer eller fjerner en server, omfordeles belastningen automatisk mellem serverne.

Balancerens unikke navn afhænger ikke af datacentret. Når tjeneste A sender en anmodning til B, omdirigerer balancer B som standard anmodningen til det aktuelle datacenter. Hvis tjenesten ikke er tilgængelig eller ikke findes i det aktuelle datacenter, omdirigeres anmodningen til andre datacentre.

Et enkelt FQDN for alle datacentre gør det muligt for tjeneste A at abstrahere fuldstændigt fra lokationer. Hans anmodning til service B vil altid blive behandlet. Undtagelsen er tilfældet, når tjenesten er placeret i alle datacentre.

Men ikke alt er så rosenrødt med denne balancer: Vi har en ekstra mellemkomponent. Balanceren kan være ustabil, og dette problem løses af redundante servere. Der er også en ekstra forsinkelse mellem tjenester A og B. Men i praksis er den mindre end 1 ms, og for de fleste tjenester er dette ikke kritisk.

Håndtering af det uventede: Balancering af søgetjeneste og modstandsdygtighed

Forestil dig, at der er et sammenbrud: du skal finde en kat med en squeaker, men serveren går ned. Eller 100 servere. Hvordan kommer man ud? Skal vi virkelig efterlade brugeren uden kat?

Situationen er skræmmende, men vi er klar til det. Jeg fortæller dig det i rækkefølge.

Søgeinfrastrukturen er placeret i flere datacentre:

Hvordan Yandex.Market-søgning fungerer, og hvad sker der, hvis en af ​​serverne fejler

Ved design inkluderer vi muligheden for at lukke ét datacenter ned. Livet er fyldt med overraskelser – for eksempel kan en gravemaskine skære et jordkabel over (ja, det skete). Kapaciteten i de resterende datacentre bør være tilstrækkelig til at modstå spidsbelastning.

Lad os overveje et enkelt datacenter. Hvert datacenter har det samme balancer-driftskema:

Hvordan Yandex.Market-søgning fungerer, og hvad sker der, hvis en af ​​serverne fejler
En balancer er mindst tre fysiske servere. Denne redundans er lavet for pålidelighed. Balancere kører på HAProx.

Vi valgte HAProx på grund af dets høje ydeevne, lave ressourcekrav og brede funktionalitet. Vores søgesoftware kører inde på hver server.

Sandsynligheden for, at én server fejler, er lav. Men hvis du har mange servere, øges sandsynligheden for, at mindst én går ned.

Dette er, hvad der sker i virkeligheden: servere går ned. Derfor er det nødvendigt konstant at overvåge status på alle servere. Hvis serveren holder op med at reagere, afbrydes den automatisk fra trafik. Til dette formål har HAProxy et indbygget sundhedstjek. Det går til alle servere en gang i sekundet med en HTTP-anmodning "/ping".

En anden funktion ved HAProxy: agent-check giver dig mulighed for at indlæse alle servere jævnt. For at gøre dette forbinder HAProxy til alle servere, og de returnerer deres vægt afhængig af den aktuelle belastning fra 1 til 100. Vægten beregnes ud fra antallet af anmodninger i køen til behandling og belastningen på processoren.

Nu om at finde katten. Søgningen resulterer i anmodninger som: /search?text=vred+kat. For at søgningen skal være hurtig, skal hele katteindekset passe ind i RAM. Selv læsning fra SSD'en er ikke hurtig nok.

Engang var tilbudsdatabasen lille, og RAM på én server var nok til det. Efterhånden som tilbudsbasen voksede, passede alt ikke længere ind i denne RAM, og dataene blev opdelt i to dele: shard 1 og shard 2.

Hvordan Yandex.Market-søgning fungerer, og hvad sker der, hvis en af ​​serverne fejler
Men dette sker altid: Enhver løsning, selv en god, giver anledning til andre problemer.

Balanceren gik stadig til enhver server. Men på maskinen, hvor anmodningen kom, var der kun halvdelen af ​​indekset. Resten var på andre servere. Derfor måtte serveren gå til en eller anden nabomaskine. Efter at have modtaget data fra begge servere, blev resultaterne kombineret og omplaceret.

Da balanceren fordeler anmodninger jævnt, var alle servere involveret i omrangering og ikke kun at sende data.

Problemet opstod, hvis en tilstødende server ikke var tilgængelig. Løsningen var at specificere flere servere med forskellige prioriteter som en "nabo"-server. Først blev anmodningen sendt til serverne i det aktuelle rack. Hvis der ikke var noget svar, blev anmodningen sendt til alle servere i dette datacenter. Og til sidst gik anmodningen til andre datacentre.
Efterhånden som antallet af forslag voksede, blev dataene opdelt i fire dele. Men dette var ikke grænsen.

I øjeblikket bruges en konfiguration på otte shards. For at spare endnu mere hukommelse blev indekset opdelt i en søgedel (som bruges til søgning) og en uddragsdel (som ikke er involveret i søgningen).

Én server indeholder information om kun én shard. Derfor, for at søge i det fulde indeks, skal du søge på otte servere, der indeholder forskellige shards.

Servere er grupperet i klynger. Hver klynge indeholder otte søgemaskiner og en snippet-server.

Hvordan Yandex.Market-søgning fungerer, og hvad sker der, hvis en af ​​serverne fejler
Snippet-serveren kører en nøgleværdi-database med statiske data. De er nødvendige for at udstede dokumenter, for eksempel en beskrivelse af en kat med en squeaker. Dataene overføres specielt til en separat server for ikke at indlæse søgeservernes hukommelse.

Da dokument-id'er kun er unikke inden for ét indeks, kan der opstå en situation, hvor der ikke er dokumenter i uddragene. Nå, eller at der for ét ID vil være forskelligt indhold. Derfor var der behov for konsistens på tværs af hele klyngen, for at søgningen kunne fungere og resultaterne kunne returneres. Jeg fortæller dig nedenfor, hvordan vi overvåger konsistens.

Selve søgningen er struktureret som følger: en søgeanmodning kan komme til enhver af de otte servere. Lad os sige, at han kom til server 1. Denne server behandler alle argumenterne og forstår, hvad og hvordan man skal lede efter. Afhængigt af den indkommende anmodning kan serveren foretage yderligere anmodninger til eksterne tjenester om de nødvendige oplysninger. En anmodning kan efterfølges af op til ti anmodninger til eksterne tjenester.

Efter at have indsamlet de nødvendige oplysninger, begynder en søgning i tilbudsdatabasen. For at gøre dette foretages underforespørgsler til alle otte servere i klyngen.

Når svarene er modtaget, kombineres resultaterne. I sidste ende kan der være behov for flere underforespørgsler til snippet-serveren for at generere resultaterne.

Søgeforespørgsler i klyngen ser sådan ud: /shard1?text=vred+kat. Derudover laves der konstant underforespørgsler til formularen mellem alle servere i klyngen én gang i sekundet: /status.

Forespørgsel /status registrerer en situation, hvor serveren ikke er tilgængelig.

Den kontrollerer også, at søgemaskineversionen og indeksversionen er ens på alle servere, ellers vil der være inkonsistente data i klyngen.

På trods af at en snippet-server behandler anmodninger fra otte søgemaskiner, er dens processor meget let belastet. Derfor overfører vi nu snippet-dataene til en separat tjeneste.

Hvordan Yandex.Market-søgning fungerer, og hvad sker der, hvis en af ​​serverne fejler

For at overføre data introducerede vi universelle nøgler til dokumenter. Nu er det umuligt i en situation, hvor indhold fra et andet dokument returneres med én nøgle.

Men overgangen til en anden arkitektur er ikke afsluttet endnu. Nu vil vi slippe af med den dedikerede snippet-server. Og så gå helt væk fra klyngestrukturen. Dette vil give os mulighed for at fortsætte med at skalere let. En ekstra bonus er betydelige jernbesparelser.

Og nu til skræmmende historier med lykkelige slutninger. Lad os overveje flere tilfælde af server utilgængelighed.

Der skete noget forfærdeligt: ​​én server er ikke tilgængelig

Lad os sige, at en server ikke er tilgængelig. Så kan de resterende servere i klyngen fortsætte med at svare, men søgeresultaterne vil være ufuldstændige.

Via statustjek /status naboservere forstår, at en ikke er tilgængelig. Derfor, for at opretholde fuldstændigheden, skal alle servere i klyngen pr. anmodning /ping de begynder at svare balanceren, at de også er utilgængelige. Det viser sig, at alle serverne i klyngen døde (hvilket ikke er sandt). Dette er den største ulempe ved vores klyngeordning - det er derfor, vi vil væk fra det.

Hvordan Yandex.Market-søgning fungerer, og hvad sker der, hvis en af ​​serverne fejler

Forespørgsler, der mislykkes med en fejl, sendes igen af ​​balanceren på andre servere.
Balanceren holder også op med at sende brugertrafik til døde servere, men fortsætter med at kontrollere deres status.

Når serveren bliver tilgængelig, begynder den at reagere på /ping. Så snart normale svar på ping fra døde servere begynder at ankomme, begynder balancere at sende brugertrafik dertil. Klyngedrift er genoprettet, hurra.

Endnu værre: mange servere er ikke tilgængelige

En væsentlig del af serverne i datacentret er skåret ned. Hvad skal man gøre, hvor skal man løbe? Balanceren kommer igen til undsætning. Hver balancer gemmer konstant det aktuelle antal live-servere i hukommelsen. Den beregner konstant den maksimale mængde trafik, som det nuværende datacenter kan behandle.

Når mange servere i et datacenter går ned, indser balanceren, at dette datacenter ikke kan behandle al trafikken.

Så begynder den overskydende trafik at blive tilfældigt fordelt til andre datacentre. Alt fungerer, alle er glade.

Hvordan Yandex.Market-søgning fungerer, og hvad sker der, hvis en af ​​serverne fejler

Sådan gør vi det: udgivelse af udgivelser

Lad os nu tale om, hvordan vi offentliggør ændringer foretaget i tjenesten. Her har vi taget vejen for at forenkle processer: udrulning af en ny udgivelse er næsten fuldstændig automatiseret.
Når et vist antal ændringer er akkumuleret i projektet, oprettes der automatisk en ny udgivelse, og dens build starter.

Hvordan Yandex.Market-søgning fungerer, og hvad sker der, hvis en af ​​serverne fejler

Derefter rulles tjenesten ud til test, hvor driftsstabiliteten kontrolleres.

Samtidig lanceres automatisk præstationstest. Dette varetages af en særlig service. Jeg vil ikke tale om det nu - dens beskrivelse er værdig til en separat artikel.

Hvis udgivelsen i test lykkes, startes udgivelsen af ​​udgivelsen i prestable automatisk. Prestable er en speciel klynge, hvor normal brugertrafik dirigeres. Hvis den returnerer en fejl, sender balanceren en genanmodning til produktion.

I prestable måles responstider og sammenlignes med den tidligere udgivelse i produktionen. Hvis alt er i orden, forbinder en person: kontrollerer graferne og resultaterne af belastningstest og begynder derefter at rulle ud til produktion.

Alt det bedste går til brugeren: A/B-test

Det er ikke altid indlysende, om ændringer af en service vil give reelle fordele. For at måle nytten af ​​ændringer kom folk med A/B-test. Jeg vil fortælle dig lidt om, hvordan det virker i Yandex.Market-søgning.

Det hele starter med at tilføje en ny CGI-parameter, der muliggør ny funktionalitet. Lad vores parameter være: market_new_functionality=1. Så i koden aktiverer vi denne funktionalitet, hvis flaget er til stede:

If (cgi.experiments.market_new_functionality) {
// enable new functionality
}

Ny funktionalitet er ved at blive udrullet til produktion.

For at automatisere A/B-test er der en dedikeret tjeneste, der giver detaljerede oplysninger beskrevet her. Der oprettes et eksperiment i tjenesten. Trafikandelen sættes fx til 15 %. Procentsatser angives ikke for forespørgsler, men for brugere. Forsøgets varighed er også angivet, for eksempel en uge.

Flere eksperimenter kan køres samtidigt. I indstillingerne kan du angive, om krydsning med andre eksperimenter er mulig.

Som et resultat tilføjer tjenesten automatisk et argument market_new_functionality=1 til 15 % af brugerne. Den beregner også automatisk de valgte metrics. Efter eksperimentet er afsluttet, ser analytikere på resultaterne og drager konklusioner. På baggrund af resultaterne træffes der en beslutning om at rulle ud til produktion eller forædling.

Markedets behændige hånd: test i produktionen

Det sker ofte, at du skal teste driften af ​​en ny funktionalitet i produktionen, men du er ikke sikker på, hvordan den vil opføre sig under "kamp"-forhold under tung belastning.

Der er en løsning: flag i CGI-parametre kan bruges ikke kun til A/B-test, men også til at teste ny funktionalitet.

Vi har lavet et værktøj, der giver dig mulighed for øjeblikkeligt at ændre konfiguration på tusindvis af servere uden at udsætte tjenesten for risici. Det hedder "Stop Tap". Den oprindelige idé var hurtigt at kunne deaktivere noget funktionalitet uden et layout. Så udvidede værktøjet sig og blev mere komplekst.

Serviceflowdiagrammet er præsenteret nedenfor:

Hvordan Yandex.Market-søgning fungerer, og hvad sker der, hvis en af ​​serverne fejler

Flagværdier indstilles via API'et. Administrationstjenesten gemmer disse værdier i databasen. Alle servere går til databasen en gang hvert tiende sekund, pumper flagværdier ud og anvender disse værdier på hver anmodning.

I Stop tap kan du indstille to typer værdier:

1) Betingede udtryk. Anvend, når en af ​​værdierne er sand. For eksempel:

{
	"condition":"IS_DC1",
	"value":"3",
}, 
{
	"condition": "CLUSTER==2 and IS_BERU", 
	"value": "4!" 
}

Værdien "3" vil blive anvendt, når anmodningen behandles på lokation DC1. Og værdien er "4", når anmodningen behandles på den anden klynge for webstedet beru.ru.

2) Ubetingede værdier. Anvend som standard, hvis ingen af ​​betingelserne er opfyldt. For eksempel:

værdi, værdi!

Hvis en værdi ender med et udråbstegn, prioriteres den højere.

CGI-parameterparseren analyserer URL'en. Anvender derefter værdierne fra Stop Tap.

Værdier med følgende prioriteter anvendes:

  1. Med øget prioritet fra Stop Tap (udråbstegn).
  2. Værdi fra forespørgsel.
  3. Standardværdi fra Stop tap.
  4. Standardværdi i kode.

Der er mange flag, der er angivet i betingede værdier - de er nok til alle scenarier, vi kender:

  • Datacenter.
  • Miljø: produktion, test, skygge.
  • Mødested: marked, beru.
  • Klyngenummer.

Med dette værktøj kan du aktivere ny funktionalitet på en bestemt gruppe af servere (for eksempel i kun ét datacenter) og teste driften af ​​denne funktionalitet uden nogen særlig risiko for hele tjenesten. Selvom du lavede en alvorlig fejl et eller andet sted, begyndte alt at falde, og hele datacentret gik ned, balancerer vil omdirigere anmodninger til andre datacentre. Slutbrugere vil ikke bemærke noget.

Hvis du bemærker et problem, kan du øjeblikkeligt returnere flaget til dets tidligere værdi, og ændringerne vil blive rullet tilbage.

Denne tjeneste har også sine ulemper: udviklerne elsker den meget og forsøger ofte at skubbe alle ændringerne ind i Stop Tap. Vi forsøger at bekæmpe misbrug.

Stop Tap-tilgangen fungerer godt, når du allerede har stabil kode klar til at blive rullet ud til produktion. Samtidig er du stadig i tvivl, og du vil tjekke koden under "kamp"-forhold.

Stop Tap er dog ikke egnet til test under udvikling. Der er en separat klynge for udviklere kaldet "skyggeklyngen".

Hemmelig test: Shadow Cluster

Anmodninger fra en af ​​klyngerne duplikeres til skyggeklyngen. Men balanceren ignorerer fuldstændigt svarene fra denne klynge. Diagrammet over dets drift er præsenteret nedenfor.

Hvordan Yandex.Market-søgning fungerer, og hvad sker der, hvis en af ​​serverne fejler

Vi får en testklynge, der er i rigtige "kamp"-forhold. Normal brugertrafik går dertil. Hardwaren i begge klynger er den samme, så ydeevne og fejl kan sammenlignes.

Og da balanceren fuldstændig ignorerer svar, vil slutbrugere ikke se svar fra skyggeklyngen. Derfor er det ikke skræmmende at lave en fejl.

Fund

Så hvordan byggede vi markedssøgningen?

For at få alt til at gå glat, opdeler vi funktionalitet i separate tjenester. På denne måde kan vi kun skalere de komponenter, vi har brug for, og gøre komponenterne enklere. Det er nemt at tildele en separat komponent til et andet team og dele ansvaret for at arbejde på det. Og betydelige besparelser i jern med denne tilgang er et indlysende plus.

Skyggeklyngen hjælper os også: Vi kan udvikle tjenester, teste dem i processen og ikke forstyrre brugeren.

Nå, test i produktion, selvfølgelig. Skal du ændre konfigurationen på tusindvis af servere? Nemt, brug Stop Tap. På denne måde kan du med det samme rulle en færdiglavet kompleks løsning ud og rulle tilbage til en stabil version, hvis der opstår problemer.

Jeg håber, jeg var i stand til at vise, hvordan vi gør markedet hurtigt og stabilt med en stadigt voksende base af tilbud. Hvordan vi løser serverproblemer, håndterer et stort antal forespørgsler, forbedrer tjenestens fleksibilitet og gør dette uden at afbryde arbejdsprocesser.

Kilde: www.habr.com

Tilføj en kommentar