Tinderio persikėlimas į Kubernetes

Parašė: Chrisas O'Brienas, inžinerijos vadovas | Chrisas Tomas, inžinerijos vadovas | Jinyong Lee, vyresnysis programinės įrangos inžinierius | Redagavo: Cooperis Jacksonas, programinės įrangos inžinierius

Kodėl

Beveik prieš dvejus metus „Tinder“ nusprendė perkelti savo platformą į „Kubernetes“. „Kubernetes“ suteikė mums galimybę paskatinti „Tinder Engineering“ kurti konteinerius ir valdyti mažu prisilietimu per nekintamą dislokavimą. Programų kūrimas, diegimas ir infrastruktūra būtų apibrėžti kaip kodas.

Mes taip pat siekėme spręsti masto ir stabilumo iššūkius. Kai mastelio keitimas tapo kritinis, mes dažnai kentėdavome kelias minutes laukdami naujų EC2 pavyzdžių prisijungimo internete. Idėja konteinerius planuoti ir aptarnauti eismą per kelias sekundes, o ne minutes, mus patraukė.

Tai nebuvo lengva. Migracijos metu 2019 m. Pradžioje pasiekėme kritinę masę savo „Kubernetes“ klasteryje ir pradėjome susidurti su įvairiais iššūkiais dėl srauto apimties, klasterio dydžio ir DNS. Mes išsprendėme įdomius iššūkius, susijusius su 200 paslaugų perkėlimu ir „Kubernetes“ klasterio valdymu, viso masto 1000 mazgų, 15 000 pod'ų ir 48 000 veikiančių konteinerių.

Kaip

Nuo 2018 m. Sausio mėn. Atlikome įvairius migracijos pastangų etapus. Pradėjome talpindami visas savo paslaugas ir diegdami jas serijoje „Kubernetes“ rengiamų inscenizacijos aplinkų. Nuo spalio mėnesio mes metodiškai pradėjome perkelti visas mūsų senas paslaugas į „Kubernetes“. Iki kitų metų kovo mėn. Mes baigėme migraciją ir „Tinder“ platforma dabar veikia tik „Kubernetes“.

„Kubernetes“ pastatų vaizdai

Yra daugiau nei 30 šaltinio kodo saugyklų, skirtų mikroservisams, kurie veikia „Kubernetes“ klasteryje. Kodas šiose saugyklose parašytas skirtingomis kalbomis (pvz., „Node.js“, „Java“, „Scala“, „Go“) su keliomis tos pačios kalbos vykdymo aplinkomis.

Versijos kūrimo sistema yra sukurta veikti visiškai pritaikomame kiekvienos mikroserviso „kūrimo kontekste“, kurį paprastai sudaro „Dockerfile“ ir apvalkalo komandos. Nors jų turinį galima visiškai pritaikyti, visi šie kontekstai yra rašomi laikantis standartizuoto formato. Standartizuojant konstravimo kontekstus, viena konstravimo sistema gali valdyti visas mikro paslaugas.

1–1 pav. Standartizuotas kūrimo procesas per „Builder“ konteinerį

Norint pasiekti maksimalų suderinamumą tarp vykdomosios aplinkos, kūrimo ir bandymo etapuose naudojamas tas pats kūrimo procesas. Tai kėlė unikalų iššūkį, kai mums reikėjo surasti būdą, kaip užtikrinti nuoseklią visos platformos kūrimo aplinką. Dėl to visi kūrimo procesai vykdomi specialiame „Builder“ konteineryje.

„Builder“ talpyklos įgyvendinimui reikėjo daugybės pažangių „Docker“ metodų. Šis „Builder“ konteineris paveldi vietinį vartotojo ID ir paslaptis (pvz., SSH raktas, AWS kredencialai ir kt.), Kurių reikia norint pasiekti „Tinder“ privačias saugyklas. Jis sujungia vietinius katalogus, kuriuose yra šaltinio kodas, kad būtų natūralus būdas kaupti artefaktus. Šis požiūris pagerina našumą, nes jis pašalina pastatytų artefaktų kopijavimą iš „Builder“ talpyklos ir pagrindinio kompiuterio. Saugomi kūrinių artefaktai bus naudojami pakartotinai kitą kartą be papildomos konfigūracijos.

