Prechod Tinder na Kubernetes

Poznámka. preklad.: Zamestnanci svetoznámej služby Tinder sa nedávno podelili o niektoré technické podrobnosti o migrácii ich infraštruktúry na Kubernetes. Tento proces trval takmer dva roky a vyústil do spustenia veľmi rozsiahlej platformy na K8, pozostávajúcej z 200 služieb umiestnených na 48 tisíc kontajneroch. S akými zaujímavými ťažkosťami sa inžinieri Tinderu stretli a k ​​akým výsledkom dospeli? Prečítajte si tento preklad.

Prechod Tinder na Kubernetes

Prečo?

Pred takmer dvoma rokmi sa Tinder rozhodol presunúť svoju platformu na Kubernetes. Kubernetes by umožnil tímu Tinder kontajnerizovať a presunúť sa do výroby s minimálnym úsilím prostredníctvom nemenného nasadenia (nezmeniteľné nasadenie). V tomto prípade by zostavenie aplikácií, ich nasadenie a samotná infraštruktúra boli jednoznačne definované kódom.

Hľadali sme aj riešenie problému škálovateľnosti a stability. Keď sa škálovanie stalo kritickým, často sme museli čakať niekoľko minút, kým sa roztočili nové inštancie EC2. Myšlienka spustenia kontajnerov a spustenie prevádzky v sekundách namiesto minút sa pre nás stala veľmi atraktívna.

Proces sa ukázal ako náročný. Počas našej migrácie začiatkom roka 2019 dosiahol klaster Kubernetes kritické množstvo a začali sme sa stretávať s rôznymi problémami v dôsledku objemu prevádzky, veľkosti klastra a DNS. Popri tom sme vyriešili množstvo zaujímavých problémov súvisiacich s migráciou 200 služieb a údržbou klastra Kubernetes pozostávajúceho z 1000 15000 uzlov, 48000 XNUMX podov a XNUMX XNUMX spustených kontajnerov.

Ako?

Od januára 2018 sme prešli rôznymi fázami migrácie. Začali sme kontajnerizáciou všetkých našich služieb a ich nasadením na testovanie cloudových prostredí Kubernetes. Od októbra sme začali metodicky migrovať všetky existujúce služby na Kubernetes. Do marca nasledujúceho roka sme dokončili migráciu a platforma Tinder teraz beží výhradne na Kubernetes.

Vytváranie obrázkov pre Kubernetes

Máme viac ako 30 úložísk zdrojového kódu pre mikroslužby bežiace na klastri Kubernetes. Kód v týchto úložiskách je napísaný v rôznych jazykoch (napríklad Node.js, Java, Scala, Go) s viacerými runtime prostrediami pre rovnaký jazyk.

Systém zostavovania je navrhnutý tak, aby poskytoval plne prispôsobiteľný „kontext zostavenia“ pre každú mikroslužbu. Zvyčajne pozostáva z Dockerfile a zoznamu príkazov shellu. Ich obsah je úplne prispôsobiteľný a zároveň sú všetky tieto kontexty zostavovania napísané podľa štandardizovaného formátu. Štandardizácia kontextov zostavovania umožňuje jedinému zostavovaciemu systému zvládnuť všetky mikroslužby.

Prechod Tinder na Kubernetes
Obrázok 1-1. Štandardizovaný proces zostavovania prostredníctvom kontajnera Builder

Na dosiahnutie maximálnej konzistencie medzi spusteniami (behové prostredia) rovnaký proces zostavovania sa používa počas vývoja a testovania. Čelili sme veľmi zaujímavej výzve: museli sme vyvinúť spôsob, ako zabezpečiť konzistentnosť prostredia na zostavenie v rámci celej platformy. Aby sa to dosiahlo, všetky montážne procesy sa vykonávajú v špeciálnom kontajneri. Staviteľ.

