Hoe Yandex.Marketsoektog werk en wat gebeur as een van die bedieners misluk

Hallo, my naam is Evgeniy. Ek werk in die Yandex.Market-soekinfrastruktuur. Ek wil vir die Habr-gemeenskap vertel van die binnekombuis van die Mark – en ek het baie om te vertel. Eerstens, hoe die marksoektog werk, prosesse en argitektuur. Hoe hanteer ons noodsituasies: wat gebeur as een bediener afgaan? Wat as daar 100 sulke bedieners is?

Jy sal ook leer hoe ons nuwe funksionaliteit op 'n klomp bedieners gelyktydig implementeer. En hoe ons komplekse dienste direk in produksie toets, sonder om enige ongerief vir gebruikers te veroorsaak. Oor die algemeen, hoe die marksoektog werk sodat almal 'n goeie tyd het.

Hoe Yandex.Marketsoektog werk en wat gebeur as een van die bedieners misluk

'n Bietjie oor ons: watter probleem ons oplos

Wanneer jy teks invoer, 'n produk volgens parameters soek, of pryse in verskillende winkels vergelyk, word alle versoeke na die soekdiens gestuur. Soek is die grootste diens in die mark.

Ons verwerk alle soekversoeke: vanaf die webwerwe market.yandex.ru, beru.ru, die Supercheck-diens, Yandex.Advisor, mobiele toepassings. Ons sluit ook produkaanbiedinge in soekresultate op yandex.ru in.

Hoe Yandex.Marketsoektog werk en wat gebeur as een van die bedieners misluk

Met soekdiens bedoel ek nie net die soektog self nie, maar ook 'n databasis met al die aanbiedinge op die Mark. Die skaal is so: meer as 'n miljard soekversoeke word per dag verwerk. En alles moet vinnig werk, sonder onderbrekings en altyd die gewenste resultaat lewer.

Wat is wat: markargitektuur

Ek sal kortliks die huidige argitektuur van die Mark beskryf. Dit kan rofweg beskryf word deur die diagram hieronder:
Hoe Yandex.Marketsoektog werk en wat gebeur as een van die bedieners misluk
Kom ons sê 'n vennootwinkel kom na ons toe. Hy sê ek wil 'n speelding verkoop: hierdie bose kat met 'n pieper. En nog 'n kwaai kat sonder 'n pieper. En net 'n kat. Dan moet die winkel aanbiedinge voorberei waarna die Mark soek. Die winkel genereer 'n spesiale xml met aanbiedinge en kommunikeer die pad na hierdie xml deur die geaffilieerde koppelvlak. Die indekseerder laai dan periodiek hierdie xml af, kyk vir foute en stoor al die inligting in 'n groot databasis.

Daar is baie sulke gestoorde xml's. 'n Soek-indeks word uit hierdie databasis geskep. Die indeks word in interne formaat gestoor. Nadat die indeks geskep is, laai die uitlegdiens dit op na soekbedieners.

As gevolg hiervan verskyn 'n kwaai kat met 'n pieper in die databasis, en die kat se indeks verskyn op die bediener.

Ek sal jou vertel hoe ons na 'n kat soek in die deel oor soekargitektuur.

Mark soek argitektuur

Ons leef in 'n wêreld van mikrodienste: elke inkomende versoek market.yandex.ru veroorsaak baie subnavrae, en dosyne dienste is betrokke by die verwerking daarvan. Die diagram toon slegs 'n paar:

Hoe Yandex.Marketsoektog werk en wat gebeur as een van die bedieners misluk
Vereenvoudigde versoekverwerkingskema

Elke diens het 'n wonderlike ding - sy eie balanseerder met 'n unieke naam:

Hoe Yandex.Marketsoektog werk en wat gebeur as een van die bedieners misluk

Die balanseerder gee ons groter buigsaamheid in die bestuur van die diens: jy kan byvoorbeeld bedieners afskakel, wat dikwels nodig is vir opdaterings. Die balanseerder sien dat die bediener nie beskikbaar is nie en herlei versoeke outomaties na ander bedieners of datasentrums. Wanneer 'n bediener bygevoeg of verwyder word, word die vrag outomaties tussen die bedieners herverdeel.

