Kaj vemo o mikrostoritvah

Zdravo! Moje ime je Vadim Madison, vodim razvoj sistemske platforme Avito. Več kot enkrat je bilo povedano, kako se v podjetju premikamo od monolitne arhitekture k mikrostoritveni. Čas je, da delimo, kako smo preoblikovali našo infrastrukturo, da kar najbolje izkoristimo mikrostoritve in preprečimo, da bi se v njih izgubili. Kako nam tukaj pomaga PaaS, kako smo poenostavili uvajanje in skrčili ustvarjanje mikrostoritve na en klik – berite dalje. Ni vse, o čemer pišem spodaj, v celoti implementirano v Avito, nekaj od tega je, kako razvijamo našo platformo.

(Na koncu tega članka bom govoril o priložnosti za udeležbo na tridnevnem seminarju strokovnjaka za arhitekturo mikrostoritev Chrisa Richardsona).

Kaj vemo o mikrostoritvah

Kako smo prišli do mikrostoritev

Avito je eno največjih malih mest na svetu, na njem je dnevno objavljenih več kot 15 milijonov novih oglasov. Naše zaledje sprejme več kot 20 tisoč zahtev na sekundo. Trenutno imamo več sto mikrostoritev.

Že nekaj let gradimo arhitekturo mikrostoritev. Kako natančno - naši kolegi podrobno povedal na naši rubriki na RIT++ 2017. Na CodeFestu 2017 (glej. Video), Sergey Orlov in Mikhail Prokopchuk sta podrobno razložila, zakaj potrebujemo prehod na mikrostoritve in kakšno vlogo je tu odigral Kubernetes. No, zdaj delamo vse, da čim bolj zmanjšamo stroške skaliranja, ki so neločljivo povezani s takšno arhitekturo.

Na začetku nismo ustvarili ekosistema, ki bi nam celovito pomagal pri razvoju in lansiranju mikrostoritev. Enostavno so zbrali smiselne odprtokodne rešitve, jih lansirali doma in povabili razvijalca, da se z njimi ukvarja. Posledično je šel na ducat mest (nadzorne plošče, interne storitve), nakar se je okrepil v želji po rezanju kode na star način, v monolit. Zelena barva v spodnjih diagramih označuje, kaj razvijalec tako ali drugače počne z lastnimi rokami, rumena barva pa označuje avtomatizacijo.

Kaj vemo o mikrostoritvah

Zdaj je v pripomočku PaaS CLI nova storitev ustvarjena z enim ukazom, nova baza podatkov pa je dodana še z dvema in razporejena v Stage.

Kaj vemo o mikrostoritvah

Kako preseči dobo "fragmentacije mikrostoritev"

Pri monolitni arhitekturi so bili razvijalci zaradi doslednosti sprememb v izdelku prisiljeni ugotavljati, kaj se dogaja pri njihovih sosedih. Pri delu na novi arhitekturi storitveni konteksti niso več odvisni drug od drugega.

Poleg tega je za učinkovito mikrostoritveno arhitekturo treba vzpostaviti številne procese, in sicer:

• sečnja;
• sledenje zahtevam (Jaeger);
• združevanje napak (Sentry);
• statusi, sporočila, dogodki iz Kubernetesa (Event Stream Processing);
• omejitev dirke / odklopnik (lahko uporabite Hystrix);
• nadzor povezljivosti storitev (uporabljamo Netramesh);
• monitoring (Grafana);
• montaža (TeamCity);
• komunikacija in obveščanje (Slack, email);
• sledenje opravilom; (Jira)
• priprava dokumentacije.

Da bi zagotovili, da sistem ne izgubi svoje celovitosti in ostane učinkovit, ko se širi, smo ponovno razmislili o organizaciji mikrostoritev v Avitu.

Kako upravljamo mikrostoritve

