Tinderjeva selitev v Kubernetes

Zapisal: Chris O'Brien, inženirski direktor | Chris Thomas, inženirski vodja | Jinyong Lee, višji programski inženir | Uredil: Cooper Jackson, inženir programske opreme

Zakaj

Pred skoraj dvema letoma se je Tinder odločil, da bo svojo platformo preselil v Kubernetes. Kubernetes nam je omogočil priložnost, da Tinder Engineering usmerimo v smeri kontejnerjev in delovanja z majhnim dotikom s pomočjo nespremenljive uporabe. Gradnja, uporaba in infrastruktura aplikacij bi bili opredeljeni kot koda.

Prav tako smo želeli reševati izzive obsega in stabilnosti. Ko je skaliranje postalo kritično, smo pogosto trpeli v nekaj minutah čakanja, da se novi primeri EC2 pojavijo na spletu. Zamisel o razporejanju zabojnikov in servisiranju prometa v nekaj sekundah nasprotno minutam nas je privlačila.

Ni bilo lahko. Med selitvijo v začetku leta 2019 smo dosegli kritično maso znotraj naše skupine Kubernetes in se začeli srečevati z različnimi izzivi zaradi obsega prometa, velikosti grozdov in DNS. Rešili smo zanimive izzive, da smo preselili 200 storitev in vodili skupino Kubernetes v obsegu 1.000 vozlišč, 15.000 podstavkov in 48.000 tekočih vsebnikov.

Kako

Od januarja 2018 smo se skozi različne stopnje migracijskih prizadevanj lotili svoje poti. Začeli smo s posodabljanjem vseh naših storitev in njihovo razporeditvijo v vrsto Kubernetes, ki gostijo uprizoritvena okolja. Od oktobra smo začeli vse svoje zapuščene storitve preseliti v Kubernetes. Do marca naslednje leto smo zaključili selitev in platforma Tinder zdaj deluje izključno na Kubernetes.

Gradnja slik za Kubernetes

Obstaja več kot 30 skladišč izvorne kode za mikroservise, ki se izvajajo v grozdu Kubernetes. Koda v teh skladiščih je napisana v različnih jezikih (npr. Node.js, Java, Scala, Go) z več okoljskimi okolji za isti jezik.

Sistem gradnje je zasnovan tako, da deluje v popolnoma prilagodljivem „kontekstu gradnje“ za vsako mikroservis, ki običajno sestavlja Dockerfile in niz ukazov lupine. Čeprav je njihova vsebina popolnoma prilagodljiva, so vsi ti konteksti za gradnjo napisani po standardiziranem formatu. Standardizacija kontekstov gradnje omogoča, da en sam sistem sestavljanja upravlja z vsemi mikro storitvami.

Slika 1–1 Standardiziran postopek izdelave skozi vsebnik Builder

Da bi dosegli največjo skladnost med izvajalnimi okolji, se v fazi razvoja in testiranja uporablja isti postopek izdelave. To je naložilo svojevrsten izziv, ko smo morali zasnovati način, kako zagotoviti celostno gradbeno okolje na celotni platformi. Kot rezultat, se vsi procesi izdelave izvedejo v posebnem vsebniku "Builder".

Za izvedbo vsebnika Builder so bile potrebne številne napredne Dockerjeve tehnike. Ta vsebnik Builder podeduje lokalni ID uporabnika in skrivnosti (npr. SSH ključ, AWS poverilnice itd.), Kot je potrebno za dostop do zasebnih skladišč Tinder. V njej so nameščeni lokalni imeniki, ki vsebujejo izvirno kodo, da bi imeli naraven način za shranjevanje umetnin. Ta pristop izboljša zmogljivost, saj odpravlja kopiranje vgrajenih artefaktov med vsebnik Builder in gostiteljskim strojem. Shranjeni artefakti izdelave bodo naslednjič znova uporabljeni brez nadaljnje konfiguracije.

Za določene storitve smo morali v Builderju ustvariti še en vsebnik, da se ujema časovno okolje prevajanja z okoljem izvajanja (npr. Namestitev knjižnice bcrypt Node.js ustvari dvojiške artefakte, specifične za platformo). Zahteve za čas predelave se lahko med storitvami razlikujejo, končni Dockerfile pa je sestavljen na poti.

Kubernetes Gluster Architecture and Migration

Velikost grozda

Odločili smo se uporabiti kube-aws za samodejno zagotavljanje grozdov na primerih Amazon EC2. Zgodaj smo izvajali vse v enem splošnem bazenu vozlišč. Hitro smo prepoznali potrebo po ločevanju delovnih obremenitev na različne velikosti in vrste primerov, da bi bolje izkoristili vire. Obrazložitev je bila, da vodenje manj močnih navojev skupaj daje bolj predvidljive rezultate delovanja, kot pa da jim omogočimo soobstoj z večjim številom enoreznih strokov.