Die unieke naam van die balanseerder hang nie van die datasentrum af nie. Wanneer diens A 'n versoek aan B rig, dan herlei balanseerder B die versoek by verstek na die huidige datasentrum. As die diens nie beskikbaar is nie of nie in die huidige datasentrum bestaan ​​nie, word die versoek na ander datasentrums herlei.

'n Enkele FQDN vir alle datasentrums laat diens A toe om heeltemal van liggings te abstraheer. Sy versoek aan diens B sal altyd verwerk word. Die uitsondering is die geval wanneer die diens in alle datasentrums geleë is.

Maar nie alles is so rooskleurig met hierdie balanseerder nie: ons het 'n bykomende intermediêre komponent. Die balanseerder kan onstabiel wees, en hierdie probleem word opgelos deur oortollige bedieners. Daar is ook 'n bykomende vertraging tussen dienste A en B. Maar in die praktyk is dit minder as 1 ms en vir die meeste dienste is dit nie krities nie.

Hantering van die onverwagte: soekdiensbalansering en veerkragtigheid

Stel jou voor dat daar 'n ineenstorting is: jy moet 'n kat met 'n pieper kry, maar die bediener crash. Of 100 bedieners. Hoe om uit te kom? Gaan ons regtig die gebruiker sonder 'n kat los?

Die situasie is skrikwekkend, maar ons is gereed daarvoor. Ek sal jou in volgorde vertel.

Die soekinfrastruktuur is in verskeie datasentrums geleë:

Hoe Yandex.Marketsoektog werk en wat gebeur as een van die bedieners misluk

By die ontwerp sluit ons die moontlikheid in om een ​​datasentrum te sluit. Die lewe is vol verrassings – ’n graafmasjien kan byvoorbeeld ’n ondergrondse kabel sny (ja, dit het gebeur). Die kapasiteit in die oorblywende datasentrums behoort voldoende te wees om pieklading te weerstaan.

Kom ons oorweeg 'n enkele datasentrum. Elke datasentrum het dieselfde balanseerder-operasieskema:

Hoe Yandex.Marketsoektog werk en wat gebeur as een van die bedieners misluk
Een balanseerder is ten minste drie fisiese bedieners. Hierdie oortolligheid word gemaak vir betroubaarheid. Balanseerders werk op HAProx.

Ons het HAProx gekies weens sy hoë werkverrigting, lae hulpbronvereistes en wye funksionaliteit. Ons soeksagteware loop binne elke bediener.

Die waarskynlikheid dat een bediener misluk, is laag. Maar as jy baie bedieners het, verhoog die waarskynlikheid dat ten minste een sal daal.

Dit is wat in werklikheid gebeur: bedieners crash. Daarom is dit nodig om die status van alle bedieners voortdurend te monitor. As die bediener ophou reageer, word dit outomaties van verkeer ontkoppel. Vir hierdie doel het HAProxy 'n ingeboude gesondheidsondersoek. Dit gaan een keer per sekonde na alle bedieners met 'n HTTP-versoek "/ping".

Nog 'n kenmerk van HAProxy: agent-check laat jou toe om alle bedieners eweredig te laai. Om dit te doen, koppel HAProxy aan alle bedieners, en hulle gee hul gewig terug na gelang van die huidige las van 1 tot 100. Die gewig word bereken op grond van die aantal versoeke in die tou vir verwerking en die las op die verwerker.

Nou oor die vind van die kat. Die soektog lei tot versoeke soos: /soek?teks=kwaad+kat. Vir die soektog om vinnig te wees, moet die hele kat-indeks in RAM pas. Selfs lees vanaf die SSD is nie vinnig genoeg nie.

Eens op 'n tyd was die aanboddatabasis klein, en die RAM van een bediener was genoeg daarvoor. Namate die aanbodbasis gegroei het, pas alles nie meer in hierdie RAM nie, en die data is in twee dele verdeel: skerf 1 en skerf 2.

