Što znamo o mikroservisima

Zdravo! Moje ime je Vadim Madison, vodim razvoj Avito System Platforme. Već je više puta rečeno kako mi u tvrtki prelazimo s monolitne arhitekture na mikroservisnu. Vrijeme je da podijelimo s vama kako smo transformirali našu infrastrukturu kako bismo maksimalno iskoristili mikroservise i spriječili da se izgubimo u njima. Kako nam PaaS tu pomaže, kako smo pojednostavili implementaciju i sveli izradu mikroservisa na jedan klik – čitajte dalje. Nije sve o čemu pišem u nastavku u potpunosti implementirano u Avito, nešto od toga je način na koji razvijamo našu platformu.

(Na kraju ovog članka, govorit ću o prilici da prisustvujem trodnevnom seminaru stručnjaka za mikroservisnu arhitekturu Chrisa Richardsona).

Što znamo o mikroservisima

Kako smo došli do mikroservisa

Avito je jedna od najvećih stranica s malim oglasima na svijetu, na kojoj se dnevno objavi više od 15 milijuna novih oglasa. Naš backend prihvaća više od 20 tisuća zahtjeva u sekundi. Trenutno imamo nekoliko stotina mikroservisa.

Već nekoliko godina gradimo mikroservisnu arhitekturu. Kako točno - naši kolege detaljno rekao u našoj sekciji na RIT++ 2017. Na CodeFestu 2017. (vidi. video), Sergey Orlov i Mikhail Prokopchuk detaljno su objasnili zašto nam je bio potreban prijelaz na mikroservise i kakvu je ulogu tu odigrao Kubernetes. Pa, sada činimo sve kako bismo minimizirali troškove skaliranja koji su svojstveni takvoj arhitekturi.

U početku nismo stvorili ekosustav koji bi nam sveobuhvatno pomogao u razvoju i pokretanju mikroservisa. Jednostavno su prikupili razumna rješenja otvorenog koda, pokrenuli ih kod kuće i pozvali programere da se pozabave njima. Zbog toga je prošao desetak mjesta (dashboards, interni servisi), nakon čega je ojačao u želji da kodira na stari način, u monolitu. Zelena boja u dijagramima ispod označava što programer na ovaj ili onaj način radi vlastitim rukama, a žuta boja označava automatizaciju.

Što znamo o mikroservisima

Sada se u PaaS CLI uslužnom programu, nova usluga stvara jednom naredbom, a nova baza podataka se dodaje s još dvije i postavlja na Stage.

Što znamo o mikroservisima

Kako prevladati eru "fragmentacije mikroservisa"

S monolitnom arhitekturom, radi dosljednosti promjena u proizvodu, programeri su bili prisiljeni shvatiti što se događa s njihovim susjedima. Prilikom rada na novoj arhitekturi, servisni konteksti više ne ovise jedan o drugome.

Osim toga, da bi arhitektura mikroservisa bila učinkovita, potrebno je uspostaviti mnoge procese, naime:

• sječa;
• praćenje zahtjeva (Jaeger);
• agregacija pogrešaka (Sentry);
• statusi, poruke, događaji iz Kubernetesa (Event Stream Processing);
• ograničenje utrke/prekidač (možete koristiti Hystrix);
• kontrola povezanosti servisa (koristimo Netramesh);
• monitoring (Grafana);
• montaža (TeamCity);
• komunikacija i obavještavanje (Slack, email);
• praćenje zadataka; (Jira)
• priprema dokumentacije.

Kako bismo osigurali da sustav ne izgubi svoj integritet i da ostane učinkovit dok se skalira, ponovno smo razmislili o organizaciji mikroservisa u Avitu.

Kako upravljamo mikroservisima

Sljedeće pomaže u implementaciji jedinstvene "stranačke politike" među mnogim Avito mikroservisima:

  • podjela infrastrukture na slojeve;
  • Koncept platforme kao usluge (PaaS);
  • praćenje svega što se događa s mikroservisima.