Naslednje pomaga pri izvajanju enotne »politike stranke« med številnimi mikrostoritvami Avito:

  • razdelitev infrastrukture na plasti;
  • Koncept platforme kot storitve (PaaS);
  • spremljanje vsega, kar se dogaja z mikrostoritvami.

Plasti abstrakcije infrastrukture vključujejo tri plasti. Pojdimo od zgoraj navzdol.

A. Zgornja servisna mreža. Najprej smo preizkusili Istio, a se je izkazalo, da porabi preveč virov, kar je za naše količine predrago. Zato je višji inženir v arhitekturni ekipi Alexander Lukyanchenko razvil lastno rešitev - Netramesh (na voljo v Open Source), ki ga trenutno uporabljamo v produkciji in porabi nekajkrat manj virov kot Istio (vendar ne počne vsega, s čimer se lahko pohvali Istio).
B. Srednje – Kubernetes. Na njem uvajamo in upravljamo mikrostoritve.
C. Dno - gola kovina. Ne uporabljamo oblakov ali stvari, kot je OpenStack, ampak se v celoti zanašamo na golo kovino.

Vse plasti združuje PaaS. In ta platforma je sestavljena iz treh delov.

I. Generatorji, nadzorovan prek pripomočka CLI. Ona je tista, ki pomaga razvijalcu ustvariti mikrostoritev na pravi način in z minimalnim trudom.

II. Konsolidirani zbiralnik z nadzorom vseh orodij prek skupne nadzorne plošče.

III. Shranjevanje. Povezuje se z načrtovalci, ki samodejno nastavijo sprožilce za pomembna dejanja. Zahvaljujoč takšnemu sistemu ni nobena naloga zgrešena samo zato, ker je nekdo pozabil nastaviti nalogo v Jiri. Za to uporabljamo interno orodje Atlas.

Kaj vemo o mikrostoritvah

Implementacija mikrostoritev v Avitu poteka tudi po enotni shemi, kar poenostavlja nadzor nad njimi na vsaki stopnji razvoja in izdaje.

Kako deluje standardni cevovod za razvoj mikrostoritev?

Na splošno je veriga ustvarjanja mikroservisov videti takole:

CLI-push → Continuous Integration → Bake → Deploy → Artificial tests → Canary tests → Squeeze Testing → Production → Maintenance.

Pojdimo skozi točno v tem vrstnem redu.

CLI-push

• Izdelava mikrostoritve.
Dolgo smo se trudili, da bi vsakega razvijalca naučili delati mikrostoritve. To je vključevalo pisanje podrobnih navodil v Confluence. Toda sheme so se spreminjale in dopolnjevale. Posledica tega je, da se je na začetku poti pojavilo ozko grlo: veliko več časa je bilo za zagon mikrostoritev, še vedno pa so se težave pogosto pojavljale med njihovim ustvarjanjem.

Na koncu smo zgradili preprost pripomoček CLI, ki avtomatizira osnovne korake pri ustvarjanju mikrostoritve. Pravzaprav nadomešča prvi git push. Evo, kaj točno počne.

— Ustvari storitev po predlogi — korak za korakom, v načinu »čarovnika«. Imamo predloge za glavne programske jezike v ozadju Avito: PHP, Golang in Python.

- En ukaz naenkrat razmesti okolje za lokalni razvoj na določen stroj - Minikube se zažene, grafikoni Helm se samodejno ustvarijo in zaženejo v lokalnih kubernetes.

— Povezuje zahtevano bazo podatkov. Razvijalcu ni treba poznati IP-ja, prijave in gesla, da bi pridobil dostop do podatkovne baze, ki jo potrebuje - bodisi lokalno, na odru ali v produkciji. Poleg tega je baza podatkov takoj razporejena v konfiguraciji, odporni na napake, in z uravnoteženjem.

— Sam izvaja montažo v živo. Recimo, da je razvijalec nekaj popravil v mikrostoritvi prek svojega IDE. Pripomoček vidi spremembe v datotečnem sistemu in na podlagi njih znova zgradi aplikacijo (za Golang) in znova zažene. Za PHP preprosto posredujemo imenik znotraj kocke in tam se live-reload pridobi »samodejno«.

