Kako je spletna arhitektura, odporna na napake, implementirana v platformo Mail.ru Cloud Solutions

Kako je spletna arhitektura, odporna na napake, implementirana v platformo Mail.ru Cloud Solutions

Pozdravljeni, Habr! Sem Artem Karamyshev, vodja ekipe za sistemsko administracijo Mail.Ru Cloud Solutions (MCS). V preteklem letu smo lansirali veliko novih izdelkov. Želeli smo zagotoviti, da so storitve API enostavno razširljive, odporne na napake in pripravljene na hitro rast obremenitve uporabnikov. Naša platforma je implementirana na OpenStacku in želim vam povedati, katere težave s toleranco napak komponent smo morali rešiti, da smo dobili sistem, toleranten na napake. Mislim, da bo to zanimivo za tiste, ki razvijajo tudi izdelke na OpenStacku.

Celotna odpornost na napake platforme je sestavljena iz odpornosti njenih komponent. Tako bomo postopoma šli skozi vse nivoje, kjer smo prepoznali tveganja in jih zaprli.

Video različica te zgodbe, katere glavni vir je bilo poročilo na konferenci Uptime day 4, ki jo je organiziral ITSumma, lahko vidiš na YouTube kanalu Uptime Community.

Odpornost fizične arhitekture

Javni del oblaka MCS je sedaj zasnovan v dveh podatkovnih centrih Tier III, med njima je lastno temno vlakno, rezervirano na fizični ravni po različnih poteh, s prepustnostjo 200 Gbit/s. Stopnja III zagotavlja potrebno raven tolerance napak za fizično infrastrukturo.

Temna vlakna so rezervirana tako na fizični kot na logični ravni. Postopek rezervacije kanalov se je ponavljal, pojavljale so se težave, komunikacijo med podatkovnimi centri pa nenehno izboljšujemo.

Na primer, nedolgo nazaj je bager med delom v vodnjaku v bližini enega od podatkovnih centrov prebil cev, znotraj katere sta bila tako glavni kot rezervni optični kabel. Naš komunikacijski kanal s podatkovnim centrom, odporen na napake, se je na eni točki, v vodnjaku, izkazal za ranljivega. Skladno s tem smo izgubili del infrastrukture. Pripravili smo zaključke in izvedli številne ukrepe, vključno z vgradnjo dodatne optike v sosednji vodnjak.

V podatkovnih centrih so točke prisotnosti komunikacijskih ponudnikov, katerim oddajamo svoje predpone preko BGP. Za vsako smer omrežja je izbrana najboljša metrika, ki omogoča različnim odjemalcem najboljšo kakovost povezave. Če se prekine komunikacija prek enega ponudnika, ponovno zgradimo usmerjanje prek razpoložljivih ponudnikov.

Če ponudnik odpove, samodejno preklopimo na naslednjega. V primeru izpada enega od podatkovnih centrov imamo v drugem podatkovnem centru zrcalno kopijo naših storitev, ki prevzame celotno obremenitev.

Kako je spletna arhitektura, odporna na napake, implementirana v platformo Mail.ru Cloud Solutions
Odpornost fizične infrastrukture

Kaj uporabljamo za toleranco napak na ravni aplikacije

Naša storitev je zgrajena na številnih odprtokodnih komponentah.

ExaBGP je storitev, ki izvaja številne funkcije z uporabo protokola dinamičnega usmerjanja, ki temelji na BGP. Aktivno ga uporabljamo za oglaševanje naših naslovov IP na beli listi, prek katerih uporabniki dostopajo do API-ja.

HAProxy je uravnoteženje visoke obremenitve, ki vam omogoča konfiguracijo zelo prilagodljivih pravil za uravnoteženje prometa na različnih ravneh modela OSI. Uporabljamo ga za ravnotežje pred vsemi storitvami: bazami podatkov, posredniki sporočil, storitvami API, spletnimi storitvami, našimi internimi projekti - vse stoji za HAProxy.

Aplikacija API — spletna aplikacija, napisana v pythonu, s katero uporabnik upravlja svojo infrastrukturo in svojo storitev.

Prijava delavca (v nadaljevanju preprosto delavec) - v storitvah OpenStack je to infrastrukturni demon, ki omogoča oddajanje ukazov API v infrastrukturo. Na primer, ustvarjanje diska se pojavi v delavcu, zahteva za ustvarjanje pa v aplikacijskem API-ju.

Standardna arhitektura aplikacij OpenStack