Tam tikroms paslaugoms mums reikėjo sukurti kitą konteinerį „Builder“ programoje, kad kompiliavimo laiko aplinka atitiktų vykdymo laiko aplinką (pvz., Diegdami „Node.js bcrypt“ biblioteką, generuojame dvejetainius specifinius platformos artefaktus). Reikalavimai kompiliacijai gali skirtis skirtingose ​​tarnybose, o galutinis „Dockerfile“ yra sudaromas skrendant.

Kubernetes klasterio architektūra ir migracija

Klasterio dydis

Nusprendėme naudoti „kube-aws“ automatiniam klasterių aprūpinimui „Amazon EC2“ atvejais. Anksčiau mes viską vykdėme viename bendro mazgo baseine. Greitai nustatėme poreikį atskirti darbo krūvius pagal įvairaus dydžio ir tipų egzempliorius, kad būtų geriau naudojami ištekliai. Priežastis buvo ta, kad važiavimas mažiau sunkiai sriegiuotų ankščių mums davė labiau nuspėjamų našumo rezultatų, nei leidžiant joms kartu egzistuoti su didesniu skaičiumi srieginių ankščių.

Mes apsigyvenome:

  • m5.4xxdidelis stebėjimui (Prometheus)
  • „c5.4xlarge“, skirta „Node.js“ darbo krūviui (vieno sriegio darbo krūvis)
  • „Java“ ir „Go“ „c5.2xx“ (daugiapakopis darbo krūvis)
  • c5.4xxdidelis valdymo plokštumas (3 mazgai)

Migracija

Vienas iš parengiamųjų žingsnių perkėlimui iš mūsų senosios infrastruktūros į „Kubernetes“ buvo pakeisti esamą paslaugų tarpusavio ryšį, kad jis nukreiptų į naujus tamprius apkrovos balansorius (ELB), kurie buvo sukurti konkrečiame „Virtual Private Cloud“ (VPC) potinklyje. Šis potinklis buvo nukreiptas į „Kubernetes“ VPC. Tai leido mums išsamiai perkelti modulius neatsižvelgdami į konkretų paslaugų priklausomybių užsakymą.

Šie galiniai taškai buvo sukurti naudojant svertinius DNS įrašų rinkinius, kurių CNAME nukreipė į kiekvieną naują ELB. Norėdami pakeisti, mes pridėjome naują įrašą, rodydami į naująją „Kubernetes“ tarnybos ELB, kurios svoris yra 0. Tada įrašo metu nustatėme, kad laikas gyventi (TTL) yra 0. Senas ir naujas svoriai pamažu buvo sureguliuoti iki galiausiai naujame serveryje galiausiai pasieksite 100 proc. Po to, kai buvo baigtas perkėlimas, TTL buvo nustatytas kažkas protingesnio.

Mūsų „Java“ moduliai pagerino žemą DNS TTL, tačiau mūsų „Node“ programos to nepadarė. Vienas iš mūsų inžinierių perrašė dalį jungimo fondo kodo, kad įvyniotų jį į tvarkyklę, kuri atnaujintų baseinus kas 60-tą. Tai labai gerai pasitarnavo be jokio pastebimo spektaklio.

Mokymai

Tinklo audinio ribos

Ankstyvu 2019 m. Sausio 8 d. Rytu „Tinder's Platform“ patyrė nuolatinį gedimą. Reaguojant į nesusijusį platformos delsos padidėjimą anksčiau tą rytą, pultų ir mazgų skaičius buvo sumažintas klasteryje. Dėl to ARP talpykla buvo išnaudota visuose mūsų mazguose.

ARP talpykloje yra trys „Linux“ vertės:

Kreditas

„gc_thresh3“ yra kietas dangtelis. Jei gaunate „kaimynų lentelės perpildymo“ žurnalo įrašus, tai rodo, kad net ir po sinchroninio ARP talpyklos šiukšlių rinkimo (GC) nebuvo pakankamai vietos kaimyno įrašui laikyti. Tokiu atveju branduolys tiesiog numeta paketą.

