A Tinder átállása Kubernetesre

Jegyzet. ford.: A világhírű Tinder szolgáltatás alkalmazottai a közelmúltban megosztottak néhány technikai részletet infrastruktúrájuk Kubernetesre való migrálásával kapcsolatban. A folyamat csaknem két évig tartott, és egy igen nagyszabású platform elindítását eredményezte a K8s-on, amely 200 szolgáltatásból áll, 48 ezer konténerben. Milyen érdekes nehézségekbe ütköztek a Tinder mérnökei, és milyen eredményekre jutottak? Olvassa el ezt a fordítást.

A Tinder átállása Kubernetesre

Miért?

Majdnem két évvel ezelőtt a Tinder úgy döntött, hogy platformját a Kubernetesre helyezi át. A Kubernetes lehetővé tenné a Tinder csapata számára, hogy konténerbe rakjon, és minimális erőfeszítéssel élesre lépjen a változatlan telepítés révén (változhatatlan telepítés). Ebben az esetben az alkalmazások összeállítását, azok telepítését és magát az infrastruktúrát egyedi kód határozza meg.

A skálázhatóság és a stabilitás problémájára is kerestünk megoldást. Amikor a méretezés kritikussá vált, gyakran néhány percet kellett várnunk az új EC2 példányok felpörgésére. Nagyon vonzóvá vált számunkra az ötlet, hogy percek helyett másodpercek alatt indítsuk el a konténereket és indítsuk el a forgalmat.

A folyamat nehéznek bizonyult. A 2019 eleji migráció során a Kubernetes-fürt elérte a kritikus tömeget, és különféle problémákkal találkoztunk a forgalom mennyisége, a fürt mérete és a DNS miatt. Útközben számos érdekes problémát megoldottunk 200 szolgáltatás migrálásával és egy 1000 csomópontból, 15000 48000 podból és XNUMX XNUMX futó konténerből álló Kubernetes-fürt karbantartásával kapcsolatban.

Hogyan?

2018 januárja óta a migráció különböző szakaszain mentünk keresztül. Kezdetben az összes szolgáltatásunkat konténerbe helyeztük, és a Kubernetes tesztfelhő-környezetekben telepítettük. Októbertől megkezdtük az összes meglévő szolgáltatás módszeres áttelepítését a Kubernetesre. A következő év márciusára befejeztük a migrációt, és a Tinder platform már kizárólag Kubernetesen fut.

Képek létrehozása a Kubernetes számára

Több mint 30 forráskód-tárhellyel rendelkezünk a Kubernetes-fürtön futó mikroszolgáltatásokhoz. Az ezekben a tárolókban található kód különböző nyelveken (például Node.js, Java, Scala, Go) van írva, ugyanazon nyelvhez több futási környezettel.

Az összeállítási rendszert úgy tervezték, hogy minden mikroszolgáltatáshoz teljesen testreszabható „összeállítási környezetet” biztosítson. Általában egy Dockerfile-ból és egy shell-parancsok listájából áll. Tartalmuk teljesen személyre szabható, ugyanakkor ezek a build kontextusok szabványos formátum szerint vannak megírva. Az összeállítási kontextusok szabványosítása lehetővé teszi, hogy egyetlen összeállítási rendszer kezelje az összes mikroszolgáltatást.

A Tinder átállása Kubernetesre
1-1. ábra. Szabványos építési folyamat Builder tárolón keresztül

A futási idők közötti maximális összhang elérése érdekében (futásidejű környezetek) ugyanazt az összeállítási folyamatot használják a fejlesztés és a tesztelés során. Nagyon érdekes kihívással kellett szembenéznünk: ki kellett dolgoznunk egy módszert, amellyel biztosítható az építési környezet konzisztenciája a teljes platformon. Ennek elérése érdekében minden összeszerelési folyamatot egy speciális tartályban hajtanak végre. Építész.

