Tinder siirtyy Kubernetesiin

Huomautus. käännös: Maailmankuulun Tinder-palvelun työntekijät jakoivat äskettäin joitain teknisiä yksityiskohtia infrastruktuurinsa siirtämisestä Kubernetesiin. Prosessi kesti lähes kaksi vuotta ja johti erittäin laajan alustan lanseeraukseen K8:ssa, joka koostuu 200 palvelusta, joita isännöi 48 tuhatta konttia. Mitä mielenkiintoisia vaikeuksia Tinderin insinöörit kohtasivat ja mihin tuloksiin he päätyivät? Lue tämä käännös.

Tinder siirtyy Kubernetesiin

Miksi?

Melkein kaksi vuotta sitten Tinder päätti siirtää alustansa Kubernetesiin. Kubernetes antaisi Tinder-tiimille mahdollisuuden varastoida ja siirtyä tuotantoon pienellä vaivalla muuttumattoman käyttöönoton ansiosta (muuttumaton käyttöönotto). Tässä tapauksessa sovellusten kokoonpano, niiden käyttöönotto ja itse infrastruktuuri määritettäisiin yksiselitteisesti koodilla.

Etsimme myös ratkaisua skaalautuvuuden ja vakauden ongelmaan. Kun skaalauksesta tuli kriittistä, jouduimme usein odottamaan useita minuutteja, jotta uudet EC2-instanssit ilmestyivät. Ajatus konttien laukaisusta ja liikenteen aloittamisesta sekunneissa minuuttien sijasta tuli meille erittäin houkuttelevaksi.

Prosessi osoittautui vaikeaksi. Siirtymisemme aikana vuoden 2019 alussa Kubernetes-klusteri saavutti kriittisen massan ja aloimme kohdata erilaisia ​​​​ongelmia liikennemäärien, klusterin koon ja DNS:n vuoksi. Matkan varrella ratkaisimme monia mielenkiintoisia ongelmia, jotka liittyvät 200 palvelun siirtämiseen ja 1000 solmusta, 15000 48000 podista ja XNUMX XNUMX käynnissä olevasta kontista koostuvan Kubernetes-klusterin ylläpitoon.

Miten?

Tammikuusta 2018 lähtien olemme käyneet läpi erilaisia ​​muuttoliikkeen vaiheita. Aloitimme kontioimalla kaikki palvelumme ja ottamalla ne käyttöön Kubernetes-testipilviympäristöissä. Lokakuusta alkaen aloitimme järjestelmällisesti kaikkien olemassa olevien palveluiden siirtämisen Kubernetesiin. Seuraavan vuoden maaliskuussa saimme siirron päätökseen, ja nyt Tinder-alusta toimii yksinomaan Kubernetesilla.

Kubernetesin kuvien rakentaminen

Meillä on yli 30 lähdekoodivarastoa Kubernetes-klusterissa toimiville mikropalveluille. Näissä arkistoissa oleva koodi on kirjoitettu eri kielillä (esimerkiksi Node.js, Java, Scala, Go) useilla ajonaikaisilla ympäristöillä samalle kielelle.

Rakennusjärjestelmä on suunniteltu tarjoamaan täysin muokattavissa oleva "koontikonteksti" jokaiselle mikropalvelulle. Se koostuu yleensä Docker-tiedostosta ja komentotulkkikomentojen luettelosta. Niiden sisältö on täysin muokattavissa, ja samalla kaikki nämä rakennuskontekstit on kirjoitettu standardoituun muotoon. Rakennuskontekstien standardointi mahdollistaa yhden koontijärjestelmän käsittelevän kaikkia mikropalveluita.

Tinder siirtyy Kubernetesiin
Kuva 1-1. Standardoitu rakennusprosessi Builder-säiliön kautta

Maksimaalisen johdonmukaisuuden saavuttamiseksi suoritusaikojen välillä (ajonaikaiset ympäristöt) samaa rakennusprosessia käytetään kehityksen ja testauksen aikana. Edessämme oli erittäin mielenkiintoinen haaste: meidän oli kehitettävä tapa varmistaa rakennusympäristön johdonmukaisuus koko alustalla. Tämän saavuttamiseksi kaikki kokoonpanoprosessit suoritetaan erityisessä säiliössä. Rakentaja.