Mes naudojame „Flannel“ kaip savo tinklo audinį „Kubernetes“. Paketai persiunčiami per VXLAN. VXLAN yra 2 sluoksnio perdangos schema per 3 sluoksnio tinklą. Jis naudoja MAC adresų-vartotojo duomenų diagramos (MAC-in-UDP) kapsulę, kad suteiktų galimybę išplėsti 2 sluoksnio tinklo segmentus. Perdavimo protokolas per fizinio duomenų centro tinklą yra IP ir UDP.

2–1 pav. Flanelio schema (kreditas)

2–2 pav. VXLAN paketas (kreditas)

Kiekvienas „Kubernetes“ darbuotojo mazgas paskiria savo / 24 virtualių adresų erdvę iš didesnio / 9 bloko. Kiekvienam mazgui gaunamas 1 maršruto lentelės įrašas, 1 ARP lentelės įrašas (flannel.1 sąsajoje) ir 1 persiuntimo duomenų bazės (FDB) įrašas. Jie pridedami pirmą kartą paleidus darbuotojo mazgą arba atrandant kiekvieną naują mazgą.

Be to, „node-to-pod“ (arba „pod-to-pod“) komunikacija galiausiai pereina per eth0 sąsają (pavaizduota aukščiau esančioje flanelės schemoje). Dėl to ARP lentelėje bus pateiktas papildomas įrašas kiekvienam atitinkamam mazgo šaltiniui ir mazgo vietai.

Mūsų aplinkoje toks bendravimo būdas yra labai paplitęs. Mūsų „Kubernetes“ paslaugų objektams yra sukuriamas ELB, o „Kubernetes“ registruoja kiekvieną mazgą naudodamas ELB. ELB nėra žinomas duomenų kaupiklyje, o pasirinktas mazgas gali būti ne paketo galutinė paskirtis. Taip yra todėl, kad mazgas, gavęs paketą iš ELB, įvertina savo iptable tarnybos taisykles ir atsitiktinai pasirenka podsą kitame mazge.

Nutraukimo metu klasteryje buvo iš viso 605 mazgai. Dėl aukščiau nurodytų priežasčių to pakako užtemdyti numatytąją „gc_thresh3“ vertę. Kai tai atsitiks, ARP lentelėje trūksta ne tik paketų, bet ir visos „Flannel“ / 24 virtualiosios adresų erdvės. Nepavyksta sujungti mazgo ir DNS paieškų. (DNS yra priglobtas klasteryje, kaip bus išsamiau paaiškinta vėliau šiame straipsnyje.)

Norėdami išspręsti, padidinamos „gc_thresh1“, „gc_thresh2“ ir „gc_thresh3“ vertės, o norint iš naujo užregistruoti trūkstamus tinklus, reikia paleisti „Flanel“.

Netikėtai veikia DNS masteliu

Norėdami patenkinti mūsų migraciją, mes labai pasinaudojome DNS, kad palengvintume srauto formavimą ir laipsnišką mūsų paslaugų perkėlimą iš palikimo į „Kubernetes“. Mes nustatėme palyginti žemas TTL reikšmes susijusiose „Route53 RecordSets“. Kai vykdėme senąją infrastruktūrą EC2 egzemplioriuose, mūsų sprendimo konfigūracija atkreipė dėmesį į „Amazon“ DNS. Mes tai priėmėme kaip savaime suprantamą dalyką ir palyginti mažos mūsų paslaugų ir „Amazon“ paslaugų (pvz., „DynamoDB“) TTL kainos beveik nepastebėtos.

Pristatydami vis daugiau ir daugiau paslaugų „Kubernetes“, mes atradome saugančią DNS paslaugą, atsakančią į 250 000 užklausų per sekundę. Savo programose mes susidūrėme su pertraukiamais ir įtakingais DNS paieškos taškais. Tai įvyko nepaisant išsamių derinimo pastangų ir DNS tiekėjo perėjimo prie „CoreDNS“ diegimo, kuris vienu metu pasiekė aukščiausią 1000 pultų, sunaudojančių 120 šerdžių.