Slojevi apstrakcije infrastrukture uključuju tri sloja. Idemo od vrha do dna.

A. Gornja - servisna mreža. Prvo smo isprobali Istio, ali se pokazalo da koristi previše resursa, što je preskupo za naše količine. Stoga je viši inženjer u arhitektonskom timu Alexander Lukyanchenko razvio vlastito rješenje - Netramesh (dostupan u Open Sourceu), koji trenutno koristimo u produkciji i koji troši nekoliko puta manje resursa od Istia (ali ne radi sve čime se Istio može pohvaliti).
B. Srednji - Kubernetes. Na njemu implementiramo i upravljamo mikroservisima.
C. Dno - goli metal. Ne koristimo oblake ili stvari poput OpenStacka, već se u potpunosti oslanjamo na goli metal.

Sve slojeve kombinira PaaS. A ova se pak platforma sastoji od tri dijela.

I. Generatori, kontroliran putem CLI uslužnog programa. Upravo ona pomaže developeru kreirati mikroservis na pravi način i uz minimalno truda.

II. Konsolidirani kolektor s kontrolom svih alata preko zajedničke nadzorne ploče.

III. Skladištenje. Povezuje se s planerima koji automatski postavljaju okidače za značajne radnje. Zahvaljujući takvom sustavu niti jedan zadatak nije propušten samo zato što je netko zaboravio postaviti zadatak u Jiri. Za to koristimo interni alat koji se zove Atlas.

Što znamo o mikroservisima

Implementacija mikroservisa u Avitu također se provodi prema jednoj shemi, što pojednostavljuje kontrolu nad njima u svakoj fazi razvoja i izdanja.

Kako funkcionira standardni cjevovod razvoja mikroservisa?

Općenito, lanac stvaranja mikroservisa izgleda ovako:

CLI-push → Kontinuirana integracija → Pečenje → Postavljanje → Umjetni testovi → Canary testovi → Testiranje stiskanja → Proizvodnja → Održavanje.

Prođimo kroz to upravo ovim redom.

CLI-push

• Izrada mikroservisa.
Dugo smo se borili da svakog programera naučimo kako raditi mikroservise. To je uključivalo pisanje detaljnih uputa u Confluenceu. Ali sheme su se mijenjale i dopunjavale. Rezultat toga je da se usko grlo pojavilo na početku puta: trebalo je puno više vremena za pokretanje mikroservisa, a još uvijek su se problemi često javljali tijekom njihove izrade.

Na kraju smo izgradili jednostavan CLI uslužni program koji automatizira osnovne korake pri stvaranju mikroservisa. Zapravo, zamjenjuje prvi git push. Evo što ona točno radi.

— Stvara uslugu prema predlošku — korak po korak, u načinu rada “čarobnjaka”. Imamo predloške za glavne programske jezike u Avito pozadini: PHP, Golang i Python.

- Jedna po naredba postavlja okruženje za lokalni razvoj na određenom stroju - Minikube se pokreće, Helm karte se automatski generiraju i pokreću u lokalnim kubernetesima.

— Povezuje potrebnu bazu podataka. Razvojni programer ne mora znati IP, prijavu i lozinku da bi dobio pristup bazi podataka koja mu je potrebna - bilo to lokalno, na Stageu ili u produkciji. Štoviše, baza podataka se odmah postavlja u konfiguraciji otpornoj na pogreške i s balansiranjem.

— Sam izvodi montažu uživo. Recimo da je programer ispravio nešto u mikroservisu kroz svoj IDE. Uslužni program vidi promjene u datotečnom sustavu i na temelju njih ponovno gradi aplikaciju (za Golang) i ponovno se pokreće. Za PHP jednostavno prosljeđujemo direktorij unutar kocke i ondje se live-reload dobiva "automatski".