Hänen konttitoteutuksensa vaati kehittyneitä Docker-tekniikoita. Builder perii paikallisen käyttäjätunnuksen ja salaisuudet (kuten SSH-avaimen, AWS-tunnistetiedot jne.), joita tarvitaan yksityisiin Tinder-tietovarastoihin pääsyyn. Se asentaa paikallisia hakemistoja, jotka sisältävät lähteitä luonnollisesti tallentaakseen rakennusartefakteja. Tämä lähestymistapa parantaa suorituskykyä, koska se eliminoi tarpeen kopioida koontiartefakteja Builder-säilön ja isännän välillä. Tallennettuja koontiartefakteja voidaan käyttää uudelleen ilman lisämäärityksiä.

Joillekin palveluille meidän piti luoda toinen säilö kartoittaaksemme käännösympäristön ajonaikaiseen ympäristöön (esimerkiksi Node.js bcrypt -kirjasto luo alustakohtaisia ​​binaariartefaktteja asennuksen aikana). Kokoamisprosessin aikana vaatimukset voivat vaihdella palveluittain, ja lopullinen Docker-tiedosto käännetään lennossa.

Kubernetes-klusteriarkkitehtuuri ja migraatio

Klusterin koon hallinta

Päätimme käyttää kube-aws automaattista klusterin käyttöönottoa varten Amazon EC2 -esiintymissä. Alussa kaikki toimi yhdessä yhteisessä solmujoukossa. Ymmärsimme nopeasti tarpeen erottaa työkuormat koon ja ilmentymän tyypin mukaan tehostaaksemme resurssien käyttöä. Logiikka oli, että useiden ladattujen monisäikeisten podien käyttäminen osoittautui suorituskyvyn kannalta ennakoitavammaksi kuin niiden rinnakkaiselo suuren määrän yksisäikeisiä podeja.

Lopulta sovittiin:

  • m5.4xiso — seurantaa varten (Prometheus);
  • c5.4xlarge - Node.js-työkuorma (yksisäikeinen työkuorma);
  • c5.2xlarge - Java ja Go (monisäikeinen työmäärä);
  • c5.4xlarge — ohjauspaneelille (3 solmua).

muutto