A konténer megvalósításához fejlett Docker-technikákra volt szükség. A Builder örökli a helyi felhasználói azonosítót és titkokat (például SSH-kulcsot, AWS-hitelesítő adatokat stb.), amelyek a privát Tinder-tárolók eléréséhez szükségesek. A forrásokat tartalmazó helyi könyvtárakat csatolja az összeállítási műtermékek természetes tárolására. Ez a megközelítés javítja a teljesítményt, mivel szükségtelenné teszi az összeállítási melléktermékek másolását a Builder-tároló és a gazdagép között. A tárolt összeállítási műtermékek további konfiguráció nélkül újrafelhasználhatók.

Egyes szolgáltatásokhoz egy másik tárolót kellett létrehoznunk, hogy a fordítási környezetet leképezzük a futási környezetre (például a Node.js bcrypt könyvtár platform-specifikus bináris melléktermékeket állít elő a telepítés során). A fordítási folyamat során a követelmények szolgáltatásonként változhatnak, és a végső Docker-fájlt menet közben állítják össze.

Kubernetes-fürt architektúra és migráció

Klaszterméret-kezelés

Úgy döntöttünk, hogy használjuk kube-aws automatizált fürttelepítéshez az Amazon EC2 példányokon. Kezdetben minden egyetlen közös csomópontban működött. Gyorsan felismertük, hogy az erőforrások hatékonyabb felhasználása érdekében a munkaterheléseket méret és példánytípus szerint kell szétválasztani. A logika az volt, hogy több betöltött többszálú pod futtatása kiszámíthatóbbnak bizonyult a teljesítmény szempontjából, mint a sok egyszálú poddal való együttélésük.

Végül megállapodtunk:

  • m5.4xnagy — megfigyelésre (Prometheus);
  • c5.4xnagy - Node.js munkaterheléshez (egyszálú munkaterhelés);
  • c5.2xnagy - Java és Go számára (többszálú munkaterhelés);
  • c5.4xnagy — a vezérlőpanelhez (3 csomópont).

elvándorlás