— Generira automatske testove. U obliku praznina, ali sasvim pogodan za upotrebu.

• Postavljanje mikroservisa.

Implementacija mikroservisa nekada nam je bila pomalo naporan posao. Bilo je potrebno sljedeće:

I. Dockerfile.

II. Konfiguracija
III. Shema kormila, koja je sama po sebi glomazna i uključuje:

— same karte;
— šablone;
— specifične vrijednosti uzimajući u obzir različita okruženja.

Olakšali smo preradu Kubernetes manifesta tako da se sada generiraju automatski. Ali što je najvažnije, pojednostavili su implementaciju do krajnjih granica. Od sada imamo Dockerfile, a programer zapisuje cijelu konfiguraciju u jednu kratku app.toml datoteku.

Što znamo o mikroservisima

Da, iu samom app.toml nemate što raditi ni minutu. Određujemo gdje i koliko kopija usluge treba podići (na razvojnom poslužitelju, na pozornici, u produkciji) i označavamo njezine ovisnosti. Primijetite veličinu retka = "small" u bloku [engine]. Ovo je ograničenje koje će biti dodijeljeno usluzi putem Kubernetesa.

Zatim se na temelju konfiguracije automatski generiraju sve potrebne Helm karte i stvaraju se veze s bazama podataka.

• Osnovna provjera valjanosti. Takve su provjere također automatizirane.
Potrebno je pratiti:
— postoji li Dockerfile;
— postoji li app.toml;
— postoji li dostupna dokumentacija?
— je li ovisnost u redu?
— jesu li postavljena pravila upozorenja.
Do posljednje točke: vlasnik usluge sam određuje koje će metrike proizvoda pratiti.

• Priprema dokumentacije.
Još uvijek problematično područje. Čini se najočiglednijim, ali je ujedno i rekord koji se “često zaboravlja”, a samim time i ranjiva karika u lancu.
Potrebno je da postoji dokumentacija za svaki mikroservis. Uključuje sljedeće blokove.

I. Kratak opis usluge. Doslovno nekoliko rečenica o tome što radi i zašto je potreban.

II. Link na dijagram arhitekture. Važno je da je brzim pogledom na njega lako razumjeti, na primjer, koristite li Redis za predmemoriju ili kao glavnu pohranu podataka u trajnom načinu rada. U Avitu je za sada ovo poveznica na Confluence.

III. Runbook. Kratki vodič za pokretanje usluge i zamršenosti rukovanja njome.

IV. Pitanja, gdje bi bilo dobro predvidjeti probleme s kojima se vaši kolege mogu susresti u radu sa servisom.

V. Opis krajnjih točaka za API. Ako iznenada niste odredili odredišta, kolege čiji su mikroservisi povezani s vašim gotovo će sigurno platiti za to. Sada za to koristimo Swagger i naše rješenje koje se zove brief.

VI. Etikete. Ili oznake koje pokazuju kojem proizvodu, funkcionalnosti ili strukturnom odjelu tvrtke usluga pripada. Pomažu vam da brzo shvatite, na primjer, smanjujete li funkcionalnost koju su vaši kolege uveli za istu poslovnu jedinicu prije tjedan dana.

VII. Vlasnik ili vlasnici usluge. U većini slučajeva, to - ili oni - mogu se odrediti automatski pomoću PaaS-a, ali da bismo bili sigurni, zahtijevamo od programera da ih odredi ručno.

Konačno, dobra je praksa pregledati dokumentaciju, slično pregledu koda.