Yksi valmistelevista vaiheista siirtymiseen vanhasta infrastruktuurista Kubernetesiin oli nykyisen palvelujen välisen suoran tiedonsiirron ohjaaminen uusiin kuormituksen tasapainottajiin (Elastic Load Balancers (ELB). Ne luotiin virtuaalisen yksityisen pilven (VPC) tiettyyn aliverkkoon. Tämä aliverkko yhdistettiin Kubernetes VPC:hen. Tämä mahdollisti moduulien siirtämisen asteittain ottamatta huomioon palveluriippuvuuksien erityistä järjestystä.

Nämä päätepisteet luotiin käyttämällä painotettuja DNS-tietueiden sarjoja, joissa CNAME:t osoittivat jokaiseen uuteen ELB:hen. Vaihtaaksemme lisäsimme uuden merkinnän, joka osoittaa Kubernetes-palvelun uuteen ELB:hen painolla 0. Tämän jälkeen asetimme merkinnän Time To Live (TTL) arvoksi 0. Tämän jälkeen vanha ja uusi painoarvot säädettiin hitaasti, ja lopulta 100 % kuormasta lähetettiin uudelle palvelimelle. Kun vaihto oli valmis, TTL-arvo palasi sopivammalle tasolle.

Meillä olleet Java-moduulit pystyivät selviytymään alhaisesta TTL DNS:stä, mutta Node-sovellukset eivät. Yksi insinööreistä kirjoitti osan yhteyspoolikoodista uudelleen ja kääri sen hallintaohjelmaan, joka päivitti poolit 60 sekunnin välein. Valittu lähestymistapa toimi erittäin hyvin ja ilman havaittavaa suorituskyvyn heikkenemistä.

Oppitunnit

Verkkokankaan rajat

Varhain aamulla 8. tammikuuta 2019 Tinder-alusta kaatui odottamatta. Vastauksena asiaan liittymättömään alustan latenssin kasvuun aiemmin sinä aamuna, klusterin podien ja solmujen määrä kasvoi. Tämä aiheutti ARP-välimuistin loppumisen kaikissa solmuissamme.

ARP-välimuistiin liittyy kolme Linux-vaihtoehtoa:

Tinder siirtyy Kubernetesiin
(lähde)

gc_thresh3 - Tämä on kova raja. "Naapuritaulukon ylivuoto" -merkintöjen ilmestyminen lokiin tarkoitti, että edes synkronisen roskienkeräyksen (GC) jälkeen ARP-välimuistissa ei ollut tarpeeksi tilaa naapurimerkinnän tallentamiseen. Tässä tapauksessa ydin yksinkertaisesti hylkäsi paketin kokonaan.

Käytämme Flanelli verkkokankaana Kubernetesissa. Paketit lähetetään VXLANin kautta. VXLAN on L2-tunneli, joka on nostettu L3-verkon päälle. Tekniikka käyttää MAC-in-UDP (MAC Address-in-User Datagram Protocol) -kapselointia ja mahdollistaa Layer 2 -verkkosegmenttien laajentamisen. Fyysisen konesaliverkon siirtoprotokolla on IP plus UDP.

Tinder siirtyy Kubernetesiin
Kuva 2-1. Flanellikaavio (lähde)

Tinder siirtyy Kubernetesiin
Kuva 2-2. VXLAN-paketti (lähde)

Jokainen Kubernetes-työntekijäsolmu varaa virtuaalisen osoiteavaruuden /24-maskin kanssa suuremmasta /9-lohkosta. Tämä on jokaiselle solmulle välineet yksi merkintä reititystaulukossa, yksi merkintä ARP-taulukossa (flanell.1-liitännässä) ja yksi merkintä kytkentätaulukossa (FDB). Ne lisätään, kun työntekijäsolmu käynnistetään ensimmäisen kerran tai joka kerta, kun uusi solmu löydetään.

Lisäksi node-pod (tai pod-pod) -viestintä kulkee lopulta käyttöliittymän kautta eth0 (kuten yllä olevassa flanellikaaviossa näkyy). Tämä johtaa lisämerkintään ARP-taulukkoon jokaiselle vastaavalle lähde- ja kohdeisännälle.

Ympäristössämme tällainen viestintä on hyvin yleistä. Kubernetesin palveluobjekteille luodaan ELB ja Kubernetes rekisteröi jokaisen solmun ELB:hen. ELB ei tiedä mitään podista, eikä valittu solmu välttämättä ole paketin lopullinen kohde. Asia on siinä, että kun solmu vastaanottaa paketin ELB:ltä, se ottaa sen huomioon ottaen säännöt iptables tietylle palvelulle ja valitsee satunnaisesti podin toisessa solmussa.

Vian tapahtuessa klusterissa oli 605 solmua. Edellä mainituista syistä tämä riitti poistamaan merkityksen gc_thresh3, joka on oletusarvo. Kun näin tapahtuu, pakettien pudottaminen ei ala vain, vaan koko Flanel-virtuaalinen osoiteavaruus /24-maskin kanssa katoaa ARP-taulukosta. Node-pod-viestintä ja DNS-kyselyt keskeytyvät (DNS on klusterissa; lue lisätietoja myöhemmin tästä artikkelista).

Tämän ongelman ratkaisemiseksi sinun on nostettava arvoja gc_thresh1, gc_thresh2 и gc_thresh3 ja käynnistä Flannel uudelleen rekisteröidäksesi puuttuvat verkot.

Odottamaton DNS-skaalaus

Siirron aikana käytimme DNS:ää aktiivisesti liikenteen hallintaan ja asteittain palveluiden siirtämiseen vanhasta infrastruktuurista Kubernetesiin. Asetamme suhteellisen alhaiset TTL-arvot liittyville tietuejoukoille Route53:ssa. Kun vanha infrastruktuuri oli käynnissä EC2-esiintymissä, ratkaisijakokoonpanomme viittasi Amazon DNS:ään. Otimme tämän itsestäänselvyytenä, ja alhaisen TTL:n vaikutus palveluihimme ja Amazon-palveluihin (kuten DynamoDB) jäi suurelta osin huomaamatta.

Siirtäessämme palveluita Kubernetesiin havaitsimme, että DNS käsitteli 250 tuhatta pyyntöä sekunnissa. Tämän seurauksena sovellukset alkoivat kokea jatkuvia ja vakavia DNS-kyselyjen aikakatkaisuja. Tämä tapahtui huolimatta uskomattomista yrityksistä optimoida ja vaihtaa DNS-toimittaja CoreDNS:ään (joka huippukuormituksessa saavutti 1000 podia, jotka toimivat 120 ytimellä).

Tutkiessamme muita mahdollisia syitä ja ratkaisuja löysimme Artikkeli, joka kuvaa pakettisuodatuskehykseen vaikuttavia kilpailuolosuhteita netfilter Linuxissa. Havaitut aikakatkaisut yhdistettynä kasvavaan laskuriin insert_failed Flannel-käyttöliittymässä olivat yhdenmukaisia ​​artikkelin havaintojen kanssa.

Ongelma ilmenee lähde- ja kohdeverkko-osoitteiden käännösvaiheessa (SNAT ja DNAT) ja sen jälkeen taulukkoon syöttämisessä. jatka. Yksi sisäisesti keskusteltu ja yhteisön ehdottama kiertotapa oli DNS:n siirtäminen itse työntekijäsolmuun. Tässä tapauksessa:

  • SNATia ei tarvita, koska liikenne pysyy solmun sisällä. Sitä ei tarvitse reitittää käyttöliittymän kautta eth0.
  • DNAT:tä ei tarvita, koska kohde-IP on solmun paikallinen, eikä sääntöjen mukaan satunnaisesti valittu pod iptables.

Päätimme pitää kiinni tästä lähestymistavasta. CoreDNS otettiin käyttöön DaemonSetinä Kubernetesissa ja otimme käyttöön paikallisen solmun DNS-palvelimen solve.conf jokainen pod asettamalla lipun --cluster-dns komennot kuutio . Tämä ratkaisu osoittautui tehokkaaksi DNS-aikakatkaisuissa.

Näemme kuitenkin edelleen pakettien katoamisen ja laskurin kasvun insert_failed Flanel-käyttöliittymässä. Tämä jatkui kiertotavan käyttöönoton jälkeen, koska pystyimme poistamaan SNAT:n ja/tai DNAT:n vain DNS-liikenteestä. Kilpailuolosuhteet säilytettiin muun tyyppiselle liikenteelle. Onneksi suurin osa paketeistamme on TCP:tä, ja jos ongelma ilmenee, ne yksinkertaisesti lähetetään uudelleen. Pyrimme edelleen löytämään sopivaa ratkaisua kaikenlaiseen liikenteeseen.

Envoyn käyttäminen parempaan kuormituksen tasapainottamiseen

Kun siirsimme taustapalveluita Kubernetesiin, aloimme kärsiä podien välisestä epätasapainoisesta kuormituksesta. Havaitsimme, että HTTP Keepalive sai ELB-yhteydet roikkumaan jokaisen käyttöönoton ensimmäisissä valmiissa podeissa. Näin ollen suurin osa liikenteestä kulki pienen osan käytettävissä olevista koteloista. Ensimmäinen testaamamme ratkaisu oli MaxSurgen asettaminen 100 prosenttiin uusille käyttöönottoille pahimpia skenaarioita varten. Vaikutus osoittautui merkityksettömäksi ja lupaamattomaksi suurempien käyttöönottojen kannalta.

Toinen käyttämämme ratkaisu oli lisätä keinotekoisesti kriittisten palvelujen resurssipyyntöjä. Tässä tapauksessa lähelle sijoitetuilla paloilla olisi enemmän liikkumavaraa muihin raskaisiin paloihin verrattuna. Se ei toimisi myöskään pitkällä aikavälillä, koska se olisi resurssien tuhlausta. Lisäksi Node-sovelluksemme olivat yksisäikeisiä ja siten saattoivat käyttää vain yhtä ydintä. Ainoa todellinen ratkaisu oli käyttää parempaa kuormitusta.

Olemme pitkään halunneet arvostaa täysin Lähettiläs. Nykyinen tilanne antoi meille mahdollisuuden ottaa sitä käyttöön hyvin rajoitetusti ja saada välittömiä tuloksia. Envoy on korkean suorituskyvyn avoimen lähdekoodin XNUMX-kerroksen välityspalvelin, joka on suunniteltu suuriin SOA-sovelluksiin. Se voi toteuttaa edistyneitä kuormituksen tasaustekniikoita, mukaan lukien automaattiset uudelleenyritykset, katkaisijat ja globaali nopeuden rajoitus. (Huomautus. käännös: Voit lukea tästä lisää kohdasta tässä artikkelissa Istiosta, joka perustuu Envoyyn.)

Päädyimme seuraavaan kokoonpanoon: on Envoy-sivuvaunu jokaiselle kotelolle ja yhdelle reitille ja yhdistä klusteri konttiin paikallisesti portin kautta. Minimoiksemme mahdollisen kaskadin ja ylläpitääksemme pienen osuman säteen, käytimme Envoy-etuvälityspalvelinkantoja, yksi kutakin käytettävyysvyöhykettä (AZ) kohden. He luottivat yksinkertaiseen palvelunhakumoottoriin, jonka oli kirjoittanut yksi insinööreistämme, joka yksinkertaisesti palautti luettelon tietyn palvelun yksiköistä kussakin AZ:ssa.

Palvelun etulähettiläät käyttivät sitten tätä palvelunhakumekanismia yhden ylävirran klusterin ja reitin kanssa. Asetimme riittävät aikakatkaisut, lisäsimme kaikkia katkaisijoiden asetuksia ja lisäsimme minimaalisen uudelleenyritysmäärityksen helpottaaksemme yksittäisiä vikoja ja varmistaaksemme sujuvan käyttöönoton. Sijoitimme TCP ELB:n jokaisen palvelun etulähettilään eteen. Vaikka päävälityspalvelinkerroksen Keepalive oli juuttunut joihinkin Envoy-tyyppeihin, ne pystyivät silti käsittelemään kuormaa paljon paremmin ja ne määritettiin tasapainottamaan backend-toiminnolla vähintään_pyyntö.

Käyttöönottoa varten käytimme preStop-koukkua sekä sovelluskoteloissa että sivuvaunukoteloissa. Koukku laukaisi virheen sivuvaunusäiliössä sijaitsevan järjestelmänvalvojan päätepisteen tilan tarkistamisessa ja meni hetkeksi nukkumaan, jotta aktiiviset yhteydet katkesivat.

Yksi syistä, miksi pystyimme siirtymään niin nopeasti, johtuu yksityiskohtaisista mittareista, jotka pystyimme helposti integroimaan tyypilliseen Prometheus-asennukseen. Näin pystyimme näkemään tarkalleen, mitä tapahtui, kun säätimme määritysparametreja ja jakoimme liikennettä uudelleen.

Tulokset olivat välittömiä ja ilmeisiä. Aloitimme epätasapainoisimmista palveluista, ja tällä hetkellä se toimii klusterin 12 tärkeimmän palvelun edessä. Suunnittelemme tänä vuonna siirtymistä täyden palvelun verkkoon, jossa on edistyneempi palvelunhaku, piirikatkaisu, poikkeamien havaitseminen, nopeuden rajoittaminen ja jäljitys.

Tinder siirtyy Kubernetesiin
Kuva 3-1. Yhden palvelun prosessorikonvergenssi Envoyyn siirtymisen aikana

Tinder siirtyy Kubernetesiin

Tinder siirtyy Kubernetesiin

Lopullinen tulos

Tämän kokemuksen ja lisätutkimuksen avulla olemme rakentaneet vahvan infrastruktuuritiimin, jolla on vahvat taidot suurten Kubernetes-klustereiden suunnittelussa, käyttöönotossa ja käytössä. Kaikilla Tinderin insinööreillä on nyt tiedot ja kokemus konttien pakkaamisesta ja sovellusten käyttöönotosta Kubernetesiin.

Kun vanhaan infrastruktuuriin ilmaantui lisäkapasiteetin tarve, jouduimme odottamaan useita minuutteja uusien EC2-instanssien julkaisua. Nyt säilöt alkavat toimia ja alkavat käsitellä liikennettä sekunneissa minuuttien sijaan. Useiden säiliöiden ajoittaminen yhteen EC2-tapaukseen parantaa myös vaakasuuntaista keskittymistä. Tämän seurauksena ennustamme EC2019-kustannusten merkittävän pienenevän vuonna 2 viime vuoteen verrattuna.

Muutto kesti lähes kaksi vuotta, mutta saimme sen päätökseen maaliskuussa 2019. Tällä hetkellä Tinder-alusta toimii yksinomaan Kubernetes-klusterissa, jossa on 200 palvelua, 1000 15 solmua, 000 48 podia ja 000 XNUMX käynnissä olevaa konttia. Infrastruktuuri ei ole enää toimintaryhmien ainoa toimialue. Kaikki insinöörimme jakavat tämän vastuun ja hallitsevat sovellusten rakentamis- ja käyttöönottoprosessia käyttämällä vain koodia.

PS kääntäjältä

Lue myös artikkelisarja blogistamme:

Lähde: will.com

Lisää kommentti