Večina storitev, ki so razvite za OpenStack, poskuša slediti eni sami paradigmi. Storitev je običajno sestavljena iz dveh delov: API-ja in delavcev (backend izvajalcev). API je praviloma WSGI aplikacija v pythonu, ki se zažene bodisi kot neodvisen proces (daemon), bodisi z že pripravljenim spletnim strežnikom Nginx ali Apache. API obdela uporabniško zahtevo in posreduje nadaljnja navodila delovni aplikaciji za izvedbo. Prenos poteka s posrednikom sporočil, običajno RabbitMQ, ostali so slabo podprti. Ko sporočila dosežejo posrednika, jih obdelajo delavci in po potrebi vrnejo odgovor.

Ta paradigma vključuje izolirane skupne točke napake: RabbitMQ in podatkovno zbirko. Toda RabbitMQ je izoliran znotraj ene storitve in je teoretično lahko individualen za vsako storitev. Zato pri MCS te storitve čim bolj ločimo; za vsak posamezen projekt ustvarimo ločeno bazo podatkov, ločen RabbitMQ. Ta pristop je dober, ker se v primeru nesreče na nekaterih ranljivih točkah ne pokvari celoten servis, ampak le del.

Število delovnih aplikacij je neomejeno, zato lahko API preprosto vodoravno prilagaja za izravnalniki, da poveča zmogljivost in odpornost na napake.

Nekatere storitve zahtevajo koordinacijo znotraj storitve, ko pride do zapletenih zaporednih operacij med API-ji in delavci. V tem primeru se uporablja en sam koordinacijski center, sistem gruče, kot je Redis, Memcache itd., ki omogoča enemu delavcu, da drugemu pove, da mu je ta naloga dodeljena (»prosim, ne jemlji«). Uporabljamo itd. Delavci praviloma aktivno komunicirajo z bazo podatkov, od tam pišejo in berejo informacije. Kot bazo podatkov uporabljamo mariadb, ki se nahaja v multimaster gruči.

Ta klasična enotna storitev je organizirana na način, ki je splošno sprejet za OpenStack. Lahko ga obravnavamo kot zaprt sistem, za katerega so metode skaliranja in tolerance napak povsem očitne. Na primer, za toleranco napak API-ja je dovolj, da pred njimi postavite balanser. Skaliranje delavcev se doseže s povečanjem njihovega števila.

Šibka točka v celotni shemi sta RabbitMQ in MariaDB. Njihova arhitektura si zasluži ločen članek. V tem članku se želim osredotočiti na toleranco napak API-ja.

Kako je spletna arhitektura, odporna na napake, implementirana v platformo Mail.ru Cloud Solutions
Arhitektura aplikacij Openstack. Uravnoteženje in toleranca napak platforme v oblaku

Izdelava uravnoteženja HAProxy, odpornega na napake, z uporabo ExaBGP

Da bi bili naši API-ji razširljivi, hitri in odporni na napake, smo prednje postavili izravnalnik obremenitve. Izbrali smo HAProxy. Po mojem mnenju ima vse potrebne lastnosti za našo nalogo: uravnoteženje na več ravneh OSI, vmesnik za upravljanje, prilagodljivost in razširljivost, veliko število metod uravnoteženja, podporo za tabele sej.

Prva težava, ki jo je bilo treba rešiti, je bila odpornost na napake samega balanserja. Preprosta namestitev balanserja prav tako povzroči točko okvare: balanser se pokvari in storitev se zruši. Da bi preprečili, da bi se to zgodilo, smo uporabili HAProxy v povezavi z ExaBGP.

ExaBGP vam omogoča implementacijo mehanizma za preverjanje stanja storitve. S tem mehanizmom smo preverili delovanje HAProxy in v primeru težav onemogočili storitev HAProxy iz BGP.

Shema ExaBGP+HAProxy

  1. Na tri strežnike namestimo potrebno programsko opremo ExaBGP in HAProxy.
  2. Na vsakem strežniku ustvarimo povratni vmesnik.
  3. Na vseh treh strežnikih temu vmesniku dodelimo enak bel naslov IP.
  4. Beli naslov IP se v internetu oglašuje prek ExaBGP.

Odpornost na napake je dosežena z oglaševanjem istega naslova IP z vseh treh strežnikov. Z omrežnega vidika je isti naslov dostopen iz treh različnih naslednjih skokov. Usmerjevalnik vidi tri enake poti, med njimi izbere najvišjo prioriteto na podlagi lastne metrike (to je običajno enaka možnost), promet pa gre samo na enega od strežnikov.