Hoe Yandex.Marketsoektog werk en wat gebeur as een van die bedieners misluk
Maar dit gebeur altyd: enige oplossing, selfs 'n goeie een, gee aanleiding tot ander probleme.

Die balanseerder het steeds na enige bediener gegaan. Maar op die masjien waar die versoek gekom het, was daar net die helfte van die indeks. Die res was op ander bedieners. Daarom moes die bediener na een of ander naburige masjien gaan. Nadat data vanaf beide bedieners ontvang is, is die resultate gekombineer en herrangskik.

Aangesien die balanseerder versoeke eweredig versprei, was alle bedieners besig met herrangskikking, en nie net om data te stuur nie.

Die probleem het voorgekom as 'n naburige bediener nie beskikbaar was nie. Die oplossing was om verskeie bedieners met verskillende prioriteite as 'n "naburige" bediener te spesifiseer. Eerstens is die versoek na die bedieners in die huidige rek gestuur. As daar geen reaksie was nie, is die versoek na alle bedieners in hierdie datasentrum gestuur. En laastens het die versoek na ander datasentrums gegaan.
Soos die aantal voorstelle gegroei het, is die data in vier dele verdeel. Maar dit was nie die limiet nie.

Tans word 'n konfigurasie van agt skerwe gebruik. Boonop, om nog meer geheue te bespaar, is die indeks verdeel in 'n soekgedeelte (wat vir soek gebruik word) en 'n brokkiegedeelte (wat nie by die soektog betrokke is nie).

Een bediener bevat inligting vir slegs een skerf. Daarom, om die volledige indeks te soek, moet jy op agt bedieners soek wat verskillende skerwe bevat.

Bedieners word in groepe gegroepeer. Elke groepering bevat agt soekenjins en een brokkiebediener.

Hoe Yandex.Marketsoektog werk en wat gebeur as een van die bedieners misluk
Die brokkiebediener bestuur 'n sleutelwaarde-databasis met statiese data. Hulle is nodig om dokumente uit te reik, byvoorbeeld 'n beskrywing van 'n kat met 'n pieper. Die data word spesiaal na 'n aparte bediener oorgedra om nie die geheue van soekbedieners te laai nie.

Aangesien dokument-ID's slegs binne een indeks uniek is, kan 'n situasie ontstaan ​​waar daar geen dokumente in die brokkies is nie. Wel, of dat daar vir een ID verskillende inhoud sal wees. Daarom was daar 'n behoefte aan konsekwentheid oor die hele groepering om die soektog te laat werk en resultate te lewer. Ek sal jou hieronder vertel hoe ons konsekwentheid monitor.

Die soektog self is soos volg gestruktureer: 'n soekversoek kan na enige van die agt bedieners kom. Kom ons sê hy het na bediener 1 gekom. Hierdie bediener verwerk al die argumente en verstaan ​​waarna en hoe om te soek. Afhangende van die inkomende versoek, kan die bediener addisionele versoeke aan eksterne dienste rig vir die nodige inligting. Een versoek kan gevolg word deur tot tien versoeke aan eksterne dienste.

Nadat die nodige inligting ingesamel is, begin 'n soektog in die aanboddatabasis. Om dit te doen, word subnavrae aan al agt bedieners in die groepering gedoen.

Sodra die antwoorde ontvang is, word die resultate gekombineer. Op die ou end kan nog verskeie subnavrae na die brokkiebediener nodig wees om die resultate te genereer.

Soeknavrae binne die groepie lyk soos volg: /shard1?text=kwaad+kat. Boonop word subnavrae van die vorm voortdurend een keer per sekonde tussen alle bedieners binne die groepering gemaak: /status.

Navraag /status bespeur 'n situasie waar die bediener nie beskikbaar is nie.

Dit beheer ook dat die soekenjinweergawe en die indeksweergawe dieselfde is op alle bedieners, anders sal daar inkonsekwente data binne die groep wees.