Nastanili smo se na:

  • m5.4velik za spremljanje (Prometej)
  • c5.4 povečanje za Node.js delovno obremenitev (enojni navoj)
  • c5.2 večji za Java in Go (več-navojna obremenitev)
  • c5.4 povečanje za krmilno ravnino (3 vozlišča)

Migracije

Eden od pripravljalnih korakov za prehod iz naše zapuščene infrastrukture na Kubernetes je bil sprememba obstoječe komunikacije med storitvami in opozarjanje na nove elastične uravnotežilnike obremenitve (ELBs), ki so bili ustvarjeni v določenem podomrežju Virtual Private Cloud (VPC). Ta podomrežje je bilo pokukano v Kubernetes VPC. To nam je omogočilo podrobno selitev modulov, ne glede na določeno naročanje za odvisnosti storitev.

Te končne točke so bile ustvarjene z uporabo tehtanih nizov zapisov DNS, ki so CNAME kazali na vsako novo ELB. Za rezanje smo dodali nov zapis, ki kaže na novo storitev Kubernetes ELB, s težo 0. Nato smo na zapisu, ki je nastavljen na 0., postavili čas za življenje (TTL) na 0. Stare in nove uteži smo nato počasi prilagodili na na koncu se na novem strežniku znajde 100%. Po končanem prerezu je bil TTL nastavljen na nekaj bolj smiselnega.

Naši moduli Java so bili deležni nizkega DNS TTL, vendar naše aplikacije Node niso. Eden od naših inženirjev je del kode povezave napisal tako, da je zavit v upravitelja, ki bi osvežil bazene vsakih 60-ih. To se nam je zelo dobro obneslo, saj nismo opazili uspešnosti.

Učenja

Omejitve omrežne tkanine

Tinderjeva platforma je v zgodnjih jutranjih urah 8. januarja 2019 utrpela trajni izpad. Kot odgovor na nepovezano povečanje zamud pri platformi zgodaj zjutraj je bilo na grozdu spremenjeno število pod in vozlišč. To je povzročilo izčrpanje predpomnilnika ARP na vseh naših vozliščih.

Za predpomnilnik ARP obstajajo tri vrednosti Linuxa:

Kredit

gc_thresh3 je trda kapa. Če dobite vnose v dnevnik "sosednja tabela preplavi", to kaže, da tudi po sinhronem zbiranju smeti (GC) predpomnilnika ARP ni bilo dovolj prostora za shranjevanje sosedovega vnosa. V tem primeru jedro v celoti izpusti paket.

Flannel uporabljamo kot mrežno tkanino v Kubernetesu. Paketi se posredujejo prek VXLAN-a. VXLAN je shema prekrivanja nivoja 2 prek omrežja 3. stopnje. Uporablja enkapsulacijo MAC-v-UDP protokola MAC-v-uporabniku, da zagotovi način za razširitev omrežnih segmentov nivoja 2. Protokol prevoza prek fizičnega omrežja podatkovnih centrov je IP plus UDP.

Slika 2–1 Flannel diagram (kredit)

Slika 2–2 VXLAN paket (dobropis)

Vsako delavčevo vozlišče Kubernetes dodeli svoj / 24 virtualnega naslovnega prostora iz večjega / 9 bloka. Za vsako vozlišče to pomeni 1 vnos tabele poti, 1 vnos tabele ARP (na vmesniku flannel.1) in 1 vnos baze podatkov za posredovanje (FDB). Te se dodajo, ko se vozlišče delavca prvič zažene ali ko je odkrito vsako novo vozlišče.

Poleg tega komunikacija od vozlišča do pod (ali pod-do-pod) komunikacija na koncu teče čez vmesnik eth0 (prikazan na Flannel diagramu zgoraj). To bo povzročilo dodaten vnos v tabeli ARP za vsak ustrezen vir vozlišča in cilj vozlišča.

V našem okolju je ta vrsta komunikacije zelo pogosta. Za naše storitvene storitve Kubernetes se ustvari ELB in Kubernetes registrira vsako vozlišče z ELB. ELB se ne zaveda in izbrano vozlišče morda ni končni cilj paketa. To je zato, ker ko vozlišče prejme paket iz ELB, oceni svoja pravila iptables za storitev in naključno izbere pod na drugem vozlišču.