V primeru težav z delovanjem HAProxy ali izpada strežnika ExaBGP preneha objavljati pot, promet pa se gladko preusmeri na drug strežnik.

Tako smo dosegli toleranco balansirja na napake.

Kako je spletna arhitektura, odporna na napake, implementirana v platformo Mail.ru Cloud Solutions
Odpornost na napake uravnalnikov HAProxy

Shema se je izkazala za nepopolno: naučili smo se rezervirati HAProxy, nismo pa se naučili porazdeliti obremenitve znotraj storitev. Zato smo to shemo nekoliko razširili: prešli smo na uravnoteženje med več belimi naslovi IP.

Uravnoteženje na podlagi DNS plus BGP

Težava z uravnoteženjem obremenitve za naš HAProxy ostaja nerešena. Lahko pa se reši čisto preprosto, kot smo to storili tukaj.

Za uravnoteženje treh strežnikov boste potrebovali 3 bele naslove IP in dobri stari DNS. Vsak od teh naslovov je določen na vmesniku povratne zanke vsakega HAProxy in objavljen v internetu.

V OpenStacku se za upravljanje virov uporablja storitveni imenik, ki določa API končne točke določene storitve. V tem imeniku registriramo ime domene - public.infra.mail.ru, ki je preko DNS razrešena s tremi različnimi naslovi IP. Posledično dobimo porazdelitev obremenitve med tremi naslovi prek DNS.

Ker pa pri objavi belih naslovov IP ne nadzorujemo prioritet izbire strežnikov, to še ni uravnoteženje. Običajno bo izbran samo en strežnik na podlagi starejšega naslova IP, druga dva pa bosta nedejavna, ker v BGP ni določena metrika.

Začeli smo pošiljati poti prek ExaBGP z različnimi metrikami. Vsak balanser oglašuje vse tri bele naslove IP, vendar se eden od njih, glavni za ta balanser, oglašuje z minimalno metriko. Torej, medtem ko vsi trije izravnalniki delujejo, gredo klici na prvi naslov IP k prvemu izravnalniku, klici na drugemu k drugemu in klici k tretjemu k tretjemu.

Kaj se zgodi, ko eden od tehtalcev pade? Če kateri koli izravnalnik odpove, se njegov glavni naslov še vedno oglašuje od drugih dveh in promet se prerazporedi med njima. Tako uporabniku preko DNS damo več IP ​​naslovov hkrati. Z uravnoteženjem po DNS in različnih metrikah dobimo enakomerno porazdelitev obremenitve na vse tri balancerje. In hkrati ne izgubimo tolerance napak.

Kako je spletna arhitektura, odporna na napake, implementirana v platformo Mail.ru Cloud Solutions
Uravnoteženje HAProxy na podlagi DNS + BGP

Interakcija med ExaBGP in HAProxy

Tako smo implementirali toleranco napak v primeru, da strežnik zapusti, ki temelji na zaustavitvi najave poti. Toda HAProxy se lahko izklopi zaradi drugih razlogov, kot je okvara strežnika: skrbniške napake, napake znotraj storitve. Tudi v teh primerih želimo polomljeno balansirko odstraniti izpod bremena in potrebujemo drugačen mehanizem.

Zato smo z razširitvijo prejšnje sheme uvedli srčni utrip med ExaBGP in HAProxy. To je programska izvedba interakcije med ExaBGP in HAProxy, ko ExaBGP uporablja skripte po meri za preverjanje stanja aplikacij.

Če želite to narediti, morate v konfiguraciji ExaBGP konfigurirati pregledovalnik zdravja, ki lahko preveri status HAProxy. V našem primeru smo konfigurirali zdravstveno zaledje v HAProxy, s strani ExaBGP pa preverimo s preprosto zahtevo GET. Če se obvestilo neha pojavljati, potem HAProxy najverjetneje ne deluje in ga ni treba oglaševati.

Kako je spletna arhitektura, odporna na napake, implementirana v platformo Mail.ru Cloud Solutions
Preverjanje zdravja HAProxy

HAProxy Peers: sinhronizacija seje

Naslednja stvar je bila sinhronizacija sej. Pri delu prek porazdeljenih uravnavalcev je težko organizirati shranjevanje informacij o sejah strank. Toda HAProxy je eden redkih uravnavalcev, ki lahko to stori zaradi funkcionalnosti Peers - zmožnosti prenosa tabel sej med različnimi procesi HAProxy.

