Kako prelazimo sa monolitne aplikacije na arhitekturu mikroservisa, suočavamo se s novim izazovima.
U monolitnoj aplikaciji obično je prilično lako odrediti u kojem dijelu sistema je došlo do greške. Najvjerovatnije je problem u kodu samog monolita, ili u bazi podataka. Ali kada počnemo tražiti problem u mikroservisnoj arhitekturi, sve više nije tako očigledno. Moramo pronaći cijeli put kojim je zahtjev prošao od početka do kraja i odabrati ga među stotinama mikroservisa. Štoviše, mnogi od njih također imaju vlastita skladišta, što također može uzrokovati logičke greške, kao i probleme s performansama i tolerancijom grešaka.
Dugo sam tražio alat koji bi pomogao u rješavanju ovakvih problema (pisao sam o tome na Habréu:
Distribuirano praćenje je uobičajeno rješenje za problem pronalaženja grešaka u distribuiranim sistemima. Ali šta ako ovaj pristup prikupljanju informacija o mrežnim interakcijama još nije implementiran u sistem, ili, još gore, u dijelu sistema već radi kako treba, ali dijelom ne, jer nije dodat starim servisima ? Da bi se utvrdio tačan uzrok problema, potrebno je imati potpunu sliku o tome šta se dešava u sistemu. Posebno je važno razumjeti koje su mikroservise uključene u ključne poslovno kritične puteve.
Ovdje nam u pomoć može priskočiti pristup servisne mreže, koji će se baviti svom mašinerijom za prikupljanje mrežnih informacija na nivou nižem nego što rade same usluge. Ovaj pristup nam omogućava da presretnemo sav promet i analiziramo ga u hodu. Štaviše, aplikacije čak i ne moraju znati ništa o tome.
Pristup servisnoj mreži
Glavna ideja pristupa servisne mreže je dodavanje još jednog infrastrukturnog sloja preko mreže, koji će nam omogućiti da uradimo bilo šta uz međuservisnu interakciju. Većina implementacija radi na sljedeći način: svakom mikroservisu se dodaje dodatni sidecar kontejner sa transparentnim proxyjem, kroz koji se propušta sav dolazni i odlazni promet usluge. I to je upravo mjesto gdje možemo raditi balansiranje klijenata, primjenjivati sigurnosne politike, nametati ograničenja broja zahtjeva i prikupljati važne informacije o interakciji usluga u produkciji.
Rešenja
Već postoji nekoliko implementacija ovog pristupa:
Kao rezultat toga, pogledali smo tačno koje su nam mogućnosti trenutno potrebne i odlučili da je glavni razlog zašto smo započeli implementaciju ovakvih rješenja bila mogućnost transparentnog prikupljanja informacija o praćenju iz cijelog sistema. Također smo željeli imati kontrolu nad interakcijom servisa i vršiti razne manipulacije sa zaglavljima koji se prenose između servisa.
Kao rezultat toga, došli smo do naše odluke:
Netramesh
Glavni ciljevi novog rješenja bili su mali troškovi resursa i visoke performanse. Među glavnim karakteristikama, odmah smo željeli da budemo u mogućnosti da transparentno šaljemo raspone praćenja u naš Jaeger sistem.
Danas se većina rješenja u oblaku implementira u Golang. I, naravno, postoje razlozi za to. Pisanje mrežnih aplikacija u Golangu koje rade asinhrono sa I/O i skaliraju preko jezgara po potrebi je zgodno i prilično jednostavno. I, što je takođe veoma važno, performanse su dovoljne da se ovaj problem reši. Zato smo i odabrali Golang.
Produktivnost
Usmjerili smo svoje napore na postizanje maksimalne produktivnosti. Za rješenje koje se postavlja pored svake instance usluge potrebna je mala potrošnja RAM-a i CPU vremena. I, naravno, kašnjenje odgovora takođe treba da bude malo.
Da vidimo kakve smo rezultate dobili.
RAM
Netramesh troši ~10Mb bez prometa i 50Mb maksimalno uz opterećenje do 10000 RPS po instanci.
Istio envoy proxy uvijek troši ~300Mb u našim klasterima sa hiljadama instanci. Ovo ne dozvoljava da se skalira na cijeli klaster.
Sa Netrameshom smo dobili ~10x smanjenje potrošnje memorije.
CPU
Upotreba CPU-a je relativno jednaka pod opterećenjem. Zavisi od broja zahtjeva po jedinici vremena do prikolice. Vrijednosti pri 3000 zahtjeva u sekundi na vrhuncu:
Postoji još jedna važna stvar: Netramesh - rješenje bez kontrolne ravni i bez opterećenja ne troši CPU vrijeme. Uz Istio, prikolice uvijek ažuriraju krajnje tačke usluge. Kao rezultat, ovu sliku možemo vidjeti bez opterećenja:
Koristimo HTTP/1 za komunikaciju između usluga. Povećanje vremena odgovora za Istio prilikom proxyja preko envoy-a bilo je do 5-10ms, što je dosta za servise koji su spremni odgovoriti u milisekundi. Sa Netramesh-om ovo vrijeme je smanjeno na 0.5-2ms.
Skalabilnost
Mala količina resursa koju troši svaki proxy omogućava njegovo postavljanje pored svake usluge. Netramesh je namjerno kreiran bez komponente kontrolne ravni kako bi jednostavno svaki bočni prikolica ostao lagan. Često u rješenjima servisne mreže, kontrolna ravnina distribuira informacije o otkrivanju usluge svakoj prikolici. Uz to dolaze i informacije o tajm-autima i postavkama balansiranja. Sve to vam omogućava da uradite mnogo korisnih stvari, ali, nažalost, povećava veličinu bočnih prikolica.
Otkriće usluge
Netramesh ne dodaje nikakve dodatne mehanizme za otkrivanje usluge. Sav promet se prenosi transparentno kroz netra sidecar.
Netramesh podržava HTTP/1 aplikacijski protokol. Da bi se to definiralo, koristi se konfigurabilna lista portova. Tipično, sistem ima nekoliko portova preko kojih se odvija HTTP komunikacija. Na primjer, za interakciju između usluga i vanjskih zahtjeva koristimo 80, 8890, 8080. U ovom slučaju, oni se mogu postaviti pomoću varijable okruženja NETRA_HTTP_PORTS
.
Ako koristite Kubernetes kao orkestrator i njegov mehanizam servisnog entiteta za komunikaciju unutar klastera između usluga, onda mehanizam ostaje potpuno isti. Prvo, mikroservis dobija IP adresu usluge koristeći kube-dns i otvara novu vezu sa njom. Ova veza se prvo uspostavlja s lokalnom netra-sidecarom i svi TCP paketi u početku stižu u netra. Zatim, netra-sidecar uspostavlja vezu sa originalnim odredištem. NAT na pod IP na čvoru ostaje potpuno isti kao bez netra.
Distribuirano praćenje i prosljeđivanje konteksta
Netramesh pruža funkcionalnost potrebnu za slanje raspona praćenja o HTTP interakcijama. Netra-sidecar analizira HTTP protokol, mjeri kašnjenja zahtjeva i izdvaja potrebne informacije iz HTTP zaglavlja. Na kraju, sve tragove dobijamo u jednom Jaeger sistemu. Za detaljnu konfiguraciju možete koristiti i varijable okruženja koje pruža zvanična biblioteka
Ali postoji problem. Sve dok usluge ne generiraju i pošalju posebno uber zaglavlje, nećemo vidjeti povezane raspone praćenja u sistemu. A to je ono što nam je potrebno da brzo pronađemo uzrok problema. I ovdje Netramesh ima rješenje. Proksiji čitaju HTTP zaglavlja i, ako ne sadrže uber trace ID, generiraju ga. Netramesh također pohranjuje informacije o dolaznim i odlaznim zahtjevima u pomoćnoj prikolici i uparuje ih obogaćujući ih potrebnim zaglavljima odlaznih zahtjeva. Sve što trebate učiniti u uslugama je da pošaljete samo jedno zaglavlje X-Request-Id
, koji se može konfigurirati pomoću varijable okruženja NETRA_HTTP_REQUEST_ID_HEADER_NAME
. Da biste kontrolirali veličinu konteksta u Netrameshu, možete postaviti sljedeće varijable okruženja: NETRA_TRACING_CONTEXT_EXPIRATION_MILLISECONDS
(vrijeme za koje će kontekst biti pohranjen) i NETRA_TRACING_CONTEXT_CLEANUP_INTERVAL
(učestalost čišćenja konteksta).
Također je moguće kombinirati više putanja na vašem sistemu označavajući ih posebnim tokenom sesije. Netra vam omogućava da instalirate HTTP_HEADER_TAG_MAP
da pretvorite HTTP zaglavlja u odgovarajuće oznake raspona praćenja. Ovo može biti posebno korisno za testiranje. Nakon prolaska funkcionalnog testa, možete vidjeti na koji dio sistema je utjecalo filtriranje po odgovarajućem ključu sesije.
Određivanje izvora zahtjeva
Da biste utvrdili odakle je zahtjev došao, možete koristiti funkciju automatskog dodavanja zaglavlja s izvorom. Korištenje varijable okruženja NETRA_HTTP_X_SOURCE_HEADER_NAME
Možete odrediti ime zaglavlja koje će se automatski instalirati. Korišćenjem NETRA_HTTP_X_SOURCE_VALUE
možete postaviti vrijednost na koju će zaglavlje X-Source biti postavljeno za sve odlazne zahtjeve.
Ovo omogućava da se distribucija ovog korisnog zaglavlja ravnomjerno distribuira kroz mrežu. Zatim ga možete koristiti u uslugama i dodati u dnevnike i metrike.
Usmjeravanje saobraćaja i Netramesh interni elementi
Netramesh se sastoji od dvije glavne komponente. Prvi, netra-init, postavlja mrežna pravila za presretanje saobraćaja. On koristi INBOUND_INTERCEPT_PORTS, OUTBOUND_INTERCEPT_PORTS
.
Alat također ima zanimljivu karakteristiku - vjerovatnost rutiranja. Ako koristite Netramesh isključivo za prikupljanje raspona praćenja, tada u proizvodnom okruženju možete uštedjeti resurse i omogućiti vjerojatnost rutiranja pomoću varijabli NETRA_INBOUND_PROBABILITY
и NETRA_OUTBOUND_PROBABILITY
(od 0 do 1). Zadana vrijednost je 1 (sav promet je presretan).
Nakon uspješnog presretanja, netra sidecar prihvata novu vezu i koristi SO_ORIGINAL_DST
opcija socketa da dobijete originalno odredište. Netra zatim otvara novu vezu sa originalnom IP adresom i uspostavlja dvosmjernu TCP komunikaciju između strana, slušajući sav promet koji prolazi. Ako je port definiran kao HTTP, Netra ga pokušava raščlaniti i pratiti. Ako HTTP raščlanjivanje ne uspije, Netra se vraća na TCP i transparentno proksije bajtove.
Izrada grafa zavisnosti
Nakon što sam dobio veliku količinu informacija o praćenju u Jaegeru, želim da dobijem kompletan grafikon interakcija u sistemu. Ali ako je vaš sistem prilično opterećen i akumuliraju se milijarde raspona praćenja dnevno, njihovo agregiranje nije tako lak zadatak. Postoji službeni način da se to uradi:
Ako koristite Elasticsearch za pohranjivanje raspona praćenja, možete koristiti
Kako koristiti Netramesh
Netra se može lako dodati bilo kojoj usluzi koja pokreće bilo koji orkestrator. Možete vidjeti primjer
U ovom trenutku, Netra nema mogućnost da automatski implementira pomoćne prikolice na usluge, ali postoje planovi za implementaciju.
Budućnost Netramesha
glavni cilj
U budućnosti, Netramesh će podržavati i druge protokole aplikacijskog sloja osim HTTP-a. L7 rutiranje će biti dostupno u bliskoj budućnosti.
Koristite Netramesh ako naiđete na slične probleme i pišite nam s pitanjima i prijedlozima.
izvor: www.habr.com