Tinderi kolimine Kubernetesesse

Kirjutas: Chris O'Brien, insenerijuht | Chris Thomas, insenerijuht | Jinyong Lee, vanem tarkvarainsener | Toimetanud: Cooper Jackson, tarkvarainsener

Miks

Peaaegu kaks aastat tagasi otsustas Tinder oma platvormi kolida Kubernetesesse. Kubernetes andis meile võimaluse juhtida Tinder Engineeringi konteinerite koondamise ja vähese puutega töötamise poole muutumatu juurutamise kaudu. Rakenduste loomine, juurutamine ja infrastruktuur määratletakse koodina.

Samuti otsisime lahendusi mastaabi- ja stabiilsusprobleemidele. Kui skaleerimine muutus kriitiliseks, kannatasime sageli mitu minutit uute EC2 eksemplaride võrku tuleku ootamisega. Konteinerite sõiduplaani koostamise ja teenindamise idee sekunditega, mitte minutitega, meeldis meile.

See polnud lihtne. 2019. aasta alguses toimunud rände ajal jõudsime oma Kubernetesi klastris kriitilise massini ja hakkasime vastama mitmesugustele väljakutsetele seoses liikluse mahu, klastri suuruse ja DNS-iga. Lahendasime huvitavad väljakutsed 200 teenuse migreerimiseks ja Kubernetes'i klastri käitamiseks, mille maht on kokku 1000 sõlme, 15 000 podsi ja 48 000 jooksvat konteinerit.

Kuidas

Alates jaanuarist 2018 töötasime läbi rände eri etappide. Alustasime kõigi oma teenuste koondamise ja nende juurutamisega mitmesse Kubernetes'i hostitud lavastuskeskkonda. Oktoobri algusest hakkasime metoodiliselt kõiki meie pärandteenuseid Kubernetesesse viima. Järgmise aasta märtsiks viisime oma migratsiooni lõpule ja Tinderi platvorm töötab nüüd eranditult Kubernetes.

Kubernetese piltide ehitamine

Kubernetesi klastris töötavatele mikroteenustele on enam kui 30 lähtekoodi hoidlat. Nendes hoidlates olev kood on kirjutatud erinevates keeltes (nt Node.js, Java, Scala, Go), sama keele jaoks on mitu käituskeskkonda.

Ehitussüsteem on loodud töötama iga mikroteenuse jaoks täielikult kohandatava „ehitamise kontekstiga”, mis koosneb tavaliselt Dockerfilest ja kesta käskudest. Ehkki nende sisu on täielikult kohandatav, kirjutatakse kõik ehituse kontekstid standardiseeritud vormingut järgides. Koostamiskontekstide standardiseerimine võimaldab kõigil mikroteenustel hallata ühte ehitamissüsteemi.

Joonis 1–1 Standardiseeritud ehitamisprotsess läbi Builderi konteineri

Maksimaalse järjepidevuse saavutamiseks käituskeskkondade vahel kasutatakse arendus- ja testimisfaasis sama ehitamisprotsessi. See nõudis ainulaadset väljakutset, kui pidime leidma viisi, kuidas tagada kogu platvormi vältel ühtne ehituskeskkond. Selle tulemusel viiakse kõik ehitamisprotsessid läbi spetsiaalses konteineris „Ehitaja“.

Konteineri Builder juurutamine nõudis mitmeid edasijõudnute Dockeri tehnikaid. See ehitaja konteiner pärib kohaliku kasutaja ID ja saladused (nt SSH-võti, AWS-i mandaadid jne), nagu on vaja Tinderi privaatsetele andmehoidlatele juurde pääsemiseks. See ühendab lähtekoodi sisaldavad kohalikud kataloogid, et loomulik viis ehitada esemete salvestamiseks. See lähenemisviis parandab jõudlust, kuna see välistab ehitatud esemete kopeerimise Builderi konteineri ja hostmasina vahel. Salvestatud ehituse esemeid kasutatakse järgmisel korral ilma täiendava konfigureerimiseta.

Teatud teenuste jaoks pidime ehitajas Builder looma uue konteineri, et sobitada kompileerimise aja keskkond käitusaja keskkonnaga (nt Node.js bcrypt teegi installimine genereerib platvormispetsiifilised binaarsed artefaktid). Kompileerimisaja nõuded võivad teenustes erineda ja lõplik Dockerfail koostatakse lennult.

Kubernetesi klastri arhitektuur ja ränne

Klastri suurus

Otsustasime kasutada kube-aws automaatse klastri varustamiseks Amazon EC2 eksemplaridel. Varem töötasime kõik ühes sõlmpunktis. Tuvastasime kiiresti vajaduse ressursside paremaks kasutamiseks eraldada töökoormused erineva suuruse ja tüüpi eksemplarideks. Põhjenduseks oli see, et vähem tugevalt keermestatud kaunade koos jooksmine andis meie jaoks ettearvatavamaid jõudlustulemusi kui see, kui lasime neil eksisteerida suurema arvu ühekeermeliste kaunadega.