— Ustvari samodejne teste. V obliki slepih, vendar zelo primernih za uporabo.

• Uvedba mikrostoritve.

Uvajanje mikroservisov je bilo včasih za nas kar malo opravilo. Zahtevano je bilo naslednje:

I. Dockerfile.

II. Config.
III. Shema krmila, ki je sama po sebi okorna in vključuje:

— same karte;
— predloge;
— specifične vrednosti ob upoštevanju različnih okolij.

Odpravili smo težave pri predelavi manifestov Kubernetes, tako da se zdaj ustvarijo samodejno. Najpomembneje pa je, da so uvajanje poenostavili do meje. Od zdaj naprej imamo datoteko Dockerfile in razvijalec zapiše celotno konfiguracijo v eno samo kratko datoteko app.toml.

Kaj vemo o mikrostoritvah

Da, in v samem app.toml za minuto ni ničesar za početi. Določimo, kje in koliko kopij storitve naj se dvigne (na razvijalskem strežniku, na uprizarjanju, v produkciji) in navedemo njene odvisnosti. Upoštevajte velikost vrstice = "small" v bloku [motor]. To je omejitev, ki bo dodeljena storitvi prek Kubernetesa.

Nato se na podlagi konfiguracije samodejno ustvarijo vsi potrebni grafikoni Helm in ustvarijo se povezave z bazami podatkov.

• Osnovna validacija. Takšni pregledi so tudi avtomatizirani.
Treba je slediti:
— ali obstaja datoteka Docker;
— ali obstaja app.toml;
— ali je na voljo dokumentacija?
— ali je odvisnost v redu?
— ali so bila nastavljena pravila opozarjanja.
Do zadnje točke: lastnik storitve sam določi, katere metrike izdelka bo spremljal.

• Priprava dokumentacije.
Še vedno problematično področje. Zdi se najbolj očitno, a je hkrati tudi »pogosto pozabljen« zapis in zato ranljiv člen v verigi.
Za vsako mikrostoritev mora obstajati dokumentacija. Vključuje naslednje bloke.

I. Kratek opis storitve. Dobesedno nekaj stavkov o tem, kaj počne in zakaj je potreben.

II. Povezava do diagrama arhitekture. Pomembno je, da je s hitrim pogledom enostavno razumeti, na primer, ali Redis uporabljate za predpomnjenje ali kot glavno shrambo podatkov v trajnem načinu. V Avitu je zaenkrat to povezava do Confluence.

III. Runbook. Kratek vodnik o zagonu storitve in zapletenosti ravnanja z njo.

IV. pogosta vprašanja, kjer bi bilo dobro predvideti težave, na katere lahko naletijo vaši sodelavci pri delu s storitvijo.

V. Opis končnih točk za API. Če nenadoma niste navedli destinacij, bodo sodelavci, katerih mikrostoritve so povezane z vašimi, skoraj zagotovo plačali za to. Zdaj za to uporabljamo Swagger in našo rešitev, imenovano brief.

VI. Etikete. Ali markerji, ki kažejo, kateremu izdelku, funkcionalnosti ali strukturni enoti podjetja storitev pripada. Pomagajo vam hitro razumeti, na primer, ali zmanjšujete funkcionalnost, ki so jo vaši kolegi uvedli za isto poslovno enoto pred tednom dni.

VII. Lastnik ali lastniki storitve. V večini primerov jih je – ali jih – mogoče določiti samodejno z uporabo PaaS, vendar zaradi varnosti zahtevamo, da jih razvijalec določi ročno.

Nazadnje je dobro pregledati dokumentacijo, podobno kot pregled kode.