Ten spyte van die feit dat een brokkiebediener versoeke van agt soekenjins verwerk, is die verwerker daarvan baie lig gelaai. Daarom dra ons nou die brokkiedata oor na 'n aparte diens.

Hoe Yandex.Marketsoektog werk en wat gebeur as een van die bedieners misluk

Om data oor te dra, het ons universele sleutels vir dokumente ingestel. Nou is dit onmoontlik vir 'n situasie waar inhoud van 'n ander dokument met een sleutel teruggestuur word.

Maar die oorgang na 'n ander argitektuur is nog nie voltooi nie. Nou wil ons ontslae raak van die toegewyde brokkiebediener. En beweeg dan heeltemal weg van die trosstruktuur. Dit sal ons toelaat om voort te gaan om maklik te skaal. 'n Bykomende bonus is aansienlike ysterbesparings.

En nou na skrikwekkende stories met gelukkige eindes. Kom ons kyk na verskeie gevalle van onbeskikbaarheid van die bediener.

Iets verskrikliks het gebeur: een bediener is nie beskikbaar nie

Kom ons sê een bediener is nie beskikbaar nie. Dan kan die oorblywende bedieners in die groep aanhou reageer, maar die soekresultate sal onvolledig wees.

Via statuskontrole /status naburige bedieners verstaan ​​dat een nie beskikbaar is nie. Daarom, om volledigheid te handhaaf, alle bedieners in die groep per versoek /ping hulle begin op die balanseerder reageer dat hulle ook nie beskikbaar is nie. Dit blyk dat al die bedieners in die groep dood is (wat nie waar is nie). Dit is die grootste nadeel van ons klusterskema - daarom wil ons daarvan wegkom.

Hoe Yandex.Marketsoektog werk en wat gebeur as een van die bedieners misluk

Versoeke wat misluk met 'n fout, word weer deur die balanseerder op ander bedieners gestuur.
Die balanseerder hou ook op om gebruikersverkeer na dooie bedieners te stuur, maar gaan voort om hul status na te gaan.

Wanneer die bediener beskikbaar word, begin dit daarop reageer /ping. Sodra normale reaksies op pings van dooie bedieners begin opdaag, begin balanseerders gebruikersverkeer daarheen stuur. Cluster werking is herstel, hoera.

Nog erger: baie bedieners is nie beskikbaar nie

'n Beduidende deel van die bedieners in die datasentrum word afgesny. Wat om te doen, waarheen om te hardloop? Die balanseerder kom weer tot die redding. Elke balanseerder stoor voortdurend die huidige aantal lewendige bedieners in die geheue. Dit bereken voortdurend die maksimum hoeveelheid verkeer wat die huidige datasentrum kan verwerk.

Wanneer baie bedieners in 'n datasentrum afgaan, besef die balanseerder dat hierdie datasentrum nie al die verkeer kan verwerk nie.

Dan begin die oortollige verkeer lukraak na ander datasentrums versprei word. Alles werk, almal is gelukkig.

Hoe Yandex.Marketsoektog werk en wat gebeur as een van die bedieners misluk

Hoe ons dit doen: publiseer vrystellings

Kom ons praat nou oor hoe ons veranderinge wat aan die diens gemaak is, publiseer. Hier het ons die pad geneem om prosesse te vereenvoudig: die uitrol van 'n nuwe vrystelling is amper heeltemal outomaties.
Wanneer 'n sekere aantal veranderinge in die projek opgehoop word, word 'n nuwe vrystelling outomaties geskep en die bou daarvan begin.

Hoe Yandex.Marketsoektog werk en wat gebeur as een van die bedieners misluk

Dan word die diens uitgerol na toetsing, waar die stabiliteit van werking nagegaan word.

Terselfdertyd word outomatiese prestasietoetsing van stapel gestuur. Dit word deur 'n spesiale diens hanteer. Ek sal nie nou daaroor praat nie - die beskrywing daarvan is 'n aparte artikel werd.