Obstajajo različne metode uravnoteženja: enostavne, kot npr okroglo-robin, in podaljšano, ko se odjemalčeva seja spomni in vsakič konča na istem strežniku kot prej. Želeli smo uresničiti drugo možnost.

HAProxy uporablja paličaste tabele za shranjevanje odjemalskih sej tega mehanizma. Shranijo odjemalčev izvirni naslov IP, izbrani ciljni naslov (backend) in nekatere storitvene informacije. Običajno se paličaste tabele uporabljajo za shranjevanje para izvorni IP + ciljni IP, kar je še posebej uporabno za aplikacije, ki ne morejo prenesti konteksta uporabniške seje, ko preklopijo na drug izravnalnik, na primer v načinu uravnoteženja RoundRobin.

Če se paličasta miza nauči premikati med različnimi procesi HAProxy (med katerimi pride do uravnoteženja), bodo naši balanserji lahko delali z enim naborom paličastih tabel. To bo omogočilo nemoteno preklapljanje odjemalčevega omrežja, če eden od uravnavalcev vrednosti odpove; delo z odjemalskimi sejami se bo nadaljevalo na istih ozadjih, ki so bila izbrana prej.

Za pravilno delovanje mora biti odpravljen problem izvornega IP naslova izravnalnika, iz katerega je bila vzpostavljena seja. V našem primeru je to dinamični naslov na vmesniku povratne zanke.

Korektno delo vrstnikov je doseženo le pod določenimi pogoji. To pomeni, da morajo biti časovne omejitve TCP dovolj velike ali pa mora biti preklapljanje dovolj hitro, da seja TCP nima časa za prekinitev. Vendar pa omogoča brezhibno preklapljanje.

V IaaS imamo storitev, zgrajeno z uporabo iste tehnologije. to Load Balancer kot storitev za OpenStack, ki se imenuje Octavia. Temelji na dveh procesih HAProxy in na začetku vključuje podporo za vrstnike. Pri tej storitvi so se odlično izkazali.

Slika shematično prikazuje premikanje enakovrednih tabel med tremi primerki HAProxy, predlagana je konfiguracija, kako je to mogoče konfigurirati:

Kako je spletna arhitektura, odporna na napake, implementirana v platformo Mail.ru Cloud Solutions
HAProxy Peers (sinhronizacija seje)

Če izvajate isto shemo, je treba njeno delovanje natančno preizkusiti. Ni dejstvo, da bo deloval na enak način 100% časa. Toda vsaj tabel palic ne boste izgubili, ko si boste morali zapomniti odjemalčev izvorni IP.

Omejitev števila hkratnih zahtev istega odjemalca

Vse storitve, ki so javno dostopne, vključno z našimi API-ji, so lahko predmet plazov zahtev. Vzroki zanje so lahko povsem različni, od uporabniških napak do ciljanih napadov. Občasno smo DDoS napadeni z naslovi IP. Stranke pogosto naredijo napake v svojih skriptih in nam posredujejo mini-DDoS.

Tako ali drugače je treba zagotoviti dodatno zaščito. Očitna rešitev je omejiti število zahtev API in ne izgubljati časa procesorja z obdelavo zlonamernih zahtev.

Za izvajanje takšnih omejitev uporabljamo omejitve hitrosti, organizirane na podlagi HAProxy, z uporabo istih paličnih tabel. Nastavitev omejitev je precej preprosta in omogoča omejitev uporabnika glede na število zahtev API-ju. Algoritem si zapomni izvorni IP, s katerega so poslane zahteve, in omeji število hkratnih zahtev enega uporabnika. Seveda smo izračunali povprečni profil obremenitve API-ja za vsako storitev in postavili omejitev ≈ 10-kratnika te vrednosti. Še naprej pozorno spremljamo situacijo in držimo prst na utripu.

Kako to izgleda v praksi? Imamo stranke, ki ves čas uporabljajo naše API-je za samodejno skaliranje. Zjutraj ustvarijo približno dvesto do tristo virtualnih strojev in jih zvečer izbrišejo. Za OpenStack ustvarjanje virtualnega stroja, tudi s storitvami PaaS, zahteva vsaj 1000 zahtev API-ja, saj interakcija med storitvami poteka tudi prek API-ja.

