Ujoj, mikroservoj kaj servaj retoj

Interrete aro artikoloj о servo maŝo (servo maŝo), kaj jen alia. Hura! Sed kial? Tiam mi volas esprimi mian opinion, ke estus pli bone, se servaj maŝoj aperus antaŭ 10 jaroj, antaŭ la apero de ujplatformoj kiel Docker kaj Kubernetes. Mi ne diras, ke mia vidpunkto estas pli bona aŭ pli malbona ol aliaj, sed ĉar servaj retoj estas sufiĉe kompleksaj bestoj, multoblaj vidpunktoj helpos pli bone kompreni ilin.

Mi parolos pri la platformo dotCloud, kiu estis konstruita sur pli ol cent mikroservoj kaj subtenis milojn da konteneritaj aplikoj. Mi klarigos la defiojn, kiujn ni renkontis disvolvante kaj lanĉante ĝin, kaj kiel servomaŝoj povus (aŭ ne povis) helpi.

Historio de dotCloud

Mi skribis pri la historio de dotCloud kaj la arkitekturaj elektoj por ĉi tiu platformo, sed mi ne multe parolis pri la retotavolo. Se vi ne volas plonĝi en legado lasta artikolo pri dotCloud, jen la esenco mallonge: ĝi estas platformo-kiel-servo de PaaS, kiu ebligas al klientoj ruli ampleksan gamon da aplikaĵoj (Java, PHP, Python...), kun subteno por ampleksa gamo de datumoj. servoj (MongoDB, MySQL, Redis...) kaj laborfluo kiel Heroku: Vi alŝutas vian kodon al la platformo, ĝi konstruas ujajn bildojn kaj deplojas ilin.

Mi rakontos al vi kiel trafiko estis direktita al la platformo dotCloud. Ne ĉar ĝi estis aparte mojosa (kvankam la sistemo funkciis bone por sia tempo!), sed ĉefe ĉar per modernaj iloj tia dezajno povas facile esti efektivigita en mallonga tempo fare de modesta teamo se ili bezonas manieron direkti trafikon inter aro. de mikroservoj aŭ aro da aplikoj. Tiel vi povas kompari la eblojn: kio okazas se vi mem disvolvas ĉion aŭ uzas ekzistantan servoreton. La norma elekto estas fari ĝin mem aŭ aĉeti ĝin.

Trafikvojigo por gastigitaj aplikoj

Aplikoj sur dotCloud povas elmontri HTTP- kaj TCP-finpunktojn.

HTTP-finpunktoj dinamike aldonita al la agordo de ŝarĝbalancilo Hipache. Ĉi tio similas al tio, kion faras rimedoj hodiaŭ Ingreso en Kubernetes kaj ŝarĝbalancilo kiel Traefik.

Klientoj konektas al HTTP-finpunktoj per taŭgaj domajnoj, kondiĉe ke la domajna nomo montras al dotCloud-ŝarĝbalanciloj. Nenio speciala.

TCP-finpunktoj asociita kun havennumero, kiu tiam estas pasita al ĉiuj ujoj en tiu stako per mediovariabloj.

Klientoj povas konektiĝi al TCP-finpunktoj uzante la taŭgan gastigan nomon (io kiel gateway-X.dotcloud.com) kaj havennumero.

Ĉi tiu gastnomo solvas al la "nats" servila aro (ne rilata al NATS), kiu direktos alvenantajn TCP-konegojn al la ĝusta ujo (aŭ, en la kazo de ŝarĝ-ekvilibraj servoj, al la ĝustaj ujoj).

Se vi konas Kubernetes, ĉi tio verŝajne memorigos vin pri Servoj NodePort.

Ne estis ekvivalentaj servoj en la platformo dotCloud ClusterIP: Por simpleco, servoj estis aliritaj same de interne kaj ekster la platformo.

Ĉio estis organizita tute simple: la komencaj efektivigoj de HTTP kaj TCP-vojaj retoj estis verŝajne nur kelkaj cent linioj de Python ĉiu. Simplaj (mi dirus naivaj) algoritmoj, kiuj estis rafinitaj dum la platformo kreskis kaj pliaj postuloj aperis.