Me otsustasime:

  • m5.4xlarge jälgimiseks (Prometheus)
  • c5.4xlarge Node.js töökoormuse jaoks (ühe keermega töökoormus)
  • c5.2xlarge Java ja Go jaoks (mitme keermega töökoormus)
  • c5.4suur kontrolltasapind (3 sõlme)

Ränne

Meie ettevalmistatud infrastruktuurilt Kubernetesisse ülemineku üks ettevalmistavaid samme oli olemasoleva teenuse-teenuse kommunikatsiooni muutmine, et osutada uutele elastsetele koormuse tasakaalustajatele (ELB), mis loodi konkreetses virtuaalse privaatpilve (VPC) alamvõrgus. See alamvõrk oli ühendatud Kubernetes VPC-ga. See võimaldas meil mooduleid granuleeritult üle viia, arvestamata konkreetset tellimust teenuse sõltuvuse jaoks.

Need lõpp-punktid loodi, kasutades kaalutud DNS-i kirjekomplekte, mille CNAME osutas igale uuele ELB-le. Üleminekuks lisasime uue rekordi, osutades uuele Kubernetes-i teenuse ELB-le, kaaluga 0. Seejärel seadsime aja järgi elamiseks (TTL) kirjele 0. Seejärel kohandati vanad ja uued kaalud aeglaselt lõpuks uues serveris lõpuks 100%. Pärast ülemineku lõppu seati TTL millekski mõistlikumaks.

Meie Java moodulid austasid madalat DNS-i TTL-i, kuid meie sõlmerakendused seda ei teinud. Üks meie inseneridest kirjutas osa ühenduse basseini koodist ümber, et mähkida see haldurisse, mis värskendaks basseine iga 60. aasta tagant. See toimis meie jaoks väga hästi, ilma et oleks saavutatud märkimisväärset tulemuslikkust.

Õppimine

Võrgu kanga piirangud

8. jaanuari 2019. aasta varahommikutundidel kannatas Tinderi platvorm püsiva seisakut. Vastusena platvormi latentsuse sõltumatule suurenemisele juba sel hommikul skaalal poodide ja sõlmede arv klastris. Selle tulemuseks oli ARP vahemälu ammendumine kõigis meie sõlmedes.

ARP-vahemälu jaoks on kolm Linuxi väärtust:

Krediit

gc_thresh3 on kõva kork. Kui saate sissekandeid naabrilaua ületäitumise kohta, näitab see, et isegi pärast ARP-vahemälu sünkroonset prügikoristamist (GC) polnud naabrikirje salvestamiseks piisavalt ruumi. Sel juhul laseb kernel paketi täielikult maha.

Kubernetes kasutame oma võrgukangana Flannelit. Paketid edastatakse VXLAN-i kaudu. VXLAN on 2. kihi ülekatteskeem 3. kihi võrgus. 2. kihi võrgusegmentide laiendamiseks kasutab see MAC-aadressi-kasutaja andmegrammi protokolli (MAC-in-UDP) kapseldamist. Füüsilise andmekeskuse võrgu ülekandeprotokoll on IP pluss UDP.

Joonis 2–1 Flanelli skeem (krediit)

Joonis 2–2 VXLAN-i pakett (krediit)

Iga Kubernetes'i töötaja sõlmpunkt eraldab suuremast / 9 plokist oma / 24 virtuaalse aadressiruumi. Iga sõlme jaoks on tulemuseks 1 marsruuditabeli kirje, 1 ARP-tabeli kirje (flannel.1 liidesel) ja 1 edastatava andmebaasi (FDB) kirje. Need lisatakse töötaja sõlme esmakordsel käivitamisel või iga uue sõlme avastamisel.

Lisaks voolab sõlme-to-pod (ehk pod-to-pod) suhtlus lõpuks üle eth0-liidese (kujutatud ülaltoodud flanelli diagrammil). Selle tulemuseks on ARP-tabelis täiendav kirje iga vastava sõlme allika ja sõlme sihtkoha kohta.

Meie keskkonnas on seda tüüpi suhtlus väga levinud. Meie Kubernetesi teenuseobjektide jaoks luuakse ELB ja Kubernetes registreerib kõik sõlmed ELB-ga. ELB pole pod-teadlik ja valitud sõlm ei pruugi olla paketi lõppsihtkoht. Selle põhjuseks on asjaolu, et kui sõlm saab paketi ELB-st, hindab ta selle iptable teenuse reegleid ja valib juhuslikult teise sõlme kausta.