Jeho implementácia kontajnera si vyžadovala pokročilé techniky Docker. Builder zdedí miestne ID používateľa a tajomstvá (napríklad kľúč SSH, poverenia AWS atď.), ktoré sú potrebné na prístup k súkromným úložiskám Tinder. Pripája miestne adresáre obsahujúce zdroje na prirodzené ukladanie artefaktov zostavy. Tento prístup zlepšuje výkon, pretože eliminuje potrebu kopírovania artefaktov zostavy medzi kontajnerom Builder a hostiteľom. Uložené artefakty zostavy je možné znova použiť bez ďalšej konfigurácie.

Pre niektoré služby sme museli vytvoriť ďalší kontajner na mapovanie prostredia kompilácie na prostredie runtime (napríklad knižnica Node.js bcrypt generuje binárne artefakty špecifické pre platformu počas inštalácie). Počas procesu kompilácie sa môžu požiadavky medzi službami líšiť a konečný súbor Dockerfile sa zostavuje za behu.

Klastrová architektúra a migrácia Kubernetes

Správa veľkosti klastra

Rozhodli sme sa použiť kube-aws pre automatizované nasadenie klastra na inštanciách Amazon EC2. Na samom začiatku všetko fungovalo v jednom spoločnom poole uzlov. Rýchlo sme si uvedomili potrebu oddeliť pracovné zaťaženia podľa veľkosti a typu inštancie, aby sme zefektívnili využívanie zdrojov. Logika bola taká, že prevádzkovanie niekoľkých nabitých viacvláknových modulov sa ukázalo z hľadiska výkonu predvídateľnejšie ako ich koexistencia s veľkým počtom modulov s jedným vláknom.

Nakoniec sme sa dohodli:

  • m5.4xveľký — na monitorovanie (Prometheus);
  • c5.4xveľký - pre pracovné zaťaženie Node.js (jednovláknové pracovné zaťaženie);
  • c5.2xveľký - pre Java and Go (viacvláknové pracovné zaťaženie);
  • c5.4xveľký — pre ovládací panel (3 uzly).

sťahovanie

Jedným z prípravných krokov na migráciu zo starej infraštruktúry na Kubernetes bolo presmerovanie existujúcej priamej komunikácie medzi službami na nové vyrovnávače zaťaženia (Elastic Load Balancers (ELB). Boli vytvorené na špecifickej podsieti virtuálneho privátneho cloudu (VPC). Táto podsieť bola pripojená k Kubernetes VPC. To nám umožnilo migrovať moduly postupne, bez zohľadnenia konkrétneho poradia závislostí služieb.

Tieto koncové body boli vytvorené pomocou vážených sád záznamov DNS, ktoré mali CNAME smerujúce na každú novú ELB. Na prepnutie sme pridali nový záznam smerujúci na nový ELB služby Kubernetes s váhou 0. Potom sme nastavili Time To Live (TTL) záznamu nastaveného na 0. Potom boli staré a nové váhy pomaly upravoval a nakoniec sa 100 % záťaže poslalo na nový server. Po dokončení prepínania sa hodnota TTL vrátila na adekvátnejšiu úroveň.

Moduly Java, ktoré sme mali, sa dokázali vyrovnať s nízkym TTL DNS, ale aplikácie Node nie. Jeden z inžinierov prepísal časť kódu oblasti pripojení a zabalil ju do manažéra, ktorý aktualizoval oblasti každých 60 sekúnd. Zvolený prístup fungoval veľmi dobre a bez výraznejšieho zníženia výkonu.

Hodiny

Limity siete

V skorých ranných hodinách 8. januára 2019 platforma Tinder nečakane havarovala. V reakcii na nesúvisiace zvýšenie latencie platformy skôr toho rána sa počet strukov a uzlov v klastri zvýšil. To spôsobilo vyčerpanie vyrovnávacej pamäte ARP na všetkých našich uzloch.

Existujú tri možnosti Linuxu súvisiace s vyrovnávacou pamäťou ARP:

Prechod Tinder na Kubernetes
(zdroj)

gc_thresh3 - toto je tvrdý limit. Výskyt záznamov „pretečenie tabuľky susedov“ v protokole znamenal, že aj po synchrónnom zbere odpadu (GC) nebolo v ARP cache dostatok miesta na uloženie susedného záznamu. V tomto prípade jadro jednoducho zahodilo paket úplne.

Používame flanel ako sieťová štruktúra v Kubernetes. Pakety sa prenášajú cez VXLAN. VXLAN je tunel L2 vybudovaný nad sieťou L3. Technológia využíva zapuzdrenie MAC-in-UDP (MAC Address-in-User Datagram Protocol) a umožňuje rozšírenie sieťových segmentov vrstvy 2. Transportný protokol vo fyzickej sieti dátového centra je IP plus UDP.

Prechod Tinder na Kubernetes
Obrázok 2-1. Flanelový diagram (zdroj)

Prechod Tinder na Kubernetes
Obrázok 2-2. Balík VXLAN (zdroj)

Každý pracovný uzol Kubernetes prideľuje virtuálny adresný priestor s maskou /24 z väčšieho bloku /9. Pre každý uzol je to tak rozumie jeden záznam v smerovacej tabuľke, jeden záznam v tabuľke ARP (na rozhraní flanel.1) a jeden záznam v prepínacej tabuľke (FDB). Pridávajú sa pri prvom spustení pracovného uzla alebo pri každom objavení nového uzla.

Komunikácia node-pod (alebo pod-pod) nakoniec prechádza cez rozhranie eth0 (ako je znázornené na Flanelovom diagrame vyššie). Výsledkom je ďalšia položka v tabuľke ARP pre každého zodpovedajúceho zdrojového a cieľového hostiteľa.

V našom prostredí je tento typ komunikácie veľmi bežný. Pre objekty služieb v Kubernetes sa vytvorí ELB a Kubernetes zaregistruje každý uzol s ELB. ELB nevie nič o moduloch a vybraný uzol nemusí byť konečným cieľom paketu. Ide o to, že keď uzol prijme paket z ELB, berie to do úvahy s ohľadom na pravidlá iptables pre konkrétnu službu a náhodne vyberie modul na inom uzle.

V čase zlyhania bolo v klastri 605 uzlov. Z vyššie uvedených dôvodov to stačilo na prekonanie významu gc_thresh3, čo je predvolené nastavenie. Keď sa to stane, začnú sa nielen zahadzovať pakety, ale z tabuľky ARP zmizne celý priestor virtuálnych adries Flannel s maskou /24. Komunikácia medzi uzlom a dotazy DNS sú prerušené (hostiteľom DNS je klaster; podrobnosti si prečítajte ďalej v tomto článku).

Ak chcete tento problém vyriešiť, musíte zvýšiť hodnoty gc_thresh1, gc_thresh2 и gc_thresh3 a reštartujte Flannel, aby ste znova zaregistrovali chýbajúce siete.

Neočakávané škálovanie DNS

Počas procesu migrácie sme aktívne využívali DNS na riadenie prevádzky a postupný prenos služieb zo starej infraštruktúry do Kubernetes. Nastavili sme relatívne nízke hodnoty TTL pre súvisiace sady záznamov v Route53. Keď stará infraštruktúra bežala na inštanciách EC2, naša konfigurácia resolvera ukazovala na Amazon DNS. Považovali sme to za samozrejmosť a vplyv nízkeho TTL na naše služby a služby Amazonu (napríklad DynamoDB) zostal do značnej miery nepovšimnutý.

Keď sme migrovali služby na Kubernetes, zistili sme, že DNS spracovávalo 250 tisíc požiadaviek za sekundu. Výsledkom bolo, že aplikácie začali neustále a vážne prekračovať časové limity pre dotazy DNS. Stalo sa tak napriek neuveriteľnému úsiliu o optimalizáciu a prepnutie poskytovateľa DNS na CoreDNS (ktorý pri špičkovom zaťažení dosiahol 1000 120 modulov bežiacich na XNUMX jadrách).

Pri skúmaní ďalších možných príčin a riešení sme zistili статью, popisujúci závodné podmienky ovplyvňujúce rámec filtrovania paketov netfilter v Linuxe. Časové limity, ktoré sme pozorovali, spolu so zvyšujúcim sa počítadlom insert_failed vo flanelovom rozhraní boli v súlade so zisteniami v článku.

Problém nastáva vo fáze prekladu zdrojovej a cieľovej siete (SNAT a DNAT) a následnom zadaní do tabuľky conntrack. Jedným z interne prediskutovaných riešení a navrhnutých komunitou bolo presunúť DNS do samotného pracovného uzla. V tomto prípade:

  • SNAT nie je potrebný, pretože prevádzka zostáva vo vnútri uzla. Nie je potrebné smerovať cez rozhranie eth0.
  • DNAT nie je potrebná, pretože cieľová IP je lokálna pre uzol, a nie náhodne vybraný modul podľa pravidiel iptables.

Rozhodli sme sa zotrvať pri tomto prístupe. CoreDNS bol nasadený ako DaemonSet v Kubernetes a implementovali sme lokálny uzol DNS server v vyriešiť.konf každý modul nastavením vlajky --cluster-dns príkazy kocka . Toto riešenie sa ukázalo ako efektívne pre časové limity DNS.

Stále sme však videli stratu paketov a nárast počítadla insert_failed v rozhraní Flanel. Toto pokračovalo aj po implementácii tohto riešenia, pretože sme boli schopní eliminovať SNAT a/alebo DNAT iba pre prenos DNS. Pretekové podmienky boli zachované pre iné druhy dopravy. Našťastie väčšina našich paketov je TCP a ak sa vyskytne problém, jednoducho sa znova prenesú. Stále sa snažíme nájsť vhodné riešenie pre všetky druhy dopravy.

Použitie Envoy pre lepšie vyrovnávanie záťaže

Keď sme migrovali backendové služby na Kubernetes, začali sme trpieť nevyváženou záťažou medzi modulmi. Zistili sme, že HTTP Keepalive spôsobilo, že pripojenia ELB visia na prvých pripravených moduloch každého zavedeného nasadenia. Prevažná časť návštevnosti teda prešla cez malé percento dostupných modulov. Prvým riešením, ktoré sme testovali, bolo nastavenie MaxSurge na 100 % pri nových nasadeniach pre najhoršie scenáre. Efekt sa ukázal ako nevýznamný a z hľadiska väčšieho nasadenia neperspektívny.

Ďalším riešením, ktoré sme použili, bolo umelé zvýšenie požiadaviek na zdroje pre kritické služby. V tomto prípade by moduly umiestnené v blízkosti mali viac priestoru na manévrovanie v porovnaní s inými ťažkými modulmi. Nefungovalo by to ani z dlhodobého hľadiska, pretože by to bolo plytvanie zdrojmi. Naše aplikácie Node boli navyše jednovláknové, a preto mohli používať iba jedno jadro. Jediným skutočným riešením bolo použiť lepšie vyvažovanie záťaže.

Dlho sme chceli plne oceniť vyslanec. Aktuálna situácia nám umožnila nasadiť ho veľmi obmedzene a získať okamžité výsledky. Envoy je vysokovýkonný proxy server s otvoreným zdrojovým kódom, vrstva XNUMX navrhnutý pre veľké aplikácie SOA. Môže implementovať pokročilé techniky vyrovnávania záťaže vrátane automatických opakovaní, ističov a globálneho obmedzenia rýchlosti. (Poznámka. preklad.: Viac o tom si môžete prečítať v v tomto článku o Istio, ktorý je založený na Envoy.)

Prišli sme s nasledujúcou konfiguráciou: mať postranný vozík Envoy pre každý modul a jednu trasu a pripojiť klaster ku kontajneru lokálne cez port. Aby sme minimalizovali potenciálne kaskádovanie a zachovali malý dosah, použili sme flotilu front-proxy modulov Envoy, jeden na zónu dostupnosti (AZ) pre každú službu. Spoliehali sa na jednoduchý nástroj na vyhľadávanie služieb napísaný jedným z našich inžinierov, ktorý jednoducho vrátil zoznam modulov v každom AZ pre danú službu.

Service front-Envoys potom použili tento mechanizmus zisťovania služieb s jedným upstream klastrom a trasou. Nastavili sme primerané časové limity, zvýšili všetky nastavenia ističov a pridali konfiguráciu minimálneho opakovania, aby sme pomohli pri jednotlivých zlyhaniach a zabezpečili hladké nasadenie. Umiestnili sme TCP ELB pred každého z týchto servisných front-Envoys. Aj keď udržiavanie z našej hlavnej proxy vrstvy uviazlo na niektorých moduloch Envoy, stále boli schopné zvládnuť záťaž oveľa lepšie a boli nakonfigurované tak, aby vyvážili najmenej_požiadavku v backende.

Na nasadenie sme použili hák preStop na aplikačných moduloch aj na držiakoch postranných vozíkov. Hák spustil chybu pri kontrole stavu koncového bodu správcu umiestneného na kontajneri postranného vozíka a na chvíľu prešiel do režimu spánku, aby sa umožnilo ukončenie aktívnych pripojení.

Jedným z dôvodov, prečo sme sa mohli pohybovať tak rýchlo, sú podrobné metriky, ktoré sme dokázali jednoducho integrovať do typickej inštalácie Prometheus. To nám umožnilo presne vidieť, čo sa deje, kým sme upravovali konfiguračné parametre a prerozdeľovali návštevnosť.

Výsledky boli okamžité a zrejmé. Začali sme s najnevyváženejšími službami a momentálne funguje pred 12 najdôležitejšími službami v klastri. Tento rok plánujeme prechod na komplexnú sieť služieb s pokročilejším vyhľadávaním služieb, prerušením okruhu, detekciou odľahlých hodnôt, obmedzením rýchlosti a sledovaním.

Prechod Tinder na Kubernetes
Obrázok 3-1. CPU konvergencia jednej služby pri prechode na Envoy

Prechod Tinder na Kubernetes

Prechod Tinder na Kubernetes

Konečný výsledok

Prostredníctvom týchto skúseností a ďalšieho výskumu sme vybudovali silný tím infraštruktúry so silnými zručnosťami v oblasti navrhovania, nasadzovania a prevádzky veľkých klastrov Kubernetes. Všetci inžinieri Tinderu majú teraz znalosti a skúsenosti na balenie kontajnerov a nasadzovanie aplikácií do Kubernetes.

Keď vznikla potreba dodatočnej kapacity na starej infraštruktúre, museli sme čakať niekoľko minút na spustenie nových inštancií EC2. Teraz sa kontajnery spustia a začnú spracovávať návštevnosť v priebehu niekoľkých sekúnd, nie minút. Naplánovanie viacerých kontajnerov v jednej inštancii EC2 tiež poskytuje zlepšenú horizontálnu koncentráciu. V dôsledku toho predpokladáme výrazné zníženie nákladov EC2019 v roku 2 v porovnaní s minulým rokom.

Migrácia trvala takmer dva roky, no dokončili sme ju v marci 2019. V súčasnosti platforma Tinder beží výhradne na klastri Kubernetes, ktorý pozostáva z 200 služieb, 1000 15 uzlov, 000 48 modulov a 000 XNUMX spustených kontajnerov. Infraštruktúra už nie je jedinou doménou operačných tímov. Všetci naši inžinieri zdieľajú túto zodpovednosť a riadia proces vytvárania a nasadzovania svojich aplikácií iba pomocou kódu.

PS od prekladateľa

Prečítajte si aj sériu článkov na našom blogu:

Zdroj: hab.com

Pridať komentár