Kas tas Envoy ir kodėl visi apie jį kalba
Jei dirbi su mikroservisais, turbūt jau girdėjai apie Envoy proxy. Šis projektas, kurį pradėjo Lyft komanda 2016 metais, per keletą metų tapo vienu iš populiariausių sprendimų modernių paskirstytų sistemų pasaulyje. Bet kas gi tai per žvėris ir kodėl jis taip svarbus?
Envoy – tai aukšto našumo C++ kalba parašytas tinklo proxy, skirtas modernių debesų aplikacijų architektūrai. Skirtingai nei tradiciniai proxy serveriai, Envoy buvo sukurtas nuo nulio su mintimi, kad šiuolaikinės aplikacijos yra sudarytos iš daugybės mažų servisų, kurie nuolat bendrauja tarpusavyje. Ir čia prasideda įdomumai.
Tradiciniai load balanceriai, kaip NGINX ar HAProxy, puikiai atlieka savo darbą, bet jie buvo sukurti kitam laikui. Kai tavo aplikacija – tai vienas didelis monolitas arba keletas serverių, viskas paprasta. Bet kai turi 50, 100 ar net 500 skirtingų mikroservisų, kurie keičiasi duomenimis tūkstančius kartų per sekundę, reikia kažko galingesnio.
Service mesh ir Envoy vaidmuo jame
Čia įžengia service mesh koncepcija, ir Envoy yra jos širdis. Service mesh – tai infrastruktūros sluoksnis, kuris valdo visą komunikaciją tarp servisų. Įsivaizduok, kad kiekvienas tavo mikroservisas turi savo asmeninį apsaugininką ir kurjerį viename asmenyje. Tas „apsaugininkas” – tai Envoy proxy, kuris veikia kaip sidecar konteineris šalia kiekvieno serviso.
Tokia architektūra leidžia atskirti verslo logiką nuo tinklo komunikacijos logikos. Tavo Python, Java ar Go kodas nebereikia rūpintis retry logika, circuit breakers, rate limiting ar kitais sudėtingais dalykais. Visa tai perima Envoy. Programuotojai gali sutelkti dėmesį į tai, kas iš tiesų svarbu – verslo problemas spręsti.
Populiariausi service mesh sprendimai, tokie kaip Istio, Linkerd ar Consul Connect, naudoja Envoy kaip savo data plane. Tai reiškia, kad Envoy atlieka visą sunkųjį darbą – maršrutizuoja srautą, renka metrikas, užtikrina saugumą. O control plane (valdymo plokštuma) tik sako Envoy, ką daryti.
Funkcionalumas, dėl kurio verta susižavėti
Gerai, bet ką konkrečiai Envoy gali? Čia sąrašas būtų ilgas, bet paminėsiu svarbiausius dalykus.
Pirma, dinaminis konfigūravimas. Skirtingai nei tradiciniai proxy, kuriems reikia perkrauti konfigūraciją ir kartais net restartinti procesą, Envoy gali gauti naują konfigūraciją per API (xDS API) ir pritaikyti ją skrydžio metu. Tai reiškia, kad galima pridėti naujų servisų, pakeisti maršrutizavimo taisykles ar atnaujinti sertifikatus be jokio downtime.
Antra, išplėstinė maršrutizavimo logika. Gali maršrutizuoti srautą pagal HTTP headers, URL path, cookies, net pagal request body turinį. Nori siųsti 5% srauto į naują serviso versiją testavimui? Lengvai. Reikia nukreipti konkrečius vartotojus į beta versiją? Nėra problemos.
Trečia, observability. Envoy renka neįtikėtiną kiekį metrikų – latency, error rates, throughput ir dar dešimtis kitų rodiklių. Visos šios metrikos eksportuojamos Prometheus formatu, todėl integruoti su Grafana ar kitais monitoring įrankiais – vaikų žaidimas. Be to, Envoy palaiko distributed tracing su Jaeger ar Zipkin, kas leidžia sekti request kelionę per visą mikroservisų ekosistemą.
Praktinis pavyzdys: kaip pradėti su Envoy
Teorija teorija, bet kaip tai atrodo praktikoje? Pažiūrėkim į paprastą pavyzdį. Tarkime, turime du mikroservisus: frontend ir backend. Norime, kad Envoy būtų tarpininkas tarp jų.
Paprasčiausia Envoy konfigūracija atrodytų maždaug taip:
static_resources:
listeners:
- name: listener_0
address:
socket_address:
address: 0.0.0.0
port_value: 10000
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: backend
domains: ["*"]
routes:
- match:
prefix: "/"
route:
cluster: backend_service
http_filters:
- name: envoy.filters.http.router
clusters:
- name: backend_service
connect_timeout: 0.25s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: backend_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: backend
port_value: 8080
Šita konfigūracija sako Envoy klausytis 10000 porto ir visus užklausimus nukreipti į backend servisą, kuris veikia 8080 porte. Paprasta, bet veikia.
Realybėje, žinoma, konfigūracija būna daug sudėtingesnė. Pridedi retry logika, timeout’us, health checks, TLS terminaciją ir t.t. Bet grožis tas, kad visa tai galima pridėti palaipsniui, neliečiant aplikacijos kodo.
Saugumo aspektai ir TLS visur
Vienas iš didžiausių Envoy privalumų – puikus TLS palaikymas. Galima įjungti mTLS (mutual TLS) tarp visų servisų, kas reiškia, kad kiekvienas servisas autentifikuoja save kiekvienam kitam servisui. Tai apsaugo nuo man-in-the-middle atakų ir užtikrina, kad tik autorizuoti servisai gali bendrauti tarpusavyje.
Envoy palaiko automatinį sertifikatų rotavimą, kas yra kritiškai svarbu production aplinkoje. Niekas nenori naktį keltis, nes baigėsi sertifikato galiojimas. Su Envoy ir SPIFFE/SPIRE arba panašiais sprendimais, sertifikatai atsinaujina automatiškai kas kelias valandas ar dienas.
Be to, Envoy gali veikti kaip Web Application Firewall (WAF), filtruodamas įtartinas užklausas, ribodamas request rate’us pagal IP adresus ar kitus kriterijus. Tai ypač naudinga apsaugant API nuo DDoS atakų ar bot’ų.
Performance tuning ir optimizavimas
Envoy parašytas C++ ne be priežasties – našumas čia prioritetas. Bet net ir su geru įrankiu reikia žinoti, kaip jį tinkamai naudoti.
Vienas iš dažniausių klausimų – kiek resursų Envoy reikia? Atsakymas: priklauso. Paprastam sidecar proxy, kuris apdoroja keletą šimtų request’ų per sekundę, pakanka 100-200MB RAM ir minimaliausio CPU. Bet jei kalba apie edge proxy, kuris priima visą išorinį srautą, gali prireikti kelių gigabaitų RAM ir dedikuotų CPU core’ų.
Svarbūs parametrai, į kuriuos verta atkreipti dėmesį:
Connection pool settings – kiek lygiagrečių connection’ų Envoy gali palaikyti į backend servisus. Per mažas skaičius – bus bottleneck, per didelis – švaistysi resursus.
Buffer limits – kiek duomenų Envoy gali laikyti atmintyje, kol laukia atsakymo iš backend’o. Jei backend lėtas, bufferiai gali perpildyti ir pradės mesti connection’us.
Worker threads – kiek thread’ų Envoy naudoja request’ams apdoroti. Paprastai geriausia nustatyti pagal CPU core’ų skaičių.
Praktikoje, pradėk su default settings ir monitorink metrikas. Jei matai, kad CPU usage artėja prie 100%, pridėk daugiau worker thread’ų arba scale horizontaliai. Jei RAM usage auga nekontroliuojamai, peržiūrėk buffer settings.
Integracijos su kitais įrankiais
Envoy nebūtų toks populiarus, jei neturėtų puikių integracijų su visa šiuolaikine DevOps ekosistema.
Kubernetes – natūralu, kad Envoy puikiai veikia su K8s. Yra daug įrankių, kurie automatizuoja Envoy deployment’ą Kubernetes klasteryje: Istio, Ambassador, Gloo ir kiti. Jie automatiškai inject’ina Envoy sidecar’us į pod’us, konfigūruoja service discovery ir t.t.
Prometheus ir Grafana – visos Envoy metrikos automatiškai eksportuojamos Prometheus formatu. Yra ready-made Grafana dashboard’ų, kuriuos galima importuoti ir iš karto matyti visą situaciją.
Jaeger/Zipkin – distributed tracing veikia out-of-the-box. Tereikia sukonfiguruoti tracing backend’ą, ir Envoy pradės siųsti span’us.
ELK stack – Envoy logai gali būti siunčiami į Elasticsearch, kur juos galima analizuoti su Kibana. Access logai, error logai, debug logai – viskas vienoje vietoje.
Kada Envoy nėra geriausias pasirinkimas
Būkime sąžiningi – Envoy ne visada yra atsakymas. Jei turi mažą aplikaciją su 2-3 servisais, Envoy bus overkill. NGINX ar Traefik bus paprastesni ir greičiau setup’inti.
Jei komanda neturi patirties su mikroservisais ir distributed systems, Envoy pridės complexity, kuris gali daugiau pakenkti nei padėti. Pirmiausia reikia suprasti, kodėl tau to reikia.
Taip pat, jei infrastruktūra dar nėra containerized ir nėra Kubernetes ar panašios orchestration platformos, Envoy deployment’as bus sudėtingas. Žinoma, galima deploy’inti Envoy tiesiog kaip procesą VM’ose, bet tada prarandama daug automatizavimo privalumų.
Ateities perspektyvos ir bendruomenė
Envoy projektas yra labai aktyvus. CNCF (Cloud Native Computing Foundation) priėmė jį kaip graduated projektą, kas reiškia, kad jis laikomas production-ready ir turi stiprią bendruomenę.
Kas ketvirtį išeina naujos versijos su naujomis features. Pavyzdžiui, pastaraisiais metais pridėta WebAssembly (WASM) palaikymas, kas leidžia rašyti custom filter’ius įvairiomis programavimo kalbomis ir juos load’inti į Envoy dinamiškai. Tai atidaro neįtikėtinas galimybes extensibility.
Taip pat vyksta darbai dėl HTTP/3 ir QUIC protokolų palaikymo, kas dar labiau pagerins performance ir patikimumą.
Bendruomenė yra draugiška ir pasiruošusi padėti. Slack channel’as aktyvus, GitHub issues sprendžiamos greitai, dokumentacija nuolat tobulinama. Jei nuspręsi naudoti Envoy, tikrai nesijausei vienas.
Kaip visa tai sujungti į vieną paveikslą
Envoy proxy pakeitė tai, kaip mes galvojame apie mikroservisų komunikaciją. Jis paėmė sudėtingus tinklo dalykus – load balancing, service discovery, observability, security – ir padarė juos valdomas ir standartizuotas.
Ar turėtum jį naudoti? Jei kuri modernią cloud-native aplikaciją su mikroservisais, atsakymas greičiausiai taip. Bet nepulk iš karto. Pradėk nuo paprasto use case – gal edge proxy arba vieno kritinio serviso apsauga. Išmok, kaip jis veikia, suprask metrikas, paeksperimentuok su konfigūracija.
Envoy nėra silver bullet, bet tai vienas geriausių įrankių, kuriuos turime šiandien mikroservisų pasaulyje. Jis reikalauja investicijos į mokymąsi, bet atsiperkanti investicija, kai tavo sistema auga ir tampa sudėtingesnė. O jei jau naudoji Kubernetes ir galvoji apie service mesh – Envoy tikrai turėtų būti tavo radar’e.