Kontinuirana integracija

  • Priprema spremišta.
  • Stvaranje cjevovoda u TeamCityju.
  • Postavljanje prava.
  • Potražite vlasnike usluga. Ovdje postoji hibridna shema - ručno označavanje i minimalna automatizacija iz PaaS-a. Potpuno automatizirana shema ne uspije kada se usluge prebace na podršku drugom razvojnom timu ili, na primjer, ako razvojni programer usluge odustane.
  • Registracija usluge u Atlasu (vidi gore). Sa svim svojim vlasnicima i ovisnicima.
  • Provjera migracija. Provjeravamo je li netko od njih potencijalno opasan. Na primjer, u jednom od njih pojavi se alter tablica ili nešto drugo što može prekinuti kompatibilnost podatkovne sheme između različitih verzija usluge. Tada se migracija ne provodi, već se stavlja u pretplatu - PaaS mora signalizirati vlasniku usluge kada je sigurno koristiti je.

Pečenje

Sljedeća faza su usluge pakiranja prije postavljanja.

  • Izrada aplikacije. Prema klasici - u Docker slici.
  • Generiranje Helm karata za samu uslugu i povezane resurse. Uključujući baze podataka i predmemoriju. Izrađuju se automatski u skladu s app.toml konfiguracijom koja je generirana u CLI-push fazi.
  • Stvaranje ulaznica za administratore za otvaranje portova (kada je potrebno).
  • Izvođenje jediničnih testova i izračunavanje pokrivenosti koda. Ako je pokrivenost koda ispod navedenog praga, najvjerojatnije usluga neće ići dalje - do implementacije. Ako je na rubu prihvatljivog, tada će se usluzi dodijeliti "pesimizirajući" koeficijent: tada, ako nema poboljšanja pokazatelja tijekom vremena, programer će primiti obavijest da nema napretka u smislu testova ( i tu treba nešto poduzeti).
  • Uzimanje u obzir ograničenja memorije i procesora. Uglavnom pišemo mikroservise u Golangu i pokrećemo ih u Kubernetesu. Otuda jedna suptilnost povezana s osobitošću jezika Golang: prema zadanim postavkama, prilikom pokretanja, koriste se sve jezgre na stroju, ako izričito ne postavite varijablu GOMAXPROCS, a kada se nekoliko takvih usluga pokrene na istom stroju, one počinju natjecati se za resurse, ometajući jedni druge. Grafikoni u nastavku pokazuju kako se vrijeme izvršenja mijenja ako pokrenete aplikaciju bez sukoba iu načinu rada utrke za resurse. (Izvori grafova su здесь).

Što znamo o mikroservisima

Vrijeme izvršenja, manje je bolje. Maksimalno: 643 ms, minimalno: 42 ms. Na fotografiju se može kliknuti.

Što znamo o mikroservisima

Vrijeme je za operaciju, manje je bolje. Maksimalno: 14091 ns, minimalno: 151 ns. Na fotografiju se može kliknuti.

U fazi pripreme sklopa, ovu varijablu možete postaviti eksplicitno ili možete koristiti biblioteku automaxprocs od momaka iz Ubera.

Rasporedi

• Provjera konvencija. Prije nego počnete isporučivati ​​servisne sklopove u predviđena okruženja, trebate provjeriti sljedeće:
- API krajnje točke.
— Sukladnost odgovora API krajnjih točaka sa shemom.
— Format dnevnika.
— Postavljanje zaglavlja za zahtjeve prema usluzi (trenutno to radi netramesh)
— Postavljanje vlasničkog tokena prilikom slanja poruka sabirnici događaja. Ovo je potrebno za praćenje povezanosti usluga preko sabirnice. U sabirnicu možete slati i idempotentne podatke koji ne povećavaju povezanost usluga (što je dobro) i poslovne podatke koji jačaju povezanost usluga (što je jako loše!). A u trenutku kada ova povezanost postane problem, razumijevanje tko piše i čita autobus pomaže u ispravnom razdvajanju usluga.

U Avitu još nema mnogo konvencija, ali njihov skup se širi. Što je više takvih ugovora dostupno u obliku koji tim može razumjeti i razumjeti, to je lakše održavati dosljednost između mikroservisa.

Sintetički testovi