Tyrinėdami kitas galimas priežastis ir sprendimus, aptikome straipsnį, kuriame aprašomos lenktynių sąlygos, turinčios įtakos „Linux“ paketų filtravimo sistemos „netfilter“. DNS laikai, kuriuos mes matėme, kartu su didėjančiu „insert_failed“ skaitikliu Flanelio sąsajoje, suderinti su straipsnio išvadomis.

Problema kyla šaltinio ir paskirties tinklo adresų vertimo (SNAT ir DNAT) metu ir vėliau įdedant į „conntrack“ lentelę. Vienas iš vidaus aptariamų ir bendruomenės pasiūlytų būdų buvo perkelti DNS į patį darbuotojo mazgą. Tokiu atveju:

  • SNAT nėra būtinas, nes srautas vyksta vietoje mazgo. Jo nereikia perduoti per eth0 sąsają.
  • DNAT nėra būtinas, nes paskirties IP yra vietinis mazgui, o ne atsitiktinai pasirinktas pod pagal „iptable“ taisykles.

Mes nusprendėme judėti pirmyn laikydamiesi šio požiūrio. „CoreDNS“ buvo įdiegtas kaip „DaemonSet“ „Kubernetes“ tinkle ir mes įpurškėme mazgo vietinį DNS serverį į kiekvieno pulto rezoliuciją.conf, sukonfigūravę „kubelet - cluster-dns“ komandos vėliavą. Šis būdas buvo efektyvus DNS pertraukoms.

Tačiau vis tiek matome numestus paketus ir Flanel sąsajos įterpimo_pavykusio skaitiklio prieaugį. Tai išliks net ir po minėto sprendimo, nes DNS srautui vengėme tik SNAT ir (arba) DNAT. Lenktynių sąlygos vis tiek išliks kitokio tipo eismui. Laimei, dauguma mūsų paketų yra TCP ir, kai susidaro tokia sąlyga, paketai bus sėkmingai perduoti. Ilgalaikis visų tipų srautų nustatymas yra tai, apie ką vis dar diskutuojame.

„Envoy“ naudojimas geresniam apkrovos balansavimui pasiekti

Perkėlę savo „backend“ paslaugas į „Kubernetes“, mes pradėjome kentėti nuo nesubalansuoto krūvio tarp ankščių. Mes sužinojome, kad dėl „HTTP Keepalive“ ELB jungtys prilipo prie kiekvieno paruošto dislokavimo pirmojo paruošto paketo, todėl didžioji dalis srauto vyko per nedidelę procentą turimų podsų. Vienas iš pirmųjų sušvelninimų, kurį mes bandėme, buvo naudoti 100% „MaxSurge“ naujiems dislokavimams blogiausiems pažeidėjams. Kai kurių didesnių dislokacijų atveju tai buvo mažai veiksminga ir netvari ilgalaikė perspektyva.

Kitas sušvelninimas, kurį mes panaudojome, buvo dirbtinai išpūsti išteklių prašymai dėl kritinių paslaugų, kad išsidėstę ankštys turėtų daugiau erdvės kartu su kitomis sunkiomis ankštimis. Ilgainiui tai taip pat netaps tinkama dėl išteklių eikvojimo, o mūsų mazgo programos buvo sujungtos sriegiu ir tokiu būdu buvo efektyviai uždengtos vienu branduoliu. Vienintelis aiškus sprendimas buvo panaudoti geresnį apkrovos balansavimą.

Mes iš vidaus siekėme įvertinti pasiuntinį. Tai mums suteikė galimybę labai ribotai panaudoti ir gauti tiesioginę naudą. „Envoy“ yra atvirojo kodo, didelio našumo „Layer 7“ įgaliotasis serveris, skirtas didelėms į paslaugas orientuotoms architektūroms. Jis sugeba įgyvendinti pažangias apkrovos balansavimo technikas, įskaitant automatinius pakartojimus, grandinės nutraukimą ir visuotinę normos ribojimą.