Ampleksa refaktorigo de ekzistanta kodo ne estis postulata. Precipe, 12 faktoraj aplikaĵoj povas rekte uzi la adreson akiritan per mediovariabloj.

Kiel tio diferencas de moderna servomaŝo?

Limigita videbleco. Ni tute ne havis metrikojn por la TCP-vojiga maŝo. Kiam temas pri HTTP-vojigo, pli postaj versioj enkondukis detalajn HTTP-metrikojn kun eraraj kodoj kaj respondaj tempoj, sed modernaj servaj retoj iras eĉ pli for, provizante integriĝon kun metraj kolektosistemoj kiel Prometheus, ekzemple.

Videbleco gravas ne nur de funkcia perspektivo (por helpi solvi problemojn), sed ankaŭ dum publikigado de novaj funkcioj. Temas pri monŝranko bluverda deplojo и kanaria deplojo.

Enruta efikeco estas ankaŭ limigita. En la dotCloud-vojiga reto, la tuta trafiko devis trapasi aron de dediĉitaj vojnodoj. Tio signifis eble transpasi multoblajn AZ (Havebleca Zono) limojn kaj signife pliigi latentecon. Mi memoras pri solvo de problemoj, kiu faris pli ol cent SQL-demandojn per paĝo kaj malfermis novan konekton al la SQL-servilo por ĉiu demando. Kiam funkcias loke, la paĝo ŝarĝas tuj, sed en dotCloud necesas kelkajn sekundojn por ŝargi ĉar ĉiu TCP-konekto (kaj posta SQL-demando) daŭras dekojn da milisekundoj. En ĉi tiu aparta kazo, persistaj konektoj solvis la problemon.

Modernaj servaj retoj estas pli bonaj por trakti tiajn problemojn. Antaŭ ĉio, ili kontrolas, ke konektoj estas direktitaj en la fonto. La logika fluo estas la sama: клиент → меш → сервис, sed nun la maŝo funkcias loke kaj ne sur foraj nodoj, do la konekto клиент → меш estas loka kaj tre rapida (mikrosekundoj anstataŭ milisekundoj).

Modernaj servaj retoj ankaŭ efektivigas pli inteligentajn ŝarĝbalancajn algoritmojn. Monitorante la sanon de backends, ili povas sendi pli da trafiko al pli rapidaj backends, rezultigante plibonigitan ĝeneralan rendimenton.

Sekureco pli bone ankaŭ. La dotCloud-vojigo-maŝo funkciis tute sur EC2 Classic kaj ne ĉifris trafikon (surbaze de la supozo, ke se iu sukcesis meti flarin sur EC2-retan trafikon, vi jam havis grandajn problemojn). Modernaj servaj retoj travideble protektas nian tutan trafikon, ekzemple, per reciproka TLS-aŭtentikigo kaj posta ĉifrado.

Voja trafiko por platformaj servoj

Bone, ni diskutis pri trafiko inter aplikaĵoj, sed kio pri la platformo dotCloud mem?

La platformo mem konsistis el ĉirkaŭ cent mikroservoj respondecaj pri diversaj funkcioj. Kelkaj akceptis petojn de aliaj, kaj kelkaj estis fonlaboristoj kiuj konektis al aliaj servoj sed ne akceptis ligojn mem. Ĉiukaze, ĉiu servo devas scii la finpunktojn de la adresoj al kiuj ĝi bezonas konekti.

Multaj altnivelaj servoj povas uzi la vojan maŝon priskribitan supre. Fakte, multaj el la pli ol cent mikroservoj de dotCloud estis deplojitaj kiel regulaj aplikoj sur la platformo dotCloud mem. Sed malgranda nombro da malaltnivelaj servoj (precipe tiuj, kiuj efektivigas ĉi tiun enrutigan reton) bezonis ion pli simplan, kun malpli da dependecoj (ĉar ili ne povis dependi de si mem por funkcii - la bona malnova problemo de kokido kaj ovo).