Stalna integracija

  • Priprava repozitorijev.
  • Ustvarjanje cevovoda v TeamCityju.
  • Nastavitev pravic.
  • Poiščite lastnike storitev. Tukaj je hibridna shema - ročno označevanje in minimalna avtomatizacija iz PaaS. Popolnoma samodejna shema odpove, ko se storitve prenesejo za podporo na drugo razvojno skupino ali na primer, če razvijalec storitve zapusti storitev.
  • Registracija storitve v Atlasu (glej zgoraj). Z vsemi svojimi lastniki in odvisnostmi.
  • Preverjanje migracij. Preverjamo, ali je katera od njih potencialno nevarna. Na primer, v enem od njih se prikaže tabela za spreminjanje ali kaj drugega, kar lahko prekine združljivost podatkovne sheme med različnimi različicami storitve. Takrat se migracija ne izvede, ampak se postavi v naročnino - PaaS mora lastniku storitve sporočiti, kdaj jo je varno uporabljati.

Pečemo

Naslednja faza so storitve pakiranja pred uvedbo.

  • Gradnja aplikacije. Po klasiki - v podobi Docker.
  • Generiranje grafikonov Helm za samo storitev in povezane vire. Vključno z bazami podatkov in predpomnilnikom. Ustvarijo se samodejno v skladu s konfiguracijo app.toml, ki je bila ustvarjena v fazi CLI-push.
  • Ustvarjanje vstopnic za skrbnike za odpiranje vrat (po potrebi).
  • Izvajanje testov enot in izračun pokritosti kode. Če je pokritost kode pod določenim pragom, potem najverjetneje storitev ne bo šla dlje - do uvajanja. Če je na meji sprejemljivega, bo storitvi dodeljen "pesimizirajoči" koeficient: potem, če se indikator sčasoma ne izboljša, bo razvijalec prejel obvestilo, da ni napredka v smislu testov ( in glede tega je treba nekaj narediti).
  • Upoštevanje omejitev pomnilnika in procesorja. Mikrostoritve večinoma pišemo v Golangu in jih izvajamo v Kubernetesu. Od tod ena subtilnost, povezana s posebnostjo jezika Golang: privzeto se ob zagonu uporabljajo vsa jedra na stroju, če ne nastavite izrecno spremenljivke GOMAXPROCS, in ko se na istem stroju zažene več takih storitev, se začnejo tekmovati za vire in se medsebojno vmešavati. Spodnji grafi prikazujejo, kako se čas izvajanja spremeni, če aplikacijo izvajate brez spora in v načinu dirke za vire. (Viri grafov so tukaj).

Kaj vemo o mikrostoritvah

Čas izvedbe, manj je bolje. Največ: 643 ms, najmanj: 42 ms. Fotografija je klikljiva.

Kaj vemo o mikrostoritvah

Čas za operacijo, manj je bolje. Največ: 14091 ns, najmanj: 151 ns. Fotografija je klikljiva.

V fazi priprave sklopa lahko to spremenljivko nastavite izrecno ali pa uporabite knjižnico automaxprocs od fantov iz Uberja.

Razporedi

• Preverjanje konvencij. Preden začnete dostavljati storitvene sklope v predvidena okolja, morate preveriti naslednje:
- API končne točke.
— Skladnost odzivov končnih točk API s shemo.
— Oblika dnevnika.
— Nastavitev glav za zahteve do storitve (trenutno to počne netramesh)
— Nastavitev lastniškega žetona pri pošiljanju sporočil v vodilo dogodkov. To je potrebno za sledenje povezljivosti storitev prek avtobusa. V vodilo lahko pošiljate tako idempotentne podatke, ki ne povečujejo povezljivosti storitev (kar je dobro), kot poslovne podatke, ki krepijo povezljivost storitev (kar je zelo slabo!). In na točki, ko ta povezljivost postane težava, razumevanje, kdo piše in bere avtobus, pomaga pravilno ločiti storitve.

V Avitu še ni prav veliko konvencij, vendar se njihov bazen širi. Več kot je takšnih sporazumov na voljo v obliki, ki jo ekipa razume in razume, lažje je vzdrževati skladnost med mikrostoritvami.