• Testiranje zatvorene petlje. Za to sada koristimo otvoreni kod Hoverfly.io. Prvo bilježi stvarno opterećenje usluge, a zatim ga - samo u zatvorenoj petlji - emulira.

• Testiranje otpornosti na stres. Trudimo se sve usluge dovesti do optimalnog učinka. I sve verzije svake usluge moraju biti podvrgnute testiranju opterećenja - na taj način možemo razumjeti trenutnu izvedbu usluge i razliku s prethodnim verzijama iste usluge. Ako je nakon ažuriranja usluge njegova izvedba pala za jedan i pol puta, to je jasan signal za njegove vlasnike: morate kopati u kod i ispraviti situaciju.
Koristimo prikupljene podatke, na primjer, kako bismo ispravno implementirali automatsko skaliranje i na kraju općenito razumjeli koliko je usluga skalabilna.

Tijekom testiranja opterećenja provjeravamo zadovoljava li potrošnja resursa postavljena ograničenja. I fokusiramo se prvenstveno na krajnosti.

a) Gledamo ukupno opterećenje.
- Premalen - najvjerojatnije nešto uopće ne radi ako opterećenje iznenada padne nekoliko puta.
- Prevelik - potrebna optimizacija.

b) Gledamo cutoff prema RPS-u.
Ovdje gledamo razliku između trenutne i prethodne verzije te ukupnu količinu. Na primjer, ako usluga proizvodi 100 okretaja u sekundi, onda je ili loše napisana, ili je to njezina specifičnost, ali u svakom slučaju, to je razlog da se usluga pažljivo pogleda.
Ako, naprotiv, ima previše RPS-ova, onda možda postoji neka vrsta greške i neke od krajnjih točaka su prestale izvršavati korisni teret, a neke druge su jednostavno pokrenute return true;

Kanarinski testovi

Nakon što prođemo sintetičke testove, mikroservis testiramo na manjem broju korisnika. Počinjemo pažljivo, s malim udjelom namijenjene publike usluge - manje od 0,1%. U ovoj je fazi vrlo važno da se u praćenje uključe ispravne tehničke i proizvodne metrike kako bi što brže pokazale problem u usluzi. Minimalno vrijeme za test kanarinca je 5 minuta, glavni je 2 sata. Za složene usluge vrijeme postavljamo ručno.
Analizirajmo:
— metrika specifična za jezik, posebno php-fpm radnici;
— greške u Sentryju;
— statusi odgovora;
— vrijeme odziva, točno i prosječno;
— latencija;
— iznimke, obrađene i neobrađene;
— metrika proizvoda.

Testiranje stiskanja

Testiranje stiskanjem naziva se i testiranjem stiskanja. Naziv tehnike uveden je u Netflix. Suština mu je da prvo jednu instancu napunimo stvarnim prometom do granice kvara i tako postavimo njen limit. Zatim dodamo još jednu instancu i učitamo ovaj par - opet do maksimuma; prvim “stiskom” vidimo njihov strop i deltu. I tako povezujemo jednu po jednu instancu i izračunavamo obrazac promjena.
Testni podaci kroz "stiskanje" također teku u zajedničku bazu metrika, gdje ili obogaćujemo rezultate umjetnog opterećenja s njima, ili čak njima zamjenjujemo "sintetiku".

Proizvodnja

• Skaliranje. Kada uvedemo uslugu u proizvodnju, pratimo kako se ona skalira. Prema našem iskustvu, praćenje samo indikatora procesora je neučinkovito. Automatsko skaliranje s RPS benchmarkingom u svom čistom obliku radi, ali samo za određene usluge, kao što je online streaming. Stoga prvo gledamo mjerne podatke proizvoda specifične za aplikaciju.

Kao rezultat toga, prilikom skaliranja analiziramo:
- CPU i RAM indikatori,
— broj zahtjeva u redu čekanja,
- vrijeme odziva,
— predviđanje na temelju prikupljenih povijesnih podataka.