As publikasie in toetsing suksesvol is, word publikasie van die vrystelling in prestable outomaties begin. Prestable is 'n spesiale groep waarheen normale gebruikersverkeer gerig word. As dit 'n fout terugstuur, doen die balanseerder 'n herversoek na produksie.

In prestable word reaksietye gemeet en vergelyk met die vorige vrystelling in produksie. As alles reg is, dan verbind 'n persoon: kontroleer die grafieke en resultate van lastoetsing en begin dan na produksie uitrol.

Alles van die beste gaan aan die gebruiker: A/B-toetsing

Dit is nie altyd voor die hand liggend of veranderinge aan 'n diens werklike voordele inhou nie. Om die nut van veranderinge te meet, het mense met A/B-toetsing vorendag gekom. Ek sal jou 'n bietjie vertel oor hoe dit werk in Yandex.Marketsoektog.

Dit begin alles met die byvoeging van 'n nuwe CGI-parameter wat nuwe funksionaliteit moontlik maak. Laat ons parameter wees: mark_nuwe_funksionaliteit=1. Dan aktiveer ons in die kode hierdie funksionaliteit as die vlag teenwoordig is:

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

Nuwe funksionaliteit word na produksie uitgerol.

Om A/B-toetsing te outomatiseer, is daar 'n toegewyde diens wat gedetailleerde inligting verskaf hier beskryf. 'n Eksperiment word in die diens geskep. Die verkeersaandeel word byvoorbeeld gestel op 15%. Persentasies word nie vir navrae gestel nie, maar vir gebruikers. Die duur van die eksperiment word ook aangedui, byvoorbeeld 'n week.

Verskeie eksperimente kan gelyktydig uitgevoer word. In die instellings kan jy spesifiseer of kruising met ander eksperimente moontlik is.

As gevolg hiervan voeg die diens outomaties 'n argument by mark_nuwe_funksionaliteit=1 tot 15% van gebruikers. Dit bereken ook outomaties die geselekteerde maatstawwe. Nadat die eksperiment voltooi is, kyk ontleders na die resultate en maak gevolgtrekkings. Op grond van die bevindinge word 'n besluit geneem om na produksie of verfyning uit te rol.

Mark se behendige hand: toets in produksie

Dit gebeur dikwels dat jy die werking van 'n nuwe funksionaliteit in produksie moet toets, maar jy is nie seker hoe dit in "geveg" toestande onder swaar vrag sal optree nie.

Daar is 'n oplossing: vlae in CGI-parameters kan nie net vir A/B-toetsing gebruik word nie, maar ook om nuwe funksionaliteit te toets.

Ons het 'n instrument gemaak waarmee u konfigurasie onmiddellik op duisende bedieners kan verander sonder om die diens aan risiko's bloot te stel. Dit word Stop Tap genoem. Die oorspronklike idee was om sekere funksies vinnig te kan deaktiveer sonder 'n uitleg. Toe het die instrument uitgebrei en meer kompleks geword.

Die diensvloeidiagram word hieronder aangebied:

Hoe Yandex.Marketsoektog werk en wat gebeur as een van die bedieners misluk

Vlagwaardes word via die API gestel. Die bestuursdiens stoor hierdie waardes in die databasis. Alle bedieners gaan een keer elke tien sekondes na die databasis, pomp vlagwaardes uit en pas hierdie waardes toe op elke versoek.

In die Stop kraan kan jy twee tipes waardes stel:

1) Voorwaardelike uitdrukkings. Dien toe wanneer een van die waardes waar is. Byvoorbeeld:

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

Die waarde "3" sal toegepas word wanneer die versoek in ligging DC1 verwerk word. En die waarde is "4" wanneer die versoek op die tweede groep vir die beru.ru-werf verwerk word.

2) Onvoorwaardelike waardes. Dien by verstek toe as geen van die voorwaardes nagekom word nie. Byvoorbeeld:

waarde, waarde!

As 'n waarde met 'n uitroepteken eindig, word dit hoër prioriteit gegee.