Sintetični testi

• Testiranje v zaprti zanki. Za to zdaj uporabljamo odprto kodo Hoverfly.io. Najprej zabeleži dejansko obremenitev storitve, nato pa jo – samo v zaprti zanki – posnema.

• Stresno testiranje. Vse storitve se trudimo pripeljati do optimalne učinkovitosti. In vse različice vsake storitve morajo biti podvržene obremenitvenemu testiranju - tako lahko razumemo trenutno delovanje storitve in razliko s prejšnjimi različicami iste storitve. Če se je po posodobitvi storitve njena zmogljivost zmanjšala za enkrat in pol, je to jasen signal za njene lastnike: morate se poglobiti v kodo in popraviti situacijo.
Zbrane podatke uporabljamo na primer za pravilno implementacijo samodejnega skaliranja in na koncu na splošno razumemo, kako prilagodljiva je storitev.

Med obremenitvenim testiranjem preverimo, ali poraba virov ustreza postavljenim omejitvam. In osredotočeni smo predvsem na ekstreme.

a) Gledamo skupno obremenitev.
- Premajhna - najverjetneje nekaj sploh ne deluje, če obremenitev nenadoma večkrat pade.
- Prevelik - potrebna je optimizacija.

b) Gledamo cutoff glede na RPS.
Tu si ogledamo razliko med trenutno različico in prejšnjo različico ter skupno količino. Na primer, če storitev proizvede 100 rps, potem je bodisi slabo napisana ali pa je to njena specifičnost, v vsakem primeru pa je to razlog, da storitev pogledamo zelo natančno.
Če pa je, nasprotno, preveč RPS-jev, je morda prišlo do neke vrste hrošča in so nekatere končne točke prenehale izvajati obremenitev, druga pa se preprosto sproži return true;

Kanarski testi

Ko opravimo sintetične teste, mikrostoritev preizkusimo na manjšem številu uporabnikov. Začnemo previdno, z majhnim deležem ciljne publike storitve - manj kot 0,1 %. Na tej stopnji je zelo pomembno, da so v spremljanje vključene pravilne tehnične in produktne metrike, da čim hitreje pokažejo težavo v storitvi. Minimalni čas za kanarčkov test je 5 minut, glavni pa 2 uri. Pri kompleksnih storitvah uro nastavimo ročno.
Analizirajmo:
— metrike, specifične za jezik, zlasti delavci php-fpm;
— napake v Sentryju;
— stanja odziva;
— odzivni čas, natančen in povprečen;
— zakasnitev;
— izjeme, obdelane in neobravnavane;
— meritve izdelka.

Testiranje stiskanja

Testiranje stiskanja se imenuje tudi testiranje stiskanja. Ime tehnike je bilo predstavljeno v Netflixu. Njegovo bistvo je, da najprej eno instanco napolnimo z realnim prometom do onemoglosti in s tem nastavimo njeno mejo. Nato dodamo še eno instanco in naložimo ta par – spet do maksimuma; že s prvim »stiskom« vidimo njihov strop in delto. In tako povežemo en primerek naenkrat in izračunamo vzorec sprememb.
Podatki o testiranju se preko »stiskanja« stekajo tudi v skupno bazo metrik, kjer z njimi bodisi obogatimo rezultate umetne obremenitve ali celo zamenjamo »sintetiko«.

Proizvodnja

• Skaliranje. Ko uvajamo storitev v proizvodnjo, spremljamo, kako se širi. Po naših izkušnjah je spremljanje samo indikatorjev procesorja neučinkovito. Samodejno skaliranje s primerjalno analizo RPS v čisti obliki deluje, vendar le za določene storitve, kot je spletno pretakanje. Zato najprej pogledamo meritve izdelka, specifične za aplikacijo.

Kot rezultat, pri skaliranju analiziramo:
- indikatorji CPU in RAM,
— število zahtevkov v čakalni vrsti,
- odzivni čas,
— napoved na podlagi zbranih preteklih podatkov.