Ĉi tiuj malaltnivelaj, misi-kritikaj servoj estis deplojitaj per uzado de ujoj rekte sur kelkaj ŝlosilaj nodoj. En ĉi tiu kazo, normaj platformservoj ne estis uzitaj: ligilo, planilo kaj kuristo. Se vi volas kompari kun modernaj ujplatformoj, estas kiel ruli kontrolaviadilon kun docker run rekte sur la nodoj, anstataŭ delegi la taskon al Kubernetes. Ĝi estas sufiĉe simila laŭ koncepto senmovaj moduloj (pods), kiun ĝi uzas kubeadmbootkube dum lanĉado de memstara grapolo.

Ĉi tiuj servoj estis elmontritaj en simpla kaj kruda maniero: YAML-dosiero listigis iliajn nomojn kaj adresojn; kaj ĉiu kliento devis preni kopion de ĉi tiu YAML-dosiero por deplojo.

Unuflanke, ĝi estas ege fidinda ĉar ĝi ne postulas la subtenon de ekstera ŝlosilo/valora vendejo kiel Zookeeper (memoru, ktpd aŭ Konsulo ne ekzistis tiutempe). Aliflanke, ĝi malfaciligis movi servojn. Ĉiufoje kiam movo estis farita, ĉiuj klientoj ricevus ĝisdatigitan YAML-dosieron (kaj eble rekomencus). Ne tre komforta!

Poste, ni komencis efektivigi novan skemon, kie ĉiu kliento konektita al loka prokura servilo. Anstataŭ adreso kaj haveno, ĝi nur bezonas scii la havennumeron de la servo, kaj konekti per localhost. La loka prokurilo pritraktas ĉi tiun konekton kaj plusendas ĝin al la fakta servilo. Nun, kiam vi movas la backend al alia maŝino aŭ skalo, anstataŭ ĝisdatigi ĉiujn klientojn, vi nur bezonas ĝisdatigi ĉiujn ĉi tiujn lokajn prokurojn; kaj rekomenco ne plu necesas.

(Oni planis ankaŭ enkapsuligi la trafikon en TLS-konektoj kaj meti alian prokuran servilon ĉe la riceva flanko, kaj ankaŭ kontroli TLS-atestilojn sen partopreno de la ricevanta servo, kiu estas agordita por akcepti konektojn nur sur localhost. Pli pri tio poste).

Ĉi tio estas tre simila al SmartStack de Airbnb, sed la grava diferenco estas, ke SmartStack estas efektivigita kaj deplojita al produktado, dum la interna vojsistemo de dotCloud estis arkivita kiam dotCloud iĝis Docker.

Mi persone konsideras SmartStack kiel unu el la antaŭuloj de sistemoj kiel Istio, Linkerd kaj Consul Connect ĉar ili ĉiuj sekvas la saman ŝablonon:

  • Rulu prokurilon sur ĉiu nodo.
  • Klientoj konektas al la prokurilo.
  • La kontrolaviadilo ĝisdatigas la prokuran agordon kiam backends ŝanĝiĝas.
  • ... Profitu!

Moderna efektivigo de servomaŝo

Se ni bezonus efektivigi similan kradon hodiaŭ, ni povus uzi similajn principojn. Ekzemple, agordu internan DNS-zonon mapante servonomojn al adresoj en la spaco 127.0.0.0/8. Poste rulu HAProxy sur ĉiu nodo en la areto, akceptante konektojn ĉe ĉiu servo-adreso (en tiu subreto 127.0.0.0/8) kaj redirektante/balancante la ŝarĝon al la taŭgaj backends. HAProxy-agordo povas esti kontrolita konfd, ebligante vin stoki backend informojn en etcd aŭ Konsulo kaj aŭtomate puŝi ĝisdatigitan agordon al HAProxy kiam necese.