Elektrikatkestuse ajal oli klastris kokku 605 sõlme. Ülaltoodud põhjustel piisas sellest gc_thresh3 vaikeväärtuse varjamiseks. Kui see juhtub, ei kaota mitte ainult pakette, vaid ka ARP-tabelist puuduvad terved virtuaalse aadressiruumi Flannel / 24-d. Tasku sõlmeside ja DNS-i otsingud nurjuvad. (DNS-i hostitakse klastris, nagu selgitatakse üksikasjalikumalt käesolevas artiklis.)

Lahendamiseks tõstetakse väärtused gc_thresh1, gc_thresh2 ja gc_thresh3 ning puuduvate võrkude uuesti registreerimiseks tuleb taaskäivitada Flanell.

Ootamatult töötab DNS skaalal

Meie rände mahutamiseks võtsime DNS-i tugevalt kasutusele, et hõlbustada meie teenuste liikluse kujundamist ja järkjärgulist üleminekut pärandist Kubernetesesse. Seadsime seotud Route53 RecordSets-is suhteliselt madalad TTL-väärtused. Kui käitasime pärandinfrastruktuuri EC2 eksemplaridel, osutas meie eraldusvõimega konfiguratsioon Amazoni DNS-ile. Me võtsime seda enesestmõistetavana ja suhteliselt madala TTL-i hind meie teenustele ja Amazoni teenustele (nt DynamoDB) jäi suuresti märkamata.

Arvestades üha enam Kubernetesesse osutatavaid teenuseid, leidsime end käitamas DNS-teenust, mis vastas 250 000 päringule sekundis. Me leidsime oma rakendustes vahelduvaid ja mõjuvaid DNS-i otsingu aegumisi. See leidis aset hoolimata ammendavast häälestamispingutusest ja DNS-i pakkuja lülitumisest CoreDNS-i juurutamisele, mis saavutas korraga maksimumi 1000 pigi juures, mis tarbisid 120 südamikku.

Teisi võimalikke põhjuseid ja lahendusi uurides leidsime artikli, milles kirjeldatakse rassitingimusi, mis mõjutavad Linuxi pakettide filtreerimise raamistiku netfiltrit. Meie nähtavad DNS-aegumised koos flanelliidese liidese insert_failed kasvava loenduriga, joondatud artikli leidudega.

Probleem ilmneb lähte- ja sihtkoha võrgu aadressi tõlkimisel (SNAT ja DNAT) ning sellele järgneval Conntracki tabelisse sisestamisel. Üks sisemiselt arutatud ja kogukonna poolt välja pakutud lahendus oli DNS-i teisaldamine töötaja sõlme. Sel juhul:

  • SNAT pole vajalik, kuna liiklus püsib sõlmes kohapeal. Seda ei pea edastama kogu eth0-liidese kaudu.
  • DNAT pole vajalik, kuna sihtkoha IP on sõlme kohalik ja mitte juhuslikult valitud pup iptable'i reeglite järgi.

Otsustasime selle lähenemisega edasi liikuda. CoreDNS juurutati Kuberneteses DaemonSetina ja me süstisime sõlme kohaliku DNS-serveri iga puldi resolv.conf-i, konfigureerides kubelet - klastri-dns-i käsu lippu. Lahendus oli DNS-aegumiste jaoks efektiivne.

Kuid ikkagi näeme langenud pakette ja Flanelli liidese insert_failed loenduri juurdekasvu. See püsib ka pärast ülaltoodud lahendust, sest DNS-liikluse jaoks vältisime ainult SNAT-i ja / või DNAT-i. Võistlustingimused esinevad endiselt muud tüüpi liikluse korral. Õnneks on suurem osa meie pakettidest TCP ja kui olukord ilmneb, edastatakse need edukalt. Igasuguse liikluse pikaajaline parandamine on asi, mida me veel arutame.

Saadiku kasutamine parema koormuse tasakaalustamise saavutamiseks

Kui rändasime oma taustateenuseid Kubernetesesse, hakkasime kannatama tasakaalustamata koorma vahel. Avastasime, et HTTP Keepalive'i tõttu kleepusid ELB ühendused iga veeremise juurutamise esimestesse valmistahvlitesse, nii et suurem osa liiklusest voolas läbi väikese protsendi saadaolevatest kaustadest. Üks esimesi leevendusi, mida proovisime, oli 100% MaxSurge'i kasutamine uutes juurutustes halvimate rikkujate jaoks. Mõne suurema suurema kasutuselevõtu korral oli see minimaalselt tõhus ega olnud pikaajaliselt jätkusuutlik.

Teine leevendamine, mida kasutasime, oli kriitiliste teenuste ressursitaotluste kunstlik suurendamine, nii et paigutatud kaustadel oleks teiste raskete kaustade kõrval rohkem ruumi. Ka ressursside raiskamise tõttu ei olnud see pikas perspektiivis vastuvõetav ja meie sõlmerakendused olid ühe keermega ja seega ühe südamiku piires. Ainus selge lahendus oli parema koorma tasakaalustamise kasutamine.