Pri skaliranju storitve je pomembno tudi spremljati njene odvisnosti, da ne skaliramo prve storitve v verigi in tiste, do katerih dostopa, odpovejo pod obremenitvijo. Za določitev sprejemljive obremenitve za celotno skupino storitev si ogledamo zgodovinske podatke »najbližje« odvisne storitve (na podlagi kombinacije indikatorjev CPE in RAM, skupaj z meritvami, specifičnimi za aplikacijo) in jih primerjamo s zgodovinskimi podatki inicializacijske storitve in tako naprej v celotni »verigi odvisnosti«, od zgoraj navzdol.

Storitev

Ko je mikrostoritev zagnana, lahko nanjo pripnemo sprožilce.

Tukaj so tipične situacije, v katerih se pojavijo sprožilci.
— Zaznane potencialno nevarne migracije.
— Izdane so varnostne posodobitve.
— Sama storitev že dolgo ni bila posodobljena.
— Obremenitev storitve se je opazno zmanjšala ali pa so nekatere njene meritve izdelkov zunaj običajnega obsega.
— Storitev ne izpolnjuje več zahtev nove platforme.

Nekateri sprožilci so odgovorni za stabilnost delovanja, nekateri - kot funkcija vzdrževanja sistema - na primer, neka storitev že dolgo ni bila nameščena in njena osnovna slika ni več prestala varnostnih pregledov.

Nadzorna plošča

Na kratko, nadzorna plošča je nadzorna plošča našega celotnega PaaS.

  • Ena točka informacij o storitvi s podatki o njeni testni pokritosti, številu njenih slik, številu produkcijskih kopij, različicah itd.
  • Orodje za filtriranje podatkov po storitvah in oznakah (označevalci pripadnosti poslovnim enotam, funkcionalnosti izdelkov itd.)
  • Orodje za integracijo z infrastrukturnimi orodji za sledenje, beleženje in spremljanje.
  • Servisna dokumentacija na eni točki.
  • En sam pogled na vse dogodke v storitvah.

Kaj vemo o mikrostoritvah
Kaj vemo o mikrostoritvah
Kaj vemo o mikrostoritvah
Kaj vemo o mikrostoritvah

Skupno

Pred uvedbo PaaS bi novi razvijalec lahko porabil več tednov za razumevanje vseh orodij, ki so potrebna za zagon mikrostoritve v produkciji: Kubernetes, Helm, naše notranje funkcije TeamCity, nastavitev povezav z bazami podatkov in predpomnilniki na način, ki je odporen na napake, itd. traja nekaj ur, da preberete hitri začetek in ustvarite samo storitev.

O tej temi sem podal poročilo za HighLoad++ 2018, lahko si ga ogledate Video и predstavitev.

Bonus skladba za tiste, ki preberete do konca

V Avitu organiziramo interno tridnevno izobraževanje za razvijalce iz Chris Richardson, strokovnjak za arhitekturo mikrostoritev. Priložnost sodelovanja pri njem želimo dati enemu od bralcev tega prispevka. Tukaj Program usposabljanja je objavljen.

Usposabljanje bo potekalo od 5. do 7. avgusta v Moskvi. To so delovni dnevi, ki bodo polno zasedeni. Kosilo in trening bosta v naši pisarni, izbrani udeleženec pa bo pot in nastanitev plačal sam.

Za sodelovanje se lahko prijavite v tem google obrazcu. Od vas - odgovor na vprašanje, zakaj se morate udeležiti izobraževanja in informacije, kako stopiti v stik z vami. Odgovorite v angleščini, saj bo Chris sam izbral udeleženca, ki se bo udeležil usposabljanja.
Ime udeleženca usposabljanja bomo objavili v posodobitvi te objave in na družbenih omrežjih Avito za razvijalce (AvitoTech v Facebook, Vkontakte, Twitter) najkasneje do 19. julija.

Vir: www.habr.com

Dodaj komentar