A régi infrastruktúráról a Kubernetesre való átállás egyik előkészítő lépése a szolgáltatások közötti meglévő közvetlen kommunikáció átirányítása az új terheléselosztókra (Elastic Load Balancers (ELB). Egy virtuális magánfelhő (VPC) meghatározott alhálózatán hozták létre. Ez az alhálózat egy Kubernetes VPC-hez volt csatlakoztatva. Ez lehetővé tette a modulok fokozatos migrálását, anélkül, hogy figyelembe vettük volna a szolgáltatásfüggőségek konkrét sorrendjét.

Ezeket a végpontokat a DNS-rekordok súlyozott készleteinek használatával hozták létre, amelyekben minden új ELB-re CNAME-ek mutattak. Az átváltáshoz hozzáadtunk egy új bejegyzést, amely a Kubernetes szolgáltatás új ELB-jére mutat 0-s súllyal. Ezután a bejegyzéskészlet TTL-jét (Time To Live) 0-ra állítottuk. Ezt követően a régi és az új súlyozást lassan igazodott, és végül a terhelés 100%-a egy új szerverre került. A váltás befejezése után a TTL érték visszatért egy megfelelőbb szintre.

A nálunk lévő Java modulok képesek voltak megbirkózni az alacsony TTL DNS-sel, de a Node alkalmazások nem. Az egyik mérnök átírta a kapcsolatkészlet kód egy részét, és egy kezelőbe csomagolta, amely 60 másodpercenként frissítette a készleteket. A választott megközelítés nagyon jól működött, és a teljesítmény észrevehető romlása nélkül.

tanulságok

A hálózati szövet határai

8. január 2019-án kora reggel a Tinder platform váratlanul összeomlott. Válaszul a platform késleltetésének nem kapcsolódó növekedésére aznap reggel, a fürtben lévő podok és csomópontok száma megnőtt. Emiatt az összes csomópontunkon kimerült az ARP gyorsítótár.

Három Linux-beállítás kapcsolódik az ARP-gyorsítótárhoz:

A Tinder átállása Kubernetesre
(forrás)

gc_thresh3 - ez kemény határ. A „szomszédtábla túlcsordulás” bejegyzések megjelenése a naplóban azt jelentette, hogy a szinkron szemétgyűjtés (GC) után sem volt elég hely az ARP gyorsítótárban a szomszédos bejegyzés tárolására. Ebben az esetben a kernel egyszerűen teljesen eldobta a csomagot.

Használunk Flanel mint hálózati szövet a Kubernetesben. A csomagok továbbítása VXLAN-on keresztül történik. A VXLAN egy L2 alagút egy L3 hálózat tetejére. A technológia MAC-in-UDP (MAC Address-in-User Datagram Protocol) tokozást használ, és lehetővé teszi a 2. rétegű hálózati szegmensek bővítését. A fizikai adatközponti hálózat szállítási protokollja IP plusz UDP.

A Tinder átállása Kubernetesre
ábra 2–1. Flanel diagram (forrás)

A Tinder átállása Kubernetesre
2-2 ábra. VXLAN csomag (forrás)

Minden Kubernetes munkavégző csomópont lefoglal egy virtuális címteret egy /24 maszkkal egy nagyobb /9 blokkból. Ez minden csomópontra vonatkozik eszközök egy bejegyzés az útválasztási táblában, egy bejegyzés az ARP táblában (a flanel.1 felületen), és egy bejegyzés a kapcsolótáblában (FDB). A munkavégző csomópont első indításakor vagy minden új csomópont felfedezésekor kerülnek hozzáadásra.

Ezenkívül a csomópont-pod (vagy pod-pod) kommunikáció végül az interfészen keresztül megy keresztül eth0 (amint a fenti Flanel diagramon látható). Ez további bejegyzést eredményez az ARP-táblázatban minden megfelelő forrás- és célállomáshoz.

Környezetünkben nagyon elterjedt ez a fajta kommunikáció. A Kubernetes szolgáltatásobjektumaihoz létrejön egy ELB, és a Kubernetes minden csomópontot regisztrál az ELB-ben. Az ELB semmit sem tud a podokról, és előfordulhat, hogy a kiválasztott csomópont nem a csomag végső rendeltetési helye. A lényeg az, hogy amikor egy csomópont csomagot kap az ELB-től, azt a szabályok figyelembevételével veszi figyelembe iptables egy adott szolgáltatáshoz, és véletlenszerűen kiválaszt egy pod egy másik csomóponton.

A hiba idején 605 csomópont volt a fürtben. A fent említett okok miatt ez elegendő volt a jelentőségének leküzdéséhez gc_thresh3, ami az alapértelmezett. Amikor ez megtörténik, nem csak a csomagok kezdődnek el, hanem a teljes Flanel virtuális címtér /24-es maszkkal is eltűnik az ARP táblából. A csomópontok közötti kommunikáció és a DNS-lekérdezések megszakadnak (a DNS-t egy fürt tárolja; a részletekért lásd később ebben a cikkben).

A probléma megoldásához növelni kell az értékeket gc_thresh1, gc_thresh2 и gc_thresh3 és indítsa újra a Flannelt a hiányzó hálózatok újraregisztrálásához.

Váratlan DNS-skálázás

A migrációs folyamat során aktívan használtuk a DNS-t a forgalom menedzselésére és a szolgáltatások fokozatos átvitelére a régi infrastruktúráról a Kubernetesre. Viszonylag alacsony TTL értékeket állítottunk be a Route53 társított rekordkészleteihez. Amikor a régi infrastruktúra futott az EC2 példányokon, a feloldó konfigurációnk az Amazon DNS-re mutatott. Ezt természetesnek vettük, és az alacsony TTL szolgáltatásainkra és az Amazon szolgáltatásainkra (például a DynamoDB) gyakorolt ​​hatása nagyrészt észrevétlen maradt.

Amikor a szolgáltatásokat áttelepítettük a Kubernetesre, azt találtuk, hogy a DNS másodpercenként 250 ezer kérést dolgozott fel. Ennek eredményeként az alkalmazások állandó és komoly időtúllépéseket tapasztaltak a DNS-lekérdezések során. Ez annak ellenére történt, hogy hihetetlen erőfeszítéseket tettek a DNS-szolgáltató optimalizálására és CoreDNS-re való átállítására (amely csúcsterheléskor elérte az 1000 podot, amely 120 magon fut).

Más lehetséges okok és megoldások kutatása közben felfedeztük статью, amely a csomagszűrő keretrendszert befolyásoló versenyfeltételeket írja le netfilternek Linuxban. Az általunk megfigyelt időtúllépések növekvő számlálóval párosulva beillesztés_sikertelen a Flanel felületen összhangban voltak a cikk megállapításaival.

A probléma a forrás- és célhálózati címfordítás (SNAT és DNAT), majd a táblázatba való belépés szakaszában jelentkezik. összevág. Az egyik belsőleg megvitatott és a közösség által javasolt megoldás az volt, hogy a DNS-t magához a munkavégző csomóponthoz helyezzék át. Ebben az esetben:

  • SNAT-ra nincs szükség, mert a forgalom a csomóponton belül marad. Nem kell az interfészen keresztül irányítani eth0.
  • A DNST-re nincs szükség, mivel a cél IP helyi a csomópontban, és nem a szabályok szerint véletlenszerűen kiválasztott pod iptables.

Úgy döntöttünk, hogy ragaszkodunk ehhez a megközelítéshez. A CoreDNS-t DaemonSetként telepítették a Kubernetesben, és egy helyi csomóponti DNS-kiszolgálót implementáltunk solve.conf minden pod egy zászló beállításával --cluster-dns parancsokat kubelet . Ez a megoldás hatékonynak bizonyult a DNS-időtúllépések esetén.

Azonban továbbra is csomagvesztést és a számláló növekedését láttuk beillesztés_sikertelen a Flanel felületen. Ez a megoldás bevezetése után is folytatódott, mivel a SNAT-ot és/vagy a DNAT-t csak a DNS-forgalom esetében tudtuk megszüntetni. A versenyfeltételeket megőrizték más forgalom számára. Szerencsére a legtöbb csomagunk TCP, és ha probléma adódik, egyszerűen újraküldjük őket. Továbbra is igyekszünk minden típusú forgalomra megfelelő megoldást találni.

Envoy használata a jobb terheléselosztás érdekében

Ahogy áttelepítettük a háttérszolgáltatásokat a Kubernetesre, elkezdtünk szenvedni a pod-ok közötti kiegyensúlyozatlan terheléstől. Megállapítottuk, hogy a HTTP Keepalive hatására az ELB-kapcsolatok lefagytak minden egyes kivezetett telepítés első kész podjain. Így a forgalom nagy része a rendelkezésre álló pod-ok kis százalékán ment keresztül. Az első általunk tesztelt megoldás az volt, hogy a MaxSurge-t 100%-ra állítottuk az új telepítéseknél a legrosszabb forgatókönyvek esetére. A hatás jelentéktelennek és reménytelennek bizonyult a nagyobb bevetések tekintetében.

Egy másik megoldás az volt, hogy mesterségesen növeltük a kritikus szolgáltatások erőforrásigényét. Ebben az esetben a közelben elhelyezett hüvelyeknek nagyobb mozgástere lenne a többi nehéz hüvelyhez képest. Hosszú távon sem működne, mert az erőforrások pazarlása lenne. Ráadásul a Node-alkalmazásaink egyszálúak voltak, és ennek megfelelően csak egy magot használhattak. Az egyetlen igazi megoldás a jobb terheléselosztás volt.

Régóta szerettük volna teljes mértékben értékelni Követ. A jelenlegi helyzet lehetővé tette számunkra, hogy nagyon korlátozott módon alkalmazzuk, és azonnali eredményeket érjünk el. Az Envoy egy nagy teljesítményű, nyílt forráskódú, XNUMX-es rétegű proxy, amelyet nagy SOA-alkalmazásokhoz terveztek. Speciális terheléselosztási technikákat valósíthat meg, beleértve az automatikus újrapróbálkozásokat, a megszakítókat és a globális sebességkorlátozást. (Jegyzet. ford.: Erről bővebben itt olvashat ezt a cikket az Istioról, amely az Envoy-n alapul.)

A következő konfigurációt hoztuk létre: legyen egy Envoy oldalkocsi minden podhoz és egyetlen útvonalhoz, és csatlakoztassa a klasztert a konténerhez helyileg a porton keresztül. A lehetséges lépcsőzetes előfordulás minimalizálása és a kis találati sugár fenntartása érdekében az Envoy front-proxy pod-flottáját használtuk, minden szolgáltatáshoz elérhetőségi zónánként egyet. Egy egyszerű szolgáltatáskereső motorra támaszkodtak, amelyet egyik mérnökünk írt, és amely egyszerűen visszaadta az adott szolgáltatáshoz tartozó AZ-okban található pod-ok listáját.

A Service Front-Envoys ezután ezt a szolgáltatáskeresési mechanizmust egy upstream fürttel és útvonallal használták. Megfelelő időtúllépést állítottunk be, megnöveltük az összes megszakító beállítását, és minimális újrapróbálkozási konfigurációt adtunk hozzá, hogy segítsünk az egyszeri meghibásodásoknál és biztosítsuk a zökkenőmentes üzembe helyezést. Mindegyik szolgálati frontmegbízott elé helyeztünk egy TCP ELB-t. Még ha a fő proxyrétegünkből származó Keepalive meg is ragadt néhány Envoy podon, még mindig sokkal jobban tudták kezelni a terhelést, és úgy lettek beállítva, hogy a háttérben a legalacsonyabb_request függvényt egyensúlyozzák.

A telepítéshez a preStop horgot használtuk mind az alkalmazás-, mind az oldalkocsi-podákon. A horog hibát váltott ki az oldalkocsi-tárolón található adminisztrátori végpont állapotának ellenőrzésekor, és egy időre aludt, hogy lehetővé tegye az aktív kapcsolatok megszakítását.

Az egyik ok, amiért ilyen gyorsan tudtunk lépni, a részletes mérőszámoknak köszönhető, amelyeket könnyen be tudtunk integrálni egy tipikus Prometheus-telepítésbe. Ez lehetővé tette számunkra, hogy pontosan lássuk, mi történik a konfigurációs paraméterek módosítása és a forgalom újraelosztása közben.

Az eredmények azonnaliak és nyilvánvalóak voltak. A legkiegyensúlyozatlanabb szolgáltatásokkal kezdtük, és jelenleg a klaszter 12 legfontosabb szolgáltatása előtt működik. Idén egy teljes körű szolgáltatásra való átállást tervezünk, fejlettebb szolgáltatásfelderítéssel, áramkör-megszakítással, kiugró értékek észlelésével, sebességkorlátozással és nyomkövetéssel.

A Tinder átállása Kubernetesre
ábra 3–1. Egy szolgáltatás CPU-konvergenciája az Envoy-ra való áttérés során

A Tinder átállása Kubernetesre

A Tinder átállása Kubernetesre

Végeredmény

Ezzel a tapasztalattal és további kutatásokkal erős infrastrukturális csapatot építettünk fel, amely erős készségekkel rendelkezik a nagy Kubernetes-fürtök tervezésében, telepítésében és üzemeltetésében. Mostantól minden Tinder mérnök rendelkezik a konténerek csomagolásához és az alkalmazások Kubernetes rendszerbe történő telepítéséhez szükséges tudással és tapasztalattal.

Amikor a régi infrastruktúrán további kapacitásra volt szükség, néhány percet kellett várnunk az új EC2 példányok indulására. Mostantól a tárolók futni kezdenek, és percek helyett másodperceken belül megkezdik a forgalom feldolgozását. Több tároló ütemezése egyetlen EC2 példányon is javítja a vízszintes koncentrációt. Ennek eredményeként az EC2019 költségek jelentős csökkenését prognosztizáljuk 2-ben a tavalyi évhez képest.

A migráció közel két évig tartott, de 2019 márciusában befejeztük. Jelenleg a Tinder platform kizárólag egy Kubernetes klaszteren fut, amely 200 szolgáltatásból, 1000 csomópontból, 15 000 podból és 48 000 futó konténerből áll. Az infrastruktúra már nem az üzemeltetési csapatok kizárólagos területe. Minden mérnökünk megosztja ezt a felelősséget, és csak kód használatával irányítja alkalmazásaik felépítésének és üzembe helyezésének folyamatát.

PS a fordítótól

Olvassa el blogunk cikksorozatát is:

Forrás: will.com

Hozzászólás