Die CGI-parameter-ontleder ontleed die URL. Pas dan die waardes van die Stop Tap toe.

Waardes met die volgende prioriteite word toegepas:

  1. Met verhoogde prioriteit van die Stop Tap (uitroepteken).
  2. Die waarde van die versoek.
  3. Verstekwaarde van Stop kraan.
  4. Verstekwaarde in kode.

Daar is baie vlae wat in voorwaardelike waardes aangedui word - dit is genoeg vir alle scenario's wat aan ons bekend is:

  • Data sentrum.
  • Omgewing: produksie, toetsing, skaduwee.
  • Plek: mark, beru.
  • Groep nommer.

Met hierdie hulpmiddel kan u nuwe funksionaliteit op 'n sekere groep bedieners aktiveer (byvoorbeeld in slegs een datasentrum) en die werking van hierdie funksionaliteit toets sonder enige spesifieke risiko vir die hele diens. Selfs as jy iewers 'n ernstige fout gemaak het, het alles begin val en die hele datasentrum het afgegaan, sal balanseerders versoeke na ander datasentrums herlei. Eindgebruikers sal niks agterkom nie.

As jy 'n probleem opmerk, kan jy die vlag onmiddellik na sy vorige waarde terugstuur en die veranderinge sal teruggerol word.

Hierdie diens het ook sy nadele: die ontwikkelaars is baie lief daarvoor en probeer dikwels al die veranderinge in die Stop Tap druk. Ons probeer misbruik bekamp.

Die Stop Tap-benadering werk goed wanneer jy reeds stabiele kode gereed het om na produksie uitgerol te word. Terselfdertyd het jy steeds twyfel, en jy wil die kode in "geveg" toestande nagaan.

Stop Tap is egter nie geskik vir toetsing tydens ontwikkeling nie. Daar is 'n aparte groepering vir ontwikkelaars wat die "skadukluster" genoem word.

Geheime toets: Shadow Cluster

Versoeke van een van die trosse word na die skadu-kluster gedupliseer. Maar die balanseerder ignoreer die antwoorde van hierdie groep heeltemal. Die diagram van die werking daarvan word hieronder aangebied.

Hoe Yandex.Marketsoektog werk en wat gebeur as een van die bedieners misluk

Ons kry 'n toetsgroep wat in werklike "geveg" toestande is. Normale gebruikersverkeer gaan daarheen. Die hardeware in beide groepe is dieselfde, so werkverrigting en foute kan vergelyk word.

En aangesien die balanseerder antwoorde heeltemal ignoreer, sal eindgebruikers nie antwoorde van die skadu-groepering sien nie. Daarom is dit nie skrikwekkend om 'n fout te maak nie.

Bevindinge

So, hoe het ons die marksoektog gebou?

Om alles glad te laat verloop, skei ons funksionaliteit in aparte dienste. Op hierdie manier kan ons net die komponente wat ons benodig skaal en die komponente eenvoudiger maak. Dit is maklik om 'n aparte komponent aan 'n ander span toe te wys en die verantwoordelikhede om daaraan te werk te deel. En aansienlike besparings in yster met hierdie benadering is 'n ooglopende pluspunt.

Die skadu-kluster help ons ook: ons kan dienste ontwikkel, dit in die proses toets en nie die gebruiker steur nie.

Wel, toets in produksie, natuurlik. Moet u konfigurasie op duisende bedieners verander? Maklik, gebruik die Stop Tap. Op hierdie manier kan jy dadelik 'n klaargemaakte komplekse oplossing uitrol en terugrol na 'n stabiele weergawe as probleme opduik.

Ek hoop ek kon wys hoe ons die mark vinnig en stabiel maak met 'n steeds groeiende basis van aanbiedinge. Hoe ons bedienerprobleme oplos, 'n groot aantal versoeke hanteer, die buigsaamheid van die diens verbeter en dit doen sonder om werkprosesse te onderbreek.

Bron: will.com

Voeg 'n opmerking