Me olime sisemiselt otsinud saadikut hinnata. See andis meile võimaluse seda väga piiratud viisil kasutada ja saada sellest kohe kasu. Envoy on avatud lähtekoodiga ja suure jõudlusega Layer 7 puhverserver, mis on loodud suurte teenustele orienteeritud arhitektuuride jaoks. See on võimeline rakendama täiustatud koormuse tasakaalustamise tehnikaid, sealhulgas automaatne uuesti proovimine, vooluringide katkemine ja globaalse kiiruse piiramine.

Konfiguratsioon, mille me välja pakkusime, pidi omama iga saadiku külgkorvi, millel oli üks marsruut ja klaster, et kohalikku konteineriporti tabada. Võimaliku kaskaadrežiimi minimeerimiseks ja väikese lööklaine raadiuse hoidmiseks kasutasime eesmise puhverserveri Envoy poodide parki, üks juurutusvõimalus tsoonis (AZ) iga teenuse jaoks. Need tabasid väikest teenuse avastamise mehhanismi, mille üks meie insener kokku pani ja tagastati lihtsalt iga teenuse AZ-s olevate poodiumide nimekiri.

Seejärel kasutasid teenuse esisaadikud seda teenuse avastamise mehhanismi ühe ülesvoolu klastri ja marsruudiga. Seadistasime mõistlikud aegumistähtajad, suurendasime kõiki kaitselülitite sätteid ja panime seejärel minimaalse uuesti proovimise konfiguratsiooni, et aidata mööduvaid rikkeid ja sujuvat juurutamist. Kõigi nende esiisaatjateenuste osutasime TCP ELB-ga. Isegi kui meie peamise eesmise puhverserveri kihi kinnitusvahendid kinnitati teatud saadiku poodiumitele, olid nad koormusega palju paremad ja konfigureeriti tasakaalustama taustarakenduse kaudu vähemalt_request.

Kasutuselevõtmiseks kasutasime nii rakenduse kui ka külgkorvi kaabli korral eelkonsooli konksu. See konks, mida kutsuti külgkorvi tervisekontrolliks, ei õnnestunud administraatori lõpp-punktina koos väikese unega, et anda lennu ajal ühenduse loomiseks ja tühjenemiseks veidi aega.

Üks põhjus, miks me suutsime nii kiiresti liikuda, oli rikkalike mõõdikute tõttu, mida suutsime hõlpsasti integreerida tavalise Prometheuse seadistusega. See võimaldas meil täpselt näha, mis toimus, kui me korratsime konfiguratsiooniseadeid ja vähendasime liiklust.

Tulemused olid vahetud ja ilmsed. Alustasime kõige tasakaalustatumate teenustega ja praegusel hetkel hakkame seda pakkuma meie klastri kaheteistkümne kõige olulisema teenuse ees. Sel aastal plaanime liikuda täisteenuste võrgule, kus on täiustatud teenuste avastamine, vooluringide katkemine, välimine tuvastamine, kiiruse piiramine ja jälgimine.

Joonis 3–1 Ühe teenuse CPU lähenemine saadikule ülemineku ajal

Lõpptulemus

Nende õppetundide ja täiendavate uuringute kaudu oleme välja töötanud tugeva ettevõttesisese infrastruktuuri meeskonna, kes on väga kursis suurte Kubernetes-klastrite kavandamise, juurutamise ja käitamisega. Kogu Tinderi inseneriorganisatsioon omab nüüd teadmisi ja kogemusi, kuidas nende rakendusi Kubernetesesse koondada ja juurutada.

Kui nõuti täiendavat skaalat, kannatasime oma pärandinfrastruktuuris sageli mitu minutit uute EC2 eksemplaride võrku tuleku ootamise tõttu. Konteinerid kavandavad ja teenindavad liiklust sekunditega, mitte minutitega. Mitme mahuti ajastamine ühele EC2 eksemplarile annab ka parema horisontaalse tiheduse. Selle tulemusel prognoosime EC2-le 2019. aastal võrreldes eelmise aastaga märkimisväärset kulude kokkuhoidu.

Läks peaaegu kaks aastat, kuid me viisime oma migratsiooni lõpule märtsis 2019. Tinderi platvorm töötab eranditult Kubernetesi klastris, mis koosneb 200 teenusest, 1000 sõlmest, 15 000 poodiumist ja 48 000 jooksvast konteinerist. Infrastruktuur pole enam meie operatsioonimeeskondade jaoks reserveeritud ülesanne. Selle asemel jagavad kogu organisatsiooni insenerid seda vastutust ja saavad kontrollida, kuidas nende rakendused ehitatakse ja juurutatakse koos koodiga.