V času izpada je bilo v grozdu skupno 605 vozlišč. Zaradi zgoraj opisanih razlogov je bilo to dovolj za pomrtitev privzete vrednosti gc_thresh3. Ko se to zgodi, ne zapadejo samo paketi, ampak celoten Flannel / 24s virtualnega naslovnega prostora manjka iz ARP tabele. Komunikacija med vozliščem in podmeni DNS ne uspe. (DNS gostuje znotraj grozda, kot bo podrobneje razloženo v tem članku.)

Če želite razrešiti, so vrednosti gc_thresh1, gc_thresh2 in gc_thresh3 dvignjene in Flannel je treba znova zagnati, da ponovno registrira manjkajoča omrežja.

Nepričakovano teče DNS na lestvici

Da bi dosegli naše migracije, smo močno izkoristili DNS za lažje oblikovanje prometa in postopno prekinitev od zapuščine do Kubernetesa za naše storitve. Na pridruženi Route53 RecordSets smo postavili relativno nizke vrednosti TTL. Ko smo zagnali svojo zapuščeno infrastrukturo na primerih EC2, je naša konfiguracija razreševalca kazala na Amazonov DNS. To smo upoštevali kot samoumevno in stroški sorazmerno nizkega TTL za naše storitve in Amazonove storitve (npr. DynamoDB) so v glavnem ostali neopaženi.

Ko smo se vkrcali na vse več storitev Kubernetesu, smo se znašli pri upravljanju storitve DNS, ki je odgovarjala 250.000 zahtevam na sekundo. V naših aplikacijah smo naleteli na vmesne in udarne časovne omejitve iskanja DNS. Do tega je prišlo kljub izčrpnemu prizadevanju za uglasitev in prehodu ponudnika DNS na uvajanje CoreDNS, ki je naenkrat dosegel največ 1.000 strokov in porabil 120 jeder.

Medtem ko smo raziskovali druge možne vzroke in rešitve, smo našli članek, ki opisuje stanje dirke, ki vpliva na okvir netfiltra za filtriranje paketov za paket. Časovne omejitve DNS, ki smo jih videli, skupaj s povečevalnim števcem inser_failed na vmesniku Flannel, ki je usklajen z ugotovitvami članka.

Do težave pride med prevodom izvornih in ciljnih omrežnih naslovov (SNAT in DNAT) in poznejšimi vstavitvami v tabelo za vpenjanje. Ena od rešitev, o kateri se je razpravljalo v notranjosti in ki jo je predlagala skupnost, je bila, da se DNS premakne na delovno vozlišče. V tem primeru:

  • SNAT ni potreben, saj promet ostane lokalno na vozlišču. Ni ga treba posredovati prek vmesnika eth0.
  • DNAT ni potreben, ker je ciljni IP lokalni vozlišču in ni naključno izbran pod za pravila iptables.

Odločili smo se, da bomo s tem pristopom napredovali. CoreDNS smo v Kubernetesu uvedli kot DaemonSet in vbrizgali smo lokalnega strežnika DNS vozlišča v vsak podv. Resv.conf s konfiguriranjem ukazne zastavice kubelet - cluster-dns. Reševanje je bilo učinkovito za časovne omejitve DNS.

Vendar še vedno opazimo izpuščene pakete in prirast vstavljenega števca vmesnika Flannel. To bo trajalo tudi po zgornjem postopku, ker smo se izognili samo SNAT in / ali DNAT za promet z DNS. Stanje dirke se bo še vedno dogajalo pri drugih vrstah prometa. Na srečo je večina naših paketov TCP. Ko se stanje pojavi, bomo pakete uspešno prenesli. Dolgoročno odpravljanje vseh vrst prometa je nekaj, o čemer še vedno razpravljamo.

Uporaba odposlanca za doseganje boljšega uravnoteženja obremenitve

Ko smo selitvene storitve preselili na Kubernetes, smo začeli trpeti zaradi neuravnoteženega bremena na strokih. Odkrili smo, da so se zaradi HTTP Keepalive povezave ELB zataknile za prve pripravljene stroke vsakega valjanega uvajanja, zato je večina prometa tekla skozi majhen odstotek razpoložljivih podstavkov. Eno prvih ublažitev smo poskušali uporabiti 100% MaxSurge pri novih uvajanjih za najhujše kršitelje. To je bilo z nekaterimi večjimi razmejitvami dolgoročno učinkovito in dolgoročno vzdržno.

Druga omilitev je bila, da smo umetno napihnili zahteve po virih za kritične storitve, tako da bi imeli obarvani stroki več prostora poleg drugih težkih strok. To tudi zaradi dolgoročne porabe virov dolgoročno ne bo mogoče zajeti, naše aplikacije Node pa so bile enojne in so tako učinkovito omejene na 1 jedro. Edina jasna rešitev je bila boljše uravnavanje obremenitve.