Takšen prenos nalog povzroči precej veliko obremenitev. Ocenili smo to obremenitev, zbrali dnevne konice, jih podeseterili in to je postala naša omejitev stopnje. Držimo prst na utripu. Pogosto vidimo bote in skenerje, ki nas poskušajo pogledati, ali imamo kakšne skripte CGA, ki jih je mogoče zagnati, mi jih aktivno režemo.

Kako posodobiti svojo kodno zbirko, ne da bi uporabniki opazili

Prav tako izvajamo toleranco napak na ravni procesov uvajanja kode. Med uvajanji lahko pride do napak, vendar je njihov vpliv na razpoložljivost storitve mogoče zmanjšati.

Nenehno posodabljamo naše storitve in moramo zagotoviti, da je baza kode posodobljena, ne da bi to vplivalo na uporabnike. To težavo smo uspeli rešiti z uporabo zmogljivosti upravljanja HAProxy in implementacijo Graceful Shutdown v naših storitvah.

Za rešitev te težave je bilo potrebno zagotoviti nadzor nad izravnalnikom in "pravilno" zaustavitev storitev:

  • V primeru HAProxy se nadzor izvaja prek datoteke statistike, ki je v bistvu vtičnica in je definirana v konfiguraciji HAProxy. Ukaze mu lahko pošiljate prek stdio. Toda naše glavno orodje za nadzor konfiguracije je ansible, zato ima vgrajen modul za upravljanje HAProxy. Ki jih aktivno uporabljamo.
  • Večina naših API-jev in storitev Engine podpira elegantne tehnologije zaustavitve: pri zaustavitvi čakajo na dokončanje trenutne naloge, pa naj bo to zahteva http ali kakšna servisna naloga. Enako se zgodi z delavcem. Pozna vse naloge, ki jih opravlja, in konča, ko vse uspešno opravi.

Zahvaljujoč tema dvema točkama je varen algoritem za našo namestitev videti takole.

  1. Razvijalec sestavi nov paket kode (za nas je to RPM), ga preizkusi v okolju za razvijalce, preizkusi v fazi in pusti v repozitoriju stopnje.
  2. Razvijalec določi nalogo za uvedbo z najnatančnejšim opisom »artefaktov«: različico novega paketa, opisom nove funkcionalnosti in drugimi podrobnostmi o uvedbi, če je potrebno.
  3. Skrbnik sistema začne posodobitev. Zažene Ansible playbook, ki naredi naslednje:
    • Vzame paket iz repozitorija stopnje in ga uporabi za posodobitev različice paketa v repozitoriju izdelkov.
    • Sestavi seznam ozadij posodobljene storitve.
    • Zaustavi prvo storitev, ki se posodobi v HAProxy, in počaka, da se njeni procesi končajo. Zahvaljujoč elegantni zaustavitvi smo prepričani, da bodo vse trenutne zahteve strank uspešno zaključene.
    • Ko se API in delavci popolnoma ustavijo in je HAProxy izklopljen, se koda posodobi.
    • Ansible izvaja storitve.
    • Za vsako storitev se potegnejo določene “ročke”, ki izvajajo enotno testiranje na številnih vnaprej določenih ključnih testih. Izvede se osnovno preverjanje nove kode.
    • Če v prejšnjem koraku ni bila najdena nobena napaka, se aktivira zaledje.
    • Pojdimo na naslednje zaledje.
  4. Ko so vsa ozadja posodobljena, se zaženejo funkcionalni testi. Če manjkajo, si razvijalec ogleda vsako novo funkcionalnost, ki jo je ustvaril.

S tem je namestitev končana.

Kako je spletna arhitektura, odporna na napake, implementirana v platformo Mail.ru Cloud Solutions
Cikel posodobitve storitve

Ta shema ne bi delovala, če ne bi imeli enega pravila. V boju podpiramo tako staro kot novo različico. Vnaprej, na stopnji razvoja programske opreme, je določeno, da tudi če pride do sprememb v bazi podatkov storitev, ne bodo zlomile prejšnje kode. Posledično se kodna baza postopoma posodablja.

Zaključek

Ko delim svoje misli o WEB arhitekturi, odporni na napake, bi rad še enkrat opozoril na njene ključne točke:

  • toleranca fizičnih napak;
  • toleranca napak v omrežju (balanserji, BGP);
  • odpornost na napake uporabljene in razvite programske opreme.

Stabilen čas delovanja za vse!

Vir: www.habr.com

Dodaj komentar