Prilikom skaliranja usluge također je važno nadzirati njezine ovisnosti kako ne bismo skalirali prvu uslugu u lancu, a one kojima pristupa otkazale bi pod opterećenjem. Kako bismo uspostavili prihvatljivo opterećenje za cijeli skup usluga, gledamo povijesne podatke "najbliže" ovisne usluge (na temelju kombinacije indikatora CPU-a i RAM-a, zajedno s mjernim podacima specifičnim za aplikaciju) i uspoređujemo ih s povijesnim podacima usluge inicijalizacije, i tako dalje kroz "lanac ovisnosti", od vrha do dna.

usluga

Nakon što je mikroservis pušten u rad, možemo mu priključiti okidače.

Ovdje su tipične situacije u kojima se pojavljuju okidači.
— Otkrivene potencijalno opasne migracije.
— Objavljena su sigurnosna ažuriranja.
— Sama usluga nije ažurirana dugo vremena.
— Opterećenje usluge primjetno se smanjilo ili su neki od njezinih pokazatelja proizvoda izvan normalnog raspona.
— Usluga više ne ispunjava zahtjeve nove platforme.

Neki od okidača odgovorni su za stabilnost rada, neki - kao funkcija održavanja sustava - na primjer, neka usluga nije bila implementirana dulje vrijeme i njezina osnovna slika prestala je prolaziti sigurnosne provjere.

Nadzorna ploča

Ukratko, nadzorna ploča je upravljačka ploča cijelog našeg PaaS-a.

  • Jedna točka informacija o usluzi, s podacima o njezinoj testnoj pokrivenosti, broju slika, broju produkcijskih primjeraka, verzijama itd.
  • Alat za filtriranje podataka po uslugama i oznakama (oznake pripadnosti poslovnim jedinicama, funkcionalnost proizvoda i sl.)
  • Integracijski alat s infrastrukturnim alatima za praćenje, bilježenje i nadzor.
  • Jedinstvena točka servisne dokumentacije.
  • Jedinstveno gledište svih događaja u svim uslugama.

Što znamo o mikroservisima
Što znamo o mikroservisima
Što znamo o mikroservisima
Što znamo o mikroservisima

Ukupno

Prije uvođenja PaaS-a, novi razvojni programer mogao bi provesti nekoliko tjedana u razumijevanju svih alata potrebnih za pokretanje mikroservisa u produkciji: Kubernetes, Helm, naše interne TeamCity značajke, postavljanje veza s bazama podataka i predmemorije na način otporan na pogreške, itd. Sada je potrebno je nekoliko sati za čitanje brzih početaka i izradu same usluge.

Dao sam izvještaj o ovoj temi za HighLoad++ 2018, možete ga pogledati video и prezentacija.

Bonus pjesma za one koji pročitaju do kraja

Mi u Avitu organiziramo interni trodnevni trening za programere iz Chris Richardson, stručnjak za arhitekturu mikroservisa. Željeli bismo pružiti priliku da u tome sudjeluje jednom od čitatelja ovog posta. Ovdje Program obuke je objavljen.

Obuka će se održati od 5. do 7. kolovoza u Moskvi. Ovo su radni dani koji će biti u potpunosti popunjeni. Ručak i trening će biti u našem uredu, a odabrani polaznik sam plaća put i smještaj.

Možete se prijaviti za sudjelovanje u ovom google obrascu. Od vas - odgovor na pitanje zašto trebate pohađati edukaciju i informacije kako vas kontaktirati. Odgovorite na engleskom jer će Chris sam odabrati sudionika koji će pohađati trening.
Objavit ćemo ime sudionika obuke u ažuriranju ove objave i na društvenim mrežama Avito za programere (AvitoTech u Фейсбуке, Vkontakte, cvrkut) najkasnije do 19. srpnja.

Izvor: www.habr.com

Dodajte komentar