Preskaŭ tiel funkcias Istio! Sed kun kelkaj diferencoj:

  • Uzoj Sendita Prokurado anstataŭ HAProxy.
  • Stokas backend-agordon per Kubernetes API anstataŭ etcd aŭ Consul.
  • Servoj estas asignitaj adresoj sur la interna subreto (Kubernetes ClusterIP-adresoj) anstataŭ 127.0.0.0/8.
  • Havas kroman komponenton (Citadelo) por aldoni reciprokan TLS-aŭtentikigon inter la kliento kaj serviloj.
  • Subtenas novajn funkciojn kiel cirkvito-rompiĝo, distribuita spurado, kanaria deplojo ktp.

Ni rapide rigardu kelkajn el la diferencoj.

Sendita Prokurado

Envoy Proxy estis verkita de Lyft [la konkuranto de Uber en la taksiomerkato - ĉ. leno]. Ĝi multmaniere similas al aliaj prokuriloj (ekz. HAProxy, Nginx, Traefik...), sed Lyft skribis la ilian ĉar ili bezonis funkciojn, kiujn mankis al aliaj prokuriloj, kaj ŝajnis pli saĝe fari novan prefere ol etendi la ekzistantan.

Envoy povas esti uzata memstare. Se mi havas specifan servon, kiu bezonas konektiĝi al aliaj servoj, mi povas agordi ĝin por konekti al Envoy, kaj tiam dinamike agordi kaj reagordi Envoy kun la loko de aliaj servoj, kaj ricevante multajn bonegajn kromajn funkciojn, kiel videblecon. Anstataŭ kutima klienta biblioteko aŭ injekti vokspurojn en la kodon, ni sendas trafikon al Envoy, kaj ĝi kolektas metrikojn por ni.

Sed Envoy ankaŭ kapablas labori kiel datumaviadilo (datumaviadilo) por la servomaŝo. Ĉi tio signifas, ke Envoy nun estas agordita por ĉi tiu servomaŝo kontrolaviadilo (kontrolaviadilo).

Kontrolaviadilo

Por la kontrolaviadilo, Istio dependas de la Kubernetes API. Ĉi tio ne estas tre malsama ol uzi confd, kiu dependas de etcd aŭ Consul por vidi la aron de ŝlosiloj en la datumvendejo. Istio uzas la Kubernetes API por vidi aron de Kubernetes-resursoj.

Inter ĉi tio kaj tiam: Mi persone trovis ĉi tion utila Kubernetes API-priskribokiu legas:

La Kubernetes API-Servilo estas "stulta servilo" kiu ofertas stokadon, versionadon, validigon, ĝisdatigon kaj semantikon por API-resursoj.

Istio estas desegnita por labori kun Kubernetes; kaj se vi volas uzi ĝin ekster Kubernetes, tiam vi devas ruli ekzemplon de la Kubernetes API-servilo (kaj la helpservo etcd).

Servaj adresoj

Istio fidas je ClusterIP-adresoj kiujn Kubernetes asignas, do Istio-servoj ricevas internan adreson (ne en la intervalo 127.0.0.0/8).

Trafiko al la ClusterIP-adreso por specifa servo en Kubernetes-areto sen Istio estas kaptita de kube-proxy kaj sendita al la backend de tiu prokurilo. Se vi interesiĝas pri la teknikaj detaloj, kube-proxy starigas regulojn de iptables (aŭ IPVS-ŝarĝbalancilojn, depende de kiel ĝi estas agordita) por reverki la celajn IP-adresojn de konektoj irantaj al la ClusterIP-adreso.

Post kiam Istio estas instalita sur Kubernetes-areto, nenio ŝanĝiĝas ĝis ĝi estas eksplicite ebligita por antaŭfiksita konsumanto, aŭ eĉ la tuta nomspaco, enkondukante ujon. sidecar en kutimajn podojn. Ĉi tiu ujo ŝprucos ekzemplon de Envoy kaj starigos aron de iptables-reguloj por kapti trafikon irantan al aliaj servoj kaj redirekti tiun trafikon al Envoy.

Se integrite kun Kubernetes DNS, ĉi tio signifas, ke nia kodo povas konektiĝi per servonomo kaj ĉio "nur funkcias". Alivorte, nia kodo eldonas demandojn kiel http://api/v1/users/4242tiam api solvi peton por 10.97.105.48, la iptables-reguloj kaptos konektojn de 10.97.105.48 kaj plusendos ilin al la loka Envoy-prokurilo, kaj tiu loka prokurilo plusendos la peton al la reala backend API. Huf!