Konfigūracija, kurią mes sugalvojome, turėjo turėti „Envoy“ priekabą prie kiekvieno podiumo, kuris turėjo vieną maršrutą ir grupę, kad pasiektų vietinį konteinerių uostą. Siekdami sumažinti galimą kaskadą ir išlaikyti mažą pūtimo spindulį, mes panaudojome priekinių įgaliotųjų Envoy pultų paketą, po vieną dislokavimą kiekvienoje prieinamumo zonoje (AZ) kiekvienai paslaugai. Jie susidūrė su nedideliu paslaugų aptikimo mechanizmu, kurį sudėjo vienas iš mūsų inžinierių ir kuris paprasčiausiai grąžino kiekvienos AZ talpyklų sąrašą tam tikrai paslaugai.

Tada tarnybos fronto pasiuntiniai panaudojo šį paslaugų aptikimo mechanizmą su viena aukščiau esančia grupe ir maršrutu. Sukonfigūravome pagrįstus laiko intervalus, padidinome visus grandinės pertraukiklio parametrus ir įdiegėme minimalią pakartotinės konfigūracijos konfigūraciją, kad padėtume dėl trumpalaikių gedimų ir sklandaus diegimo. Kiekvieną iš šių priekinių pasiuntinių paslaugų mes apjungėme TCP ELB. Net jei mūsų pagrindinio įgaliotojo serverio sluoksnio atsargos buvo pritvirtintos prie tam tikrų „Envoy“ pultų, jie daug geriau sugebėjo valdyti apkrovą ir buvo sukonfigūruoti išlaikyti pusiausvyrą per „mažiausias_prašymas“ užpakalinę dalį.

Diegdami mes panaudojome „PreStop“ kabliuką tiek programoje, tiek priekabos šonuose. Šis kabliukas, vadinamas šalutinio automobilio sveikatos patikrinimu, nepavyko pasiekti galutinio taško kartu su mažu miegu, kad būtų galima šiek tiek laiko leisti skrydžio jungtims baigtis ir nutekėti.

Viena iš priežasčių, kodėl mes sugebėjome judėti taip greitai, buvo dėl gausios metrikos, kurią lengvai galėjome integruoti įprastoje „Prometheus“ sąrankoje. Tai leido mums tiksliai pamatyti, kas vyksta, kartodamiesi konfigūracijos parametrais ir mažindami srautą.

Rezultatai buvo tiesioginiai ir akivaizdūs. Pradėjome nuo labiausiai nesubalansuotų paslaugų ir šiuo metu galime pateikti jas prieš dvylika svarbiausių mūsų grupės paslaugų. Šiais metais planuojame pereiti prie visos paslaugos tinklo, kuriame yra pažangesnis paslaugų aptikimas, grandinės nutraukimas, pašalinių atvejų aptikimas, greičio ribojimas ir sekimas.

3–1 pav. Vienos tarnybos CPU suartėjimas per pasiuntinį

Pabaigos rezultatas

Pasitelkę šiuos mokymus ir atlikdami papildomus tyrimus, sukūrėme stiprią vidinės infrastruktūros komandą, puikiai suprantančią, kaip kurti, diegti ir valdyti dideles „Kubernetes“ grupes. Visa „Tinder“ inžinerinė organizacija dabar turi žinių ir patirties, kaip sudėti ir diegti jų programas „Kubernetes“.

Kai reikėjo papildomos apimties, palikdami savo senąją infrastruktūrą, mes dažnai kentėdavome kelias minutes laukdami naujų EC2 pavyzdžių prisijungimo internete. Dabar konteineriai planuoja ir aptarnauja eismą per kelias sekundes, o ne minutes. Planuodami kelis konteinerius viename EC2 pavyzdyje, taip pat pagerinsite horizontalųjį tankį. Todėl mes planuojame, kad 2019 m., Palyginti su ankstesniais metais, bus sutaupytos EC2 išlaidos.

Tai užtruko beveik dvejus metus, tačiau perėjimą baigėme 2019 m. Kovo mėn. „Tinder“ platforma veikia išskirtinai „Kubernetes“ klasteryje, kurį sudaro 200 paslaugų, 1 000 mazgų, 15 000 pultų ir 48 000 veikiančių konteinerių. Infrastruktūra nebėra užduotis, skirta tik mūsų operacijų komandoms. Vietoj to, visos organizacijos inžinieriai dalijasi šia atsakomybe ir kontroliuoja, kaip jų programos yra kuriamos ir diegiamos, kaip viskas.