Přechod Tinder na Kubernetes

Poznámka. přel.: Zaměstnanci světoznámé služby Tinder nedávno sdíleli některé technické podrobnosti o migraci své infrastruktury na Kubernetes. Proces trval téměř dva roky a vyústil ve spuštění velmi rozsáhlé platformy na K8, sestávající z 200 služeb hostovaných na 48 tisících kontejnerech. S jakými zajímavými obtížemi se inženýři Tinderu setkali a k ​​jakým výsledkům došli? Přečtěte si tento překlad.

Přechod Tinder na Kubernetes

Proč?

Před téměř dvěma lety se Tinder rozhodl přesunout svou platformu na Kubernetes. Kubernetes by týmu Tinder umožnil kontejnerizaci a přechod do výroby s minimálním úsilím díky neměnnému nasazení (neměnné nasazení). V tomto případě by sestavení aplikací, jejich nasazení a samotná infrastruktura byly jednoznačně definovány kódem.

Hledali jsme také řešení problému škálovatelnosti a stability. Když se škálování stalo kritickým, museli jsme často čekat několik minut, než se roztočily nové instance EC2. Myšlenka spouštění kontejnerů a zahájení provozu během několika sekund místo minut se pro nás stala velmi atraktivní.

Proces se ukázal jako obtížný. Během naší migrace na začátku roku 2019 dosáhl cluster Kubernetes kritického množství a začali jsme narážet na různé problémy kvůli objemu provozu, velikosti clusteru a DNS. Po cestě jsme vyřešili spoustu zajímavých problémů souvisejících s migrací 200 služeb a údržbou clusteru Kubernetes sestávajícího z 1000 uzlů, 15000 48000 podů a XNUMX XNUMX běžících kontejnerů.

Jak?

Od ledna 2018 jsme prošli různými fázemi migrace. Začali jsme kontejnerizací všech našich služeb a jejich nasazením do testovacích cloudových prostředí Kubernetes. Od října jsme začali metodicky migrovat všechny stávající služby na Kubernetes. Do března následujícího roku jsme dokončili migraci a platforma Tinder nyní běží výhradně na Kubernetes.

Vytváření obrázků pro Kubernetes

Máme více než 30 úložišť zdrojového kódu pro mikroslužby běžící na clusteru Kubernetes. Kód v těchto úložištích je napsán v různých jazycích (například Node.js, Java, Scala, Go) s více běhovými prostředími pro stejný jazyk.

Systém sestavení je navržen tak, aby poskytoval plně přizpůsobitelný „kontext sestavení“ pro každou mikroslužbu. Obvykle se skládá z Dockerfile a seznamu příkazů shellu. Jejich obsah je zcela přizpůsobitelný a zároveň jsou všechny tyto kontexty sestavení psány podle standardizovaného formátu. Standardizace kontextů sestavení umožňuje jedinému systému sestavení zpracovávat všechny mikroslužby.

Přechod Tinder na Kubernetes
Obrázek 1-1. Standardizovaný proces sestavení prostřednictvím kontejneru Builder

Pro dosažení maximální konzistence mezi běhy (běhová prostředí) stejný proces sestavení se používá během vývoje a testování. Čelili jsme velmi zajímavé výzvě: museli jsme vyvinout způsob, jak zajistit konzistenci prostředí sestavení napříč celou platformou. Aby toho bylo dosaženo, všechny montážní procesy se provádějí uvnitř speciálního kontejneru. Stavitel.

Jeho implementace kontejneru vyžadovala pokročilé techniky Docker. Builder zdědí ID místního uživatele a tajemství (jako je klíč SSH, pověření AWS atd.) potřebné pro přístup k soukromým úložištím Tinder. Připojuje místní adresáře obsahující zdroje pro přirozené ukládání artefaktů sestavení. Tento přístup zlepšuje výkon, protože eliminuje potřebu kopírovat artefakty sestavení mezi kontejnerem Builder a hostitelem. Uložené artefakty sestavení lze znovu použít bez další konfigurace.

Pro některé služby jsme museli vytvořit další kontejner, abychom namapovali prostředí kompilace na běhové prostředí (například knihovna Node.js bcrypt generuje během instalace binární artefakty specifické pro platformu). Během procesu kompilace se mohou požadavky mezi službami lišit a konečný soubor Dockerfile je kompilován za běhu.

Architektura a migrace clusteru Kubernetes

Správa velikosti clusteru