Pliaj luksaĵoj

Istio ankaŭ disponigas fin-al-finan ĉifradon kaj aŭtentikigon per mTLS (reciproka TLS). Komponanto nomita citadelon.

Estas ankaŭ komponanto Miksaĵo, kiun Sendito povas peti ĉiu peto fari specialan decidon pri tiu peto depende de diversaj faktoroj kiel kaplinioj, backend-ŝarĝo, ktp... (ne maltrankviliĝu: ekzistas multaj manieroj por ke Mixer funkcias, kaj eĉ se ĝi kraŝos, Envoy daŭre funkcios). bone kiel prokurilo).

Kaj, kompreneble, ni menciis videblecon: Envoy kolektas grandegan kvanton da metrikoj dum ili provizas distribuitan spuron. En arkitekturo de mikroservoj, se ununura API-peto devas pasi tra mikroservoj A, B, C, kaj D, tiam post ensaluto, distribuita spurado aldonos unikan identigilon al la peto kaj stokos ĉi tiun identigilon per subpetoj al ĉiuj ĉi tiuj mikroservoj, permesante. ĉiuj rilataj vokoj por esti kaptitaj, prokrastoj ktp.

Evoluigi aŭ aĉeti

Istio havas reputacion por esti kompleksa. Kontraste, konstrui la enrutan maŝon, kiun mi priskribis komence de ĉi tiu afiŝo, estas relative simpla uzante ekzistantajn ilojn. Do, ĉu havas sencon krei vian propran servomaŝon anstataŭe?

Se ni havas modestajn bezonojn (ni ne bezonas videblecon, ŝaltilon kaj aliajn subtilaĵojn), tiam pensoj venas por disvolvi nian propran ilon. Sed se ni uzas Kubernetes, ĝi eble eĉ ne bezonas, ĉar Kubernetes jam provizas bazajn ilojn por servo-malkovro kaj ŝarĝoekvilibro.

Sed se ni havas altnivelajn postulojn, tiam "aĉeti" servomaŝo ŝajnas esti multe pli bona elekto. (Ĉi tio ne ĉiam estas "aĉeto" ĉar Istio estas malferma fonto, sed ni ankoraŭ bezonas investi inĝenieran tempon por kompreni, deploji kaj administri ĝin.)

Ĉu mi elektu Istio, Linkerd aŭ Consul Connect?

Ĝis nun ni nur parolis pri Istio, sed ĉi tio ne estas la sola servo-reto. Populara alternativo - Linkerd, kaj estas pli Konsulo Konekti.

Kion elekti?

Verdire, mi ne scias. Nuntempe mi ne konsideras min sufiĉe kompetenta por respondi ĉi tiun demandon. Estas kelkaj interesaj artikoloj kun komparo de ĉi tiuj iloj kaj eĉ benchmarks.

Unu promesplena aliro estas uzi ilon kiel SuperGloo. Ĝi efektivigas abstraktan tavolon por simpligi kaj unuigi la API-ojn elmontritajn per servaj retoj. Anstataŭ lerni la specifajn (kaj, laŭ mi, relative kompleksajn) API-ojn de malsamaj servaj retoj, ni povas uzi la pli simplajn konstrukciojn de SuperGloo - kaj facile ŝanĝi de unu al alia, kvazaŭ ni havus mezan agordan formaton priskribantan HTTP-interfacojn kaj backends kapablajn. de generi la realan agordon por Nginx, HAProxy, Traefik, Apache...

Mi iom okupiĝis pri Istio kaj SuperGloo, kaj en la sekva artikolo mi volas montri kiel aldoni Istio aŭ Linkerd al ekzistanta areto uzante SuperGloo, kaj kiel ĉi-lasta faras la laboron, tio estas, ebligas vin ŝanĝi de. unu servo maŝo al alia sen anstataŭi agordojn.

fonto: www.habr.com

Aldoni komenton