Notranje smo želeli oceniti odposlanca. To nam je ponudilo priložnost, da ga razmestimo na zelo omejen način in izkoristimo takojšnje koristi. Envoy je odprtokoden, visoko zmogljiv proxy Layer 7, zasnovan za velike storitveno usmerjene arhitekture. Zna izvajati napredne tehnike uravnavanja obremenitve, vključno s samodejnimi poskusi, prekinitvijo vezja in omejitvijo globalne hitrosti.

Konfiguracija, ki smo jo izbrali, je bila, da je poleg vsakega podstavka, ki je imel eno pot in gručo, zadel lokalno pristanišče zabojnikov, stranski voziček odposlanca. Da bi zmanjšali potencialno kaskadno in da bi ohranili majhen polmer eksplozije, smo uporabili floto prednjih proxy strojev Envoy, po eno uvajanje v vsako cono razpoložljivosti (AZ) za vsako storitev. Ti so zadeli majhen mehanizem za odkrivanje storitev, ki ga je sestavil eden izmed naših inženirjev, ki je preprosto vrnil seznam strokov v vsaki AZ za določeno storitev.

Prednji odposlani servisi so nato uporabili ta mehanizem za odkrivanje storitev z enim grozdom navzgor in navzgor. Konfigurirali smo razumne časovne omejitve, povečali vse nastavitve odklopnikov in nato vložili minimalno konfiguracijo poskusa, da bi pomagali pri prehodnih okvarah in gladkih namestitvah. Vsako od teh storitev prednjega odposlanca smo spopadli s TCP ELB. Tudi če so se keepalive iz naše glavne sprednje proxy plasti pripeli na določene stroje Envoy, so veliko bolje obvladovali obremenitev in bili konfigurirani za uravnoteženje z najmanj_request do zaledja.

Za uvajanja smo uporabili kljuko preStop tako na aplikaciji kot na stranskem podstavku. Ta kavelj, imenovan stranska zdravstvena kontrola neuspešne končne točke skrbnika, skupaj z majhnim spanjem, da bi zagotovil nekaj časa, da se omogoči dokončanje in odtekanje povezav za zrakoplov.

Eden od razlogov, da smo se lahko tako hitro premaknili, je bil zaradi bogatih meritev, ki smo jih lahko enostavno integrirali z našo normalno nastavitvijo Prometeja. To nam je omogočilo, da smo natančno videli, kaj se dogaja, ko smo ponavljali nastavitve konfiguracije in zmanjšali promet.

Rezultati so bili takojšnji in očitni. Začeli smo z najbolj neuravnoteženimi storitvami in na tej točki se izvajajo pred dvanajstimi najpomembnejšimi storitvami v našem grozdu. Letos načrtujemo prehod na mrežo s polnimi storitvami z naprednejšim odkrivanjem storitev, prekinitvijo vezja, zunanjim odkrivanjem, omejevanjem hitrosti in sledenjem.

Slika 3–1 konvergenca CPU-ja ene storitve med preselitvijo do odposlanca

Končni rezultat

S pomočjo teh spoznanj in dodatnih raziskav smo razvili močan notranji infrastrukturni tim z veliko znanja o oblikovanju, uvajanju in upravljanju velikih skupin Kubernetes. Celotna inženirska organizacija Tinder ima zdaj znanje in izkušnje o tem, kako skladiščiti in namestiti svoje aplikacije na Kubernetes.

Kadar je bila potrebna dodatna lestvica, smo na svoji zapuščeni infrastrukturi pogosto trpeli v nekaj minutah čakanja, da se novi primeri EC2 pojavijo na spletu. Kontejnerji zdaj načrtujejo in v nekaj sekundah oskrbujejo promet v nasprotju z minutami. Načrtovanje več posod na enem primerku EC2 zagotavlja tudi izboljšano vodoravno gostoto. Zato v letu 2019 načrtujemo znatne prihranke stroškov na EC2 v primerjavi s prejšnjim letom.

Trajalo je skoraj dve leti, vendar smo selitev dokončno zaključili marca 2019. Platforma Tinder deluje izključno na skupini Kubernetes, ki jo sestavlja 200 storitev, 1.000 vozlišč, 15.000 podstavkov in 48.000 tekočih zabojnikov. Infrastruktura ni več naloga, rezervirana za naše operativne skupine. Namesto tega inženirji v celotni organizaciji delijo to odgovornost in nadzorujejo, kako so njihove aplikacije zgrajene in nameščene z vsem kot kodo.