Rozhodli jsme se použít kube-aws pro automatizované nasazení clusteru na instancích Amazon EC2. Na samém začátku vše fungovalo v jednom společném poolu uzlů. Rychle jsme si uvědomili potřebu oddělit pracovní zátěže podle velikosti a typu instance, abychom efektivněji využívali zdroje. Logika byla taková, že provozování několika nabitých vícevláknových modulů se ukázalo z hlediska výkonu předvídatelnější než jejich koexistence s velkým počtem modulů s jedním vláknem.

Nakonec jsme se dohodli:

  • m5.4xvelký — pro sledování (Prometheus);
  • c5.4xvelký - pro zátěž Node.js (jednovláknová zátěž);
  • c5.2xvelký - pro Java and Go (vícevláknové pracovní zatížení);
  • c5.4xvelký — pro ovládací panel (3 uzly).

Migrace

Jedním z přípravných kroků pro migraci ze staré infrastruktury na Kubernetes bylo přesměrování stávající přímé komunikace mezi službami na nové load balancery (Elastic Load Balancers (ELB). Byly vytvořeny na konkrétní podsíti virtuálního privátního cloudu (VPC). Tato podsíť byla připojena k Kubernetes VPC. To nám umožnilo migrovat moduly postupně, bez ohledu na konkrétní pořadí závislostí služeb.

Tyto koncové body byly vytvořeny pomocí vážených sad záznamů DNS, které měly CNAME odkazující na každý nový ELB. Pro přepnutí jsme přidali nový záznam ukazující na nový ELB služby Kubernetes s vahou 0. Poté jsme nastavili Time To Live (TTL) záznamu nastaveného na 0. Poté byly staré a nové váhy pomalu upravoval a nakonec bylo 100 % zátěže odesláno na nový server. Po dokončení přepínání se hodnota TTL vrátila na adekvátnější úroveň.

Moduly Java, které jsme měli, si dokázaly poradit s nízkým TTL DNS, ale aplikace Node ne. Jeden z inženýrů přepsal část kódu fondu připojení a zabalil jej do správce, který aktualizoval fondy každých 60 sekund. Zvolený přístup fungoval velmi dobře a bez znatelného snížení výkonu.

Lekce

Limity sítě

Brzy ráno 8. ledna 2019 nečekaně havarovala platforma Tinder. V reakci na nesouvisející zvýšení latence platformy dříve toho rána se počet podů a uzlů v clusteru zvýšil. To způsobilo vyčerpání mezipaměti ARP na všech našich uzlech.

Existují tři možnosti Linuxu související s mezipamětí ARP:

Přechod Tinder na Kubernetes
(zdroj)

gc_thresh3 - to je tvrdý limit. Vzhled položek „přetečení tabulky sousedů“ v protokolu znamenal, že i po synchronním shromažďování odpadků (GC) nebylo v mezipaměti ARP dostatek místa pro uložení sousední položky. V tomto případě jádro jednoduše zahodilo paket úplně.

Používáme Flanel jako síťová struktura v Kubernetes. Pakety jsou přenášeny přes VXLAN. VXLAN je tunel L2 nad sítí L3. Technologie využívá zapouzdření MAC-in-UDP (MAC Address-in-User Datagram Protocol) a umožňuje rozšíření segmentů sítě na druhé vrstvě. Transportní protokol ve fyzické síti datového centra je IP plus UDP.

Přechod Tinder na Kubernetes
Obrázek 2-1. Flanelový diagram (zdroj)

Přechod Tinder na Kubernetes
Obrázek 2–2. Balíček VXLAN (zdroj)

Každý pracovní uzel Kubernetes přiděluje virtuální adresní prostor s maskou /24 z většího bloku /9. Pro každý uzel je to tak rozumí jeden záznam ve směrovací tabulce, jeden záznam v tabulce ARP (na rozhraní flanel.1) a jeden záznam v přepínací tabulce (FDB). Jsou přidány při prvním spuštění pracovního uzlu nebo pokaždé, když je objeven nový uzel.

Navíc komunikace mezi node-pod (nebo pod-pod) nakonec prochází rozhraním eth0 (jak je znázorněno na Flanelově diagramu výše). To má za následek další položku v tabulce ARP pro každý odpovídající zdrojový a cílový hostitel.

V našem prostředí je tento typ komunikace velmi běžný. Pro objekty služeb v Kubernetes se vytvoří ELB a Kubernetes zaregistruje každý uzel u ELB. ELB neví nic o podech a vybraný uzel nemusí být konečným cílem paketu. Jde o to, že když uzel přijme paket z ELB, zváží to s ohledem na pravidla iptables pro konkrétní službu a náhodně vybere pod na jiném uzlu.

V době selhání bylo v clusteru 605 uzlů. Z výše uvedených důvodů to stačilo k překonání významu gc_thresh3, což je výchozí nastavení. Když k tomu dojde, začnou se nejen zahazovat pakety, ale z tabulky ARP zmizí celý virtuální adresní prostor Flannel s maskou /24. Komunikace mezi uzly a dotazy DNS jsou přerušeny (DNS je hostován v clusteru; podrobnosti si přečtěte dále v tomto článku).

Chcete-li tento problém vyřešit, musíte zvýšit hodnoty gc_thresh1, gc_thresh2 и gc_thresh3 a restartujte Flannel, abyste znovu zaregistrovali chybějící sítě.

Neočekávané škálování DNS

Během procesu migrace jsme aktivně využívali DNS ke správě provozu a postupnému přenosu služeb ze staré infrastruktury do Kubernetes. Nastavili jsme relativně nízké hodnoty TTL pro související sady záznamů v Route53. Když stará infrastruktura běžela na instancích EC2, naše konfigurace resolveru ukazovala na Amazon DNS. Považovali jsme to za samozřejmost a dopad nízkého TTL na naše služby a služby Amazonu (jako je DynamoDB) zůstal do značné míry bez povšimnutí.

Když jsme migrovali služby na Kubernetes, zjistili jsme, že DNS zpracovávalo 250 tisíc požadavků za sekundu. V důsledku toho aplikace začaly docházet k neustálým a vážným časovým limitům pro dotazy DNS. Stalo se tak i přes neuvěřitelné úsilí o optimalizaci a přepnutí poskytovatele DNS na CoreDNS (který ve špičkové zátěži dosáhl 1000 modulů běžících na 120 jádrech).

Při zkoumání dalších možných příčin a řešení jsme zjistili Článek, popisující závodní podmínky ovlivňující rámec filtrování paketů netfilter v Linuxu. Časové limity, které jsme pozorovali, spolu s rostoucím počítadlem insert_failed ve flanelovém rozhraní byly v souladu se zjištěními v článku.

Problém nastává ve fázi překladu zdrojové a cílové síťové adresy (SNAT a DNAT) a následného zápisu do tabulky Conntrack. Jedním z interně diskutovaných řešení a navržených komunitou bylo přesunout DNS do samotného pracovního uzlu. V tomto případě:

  • SNAT není potřeba, protože provoz zůstává uvnitř uzlu. Nemusí být směrován přes rozhraní eth0.
  • DNAT není potřeba, protože cílová IP je lokální pro uzel, a ne náhodně vybraný modul podle pravidel iptables.

Rozhodli jsme se zůstat u tohoto přístupu. CoreDNS byl nasazen jako DaemonSet v Kubernetes a implementovali jsme lokální server DNS uzlu v vyřešit.conf každý modul nastavením vlajky --cluster-dns týmy kubelet . Toto řešení se ukázalo jako efektivní pro časové limity DNS.

Stále jsme však viděli ztrátu paketů a nárůst počítadla insert_failed v rozhraní Flanel. To pokračovalo po implementaci tohoto řešení, protože jsme byli schopni eliminovat SNAT a/nebo DNAT pouze pro provoz DNS. Závodní podmínky byly zachovány pro ostatní druhy provozu. Naštěstí většina našich paketů je TCP a pokud dojde k problému, jsou jednoduše znovu odeslány. Stále se snažíme najít vhodné řešení pro všechny druhy dopravy.

Použití Envoy pro lepší vyrovnávání zátěže

Když jsme migrovali backendové služby na Kubernetes, začali jsme trpět nevyváženou zátěží mezi moduly. Zjistili jsme, že HTTP Keepalive způsobilo, že připojení ELB visela na prvních připravených modulech každého nasazení. Převážná část provozu tedy procházela malým procentem dostupných modulů. Prvním řešením, které jsme testovali, bylo nastavení MaxSurge na 100 % u nových nasazení pro nejhorší možné scénáře. Efekt se z hlediska většího nasazení ukázal jako nevýznamný a neperspektivní.

Dalším řešením, které jsme použili, bylo umělé zvýšení požadavků na zdroje pro kritické služby. V tomto případě by moduly umístěné poblíž měly více prostoru pro manévrování ve srovnání s jinými těžkými moduly. Nefungovalo by to ani dlouhodobě, protože by to bylo plýtvání zdroji. Naše aplikace Node byly navíc jednovláknové, a proto mohly používat pouze jedno jádro. Jediným skutečným řešením bylo použití lepšího vyvažování zátěže.

Dlouho jsme chtěli plně ocenit Vyslanec. Současná situace nám umožnila jej nasadit velmi omezeně a získat okamžité výsledky. Envoy je vysoce výkonný server proxy s otevřeným zdrojovým kódem vrstvy XNUMX určený pro velké aplikace SOA. Může implementovat pokročilé techniky vyvažování zátěže, včetně automatického opakování, jističů a globálního omezení rychlosti. (Poznámka. přel.: Více si o tom můžete přečíst v tento článek o Istio, který je založen na Envoy.)

Přišli jsme s následující konfigurací: mít postranní vozík Envoy pro každý modul a jednu trasu a připojit cluster ke kontejneru lokálně přes port. Abychom minimalizovali potenciální kaskádování a zachovali malý dosah, použili jsme flotilu předních proxy modulů Envoy, jeden na zónu dostupnosti (AZ) pro každou službu. Spoléhali na jednoduchý nástroj pro vyhledávání služeb napsaný jedním z našich inženýrů, který jednoduše vrátil seznam modulů v každém AZ pro danou službu.

Service front-Envoys pak použili tento mechanismus zjišťování služeb s jedním upstream clusterem a směrováním. Nastavili jsme adekvátní časové limity, zvýšili všechna nastavení jističů a přidali konfiguraci minimálního opakování, abychom pomohli s jednotlivými poruchami a zajistili hladké nasazení. Umístili jsme TCP ELB před každého z těchto služebních front-Envoys. I když se udržování naživu z naší hlavní proxy vrstvy zaseklo na některých Envoy podech, stále byly schopny zvládat zátěž mnohem lépe a byly nakonfigurovány tak, aby vyvažovaly prostřednictvím less_request v backendu.

Pro nasazení jsme použili háček preStop na aplikačních podstavcích i postranních podvozcích. Hák spustil chybu při kontrole stavu koncového bodu správce umístěného na kontejneru postranního vozíku a na chvíli usnul, aby umožnil ukončení aktivních připojení.

Jedním z důvodů, proč jsme byli schopni přejít tak rychle, jsou podrobné metriky, které jsme byli schopni snadno integrovat do typické instalace Prometheus. To nám umožnilo přesně vidět, co se děje, zatímco jsme upravovali konfigurační parametry a přerozdělovali provoz.

Výsledky byly okamžité a zřejmé. Začali jsme s nejnevyváženějšími službami a v současnosti působí před 12 nejdůležitějšími službami v clusteru. V letošním roce plánujeme přechod na síť plných služeb s pokročilejším zjišťováním služeb, přerušením obvodu, detekcí odlehlých hodnot, omezením rychlosti a sledováním.

Přechod Tinder na Kubernetes
Obrázek 3-1. CPU konvergence jedné služby při přechodu na Envoy

Přechod Tinder na Kubernetes

Přechod Tinder na Kubernetes

Konečný výsledek

Díky těmto zkušenostem a dalšímu výzkumu jsme vybudovali silný tým infrastruktury se silnými dovednostmi v navrhování, nasazování a provozování velkých clusterů Kubernetes. Všichni inženýři Tinderu nyní mají znalosti a zkušenosti s balením kontejnerů a nasazením aplikací do Kubernetes.

Když vznikla potřeba další kapacity na staré infrastruktuře, museli jsme několik minut čekat na spuštění nových instancí EC2. Nyní se kontejnery rozběhnou a začnou zpracovávat provoz během několika sekund, nikoli minut. Naplánování více kontejnerů v jedné instanci EC2 také poskytuje zlepšenou horizontální koncentraci. V důsledku toho předpovídáme výrazné snížení nákladů EC2019 v roce 2 ve srovnání s loňským rokem.

Migrace trvala téměř dva roky, ale dokončili jsme ji v březnu 2019. V současnosti platforma Tinder běží výhradně na clusteru Kubernetes sestávajícím z 200 služeb, 1000 15 uzlů, 000 48 podů a 000 XNUMX běžících kontejnerů. Infrastruktura již není jedinou doménou operačních týmů. Všichni naši inženýři sdílejí tuto odpovědnost a řídí proces vytváření a nasazování svých aplikací pouze pomocí kódu.

PS od překladatele

Přečtěte si také sérii článků na našem blogu:

Zdroj: www.habr.com

Přidat komentář