Den Tinder ass op Kubernetes geplënnert

Schrëftlech vum: Chris O'Brien, Ingenieur Manager | Chris Thomas, Ingenieur Manager | Jinyong Lee, Senior Software Ingenieur | Geännert Vun: Cooper Jackson, Software Ingenieur

Firwat

Viru bal zwee Joer huet den Tinder beschloss seng Plattform op Kubernetes ze plënneren. Kubernetes huet eis eng Chance ginn Tinder Engineering Richtung Containeriséierung a Low-Touch Operatioun duerch onverännerbar Deployment ze féieren. Applikatioun bauen, Détachement, an Infrastruktur géif als Code definéiert ginn.

Mir hunn och gesicht fir Erausfuerderunge vun Skala a Stabilitéit unzegoen. Wann d'Skaléieren kritesch ginn, hu mir dacks duerch e puer Minutte gelaacht fir nei EC2 Instanzen online ze kommen. D'Iddi fir Container ze plangen an den Traffic bannent Sekonnen ze verdeedegen am Géigesaz zu Minutte war eis gefleegter.

Et war net einfach. Wärend eiser Migratioun am fréien 2019 erreeche mir kritesch Mass an eisem Kubernetes Stärekoup an hunn ugefaang mat verschiddenen Erausfuerderungen opgrond vum Trafficvolumen, Clustergréisst an DNS. Mir hunn interessant Erausfuerderunge geléist fir 200 Servicer ze migréieren an e Kubernetes Stärekoup op Skala vun insgesamt 1000 Noden, 15.000 Pods, an 48.000 Runcontainer ze bedreiwen.

Wéi geet dat

Ab Januar 2018 hu mir eis duerch verschidden Etappe vun der Migratiounseffort geschafft. Mir hunn ugefaang mat all eise Servicer ze Containeréieren an se an eng Serie vu Kubernetes gehost Staging-Ëmfeld z'installéieren. Ufank Oktober hu mir methodesch ugefaang all eis Legacy Servicer op Kubernetes ze plënneren. Bis de Mäerz d'nächst Joer finaliséiert eis Migratioun an d'Tinder Plattform leeft elo exklusiv op Kubernetes.

Bauen Biller fir Kubernetes

Et gi méi wéi 30 Quellcode Repositories fir d'Microservicer déi am Kubernetes Cluster lafen. De Code an dëse Repositories ass a verschiddene Sprooche geschriwwe ginn (z. B. Node.js, Java, Scala, Go) mat verschiddene Runtime Ëmfeld fir déiselwecht Sprooch.

De Build System ass entwéckelt fir e voll personaliséierbar "build context" fir all Mikroservice ze bedreiwen, wat normalerweis aus engem Dockerfile an enger Serie vu Shell Kommandoen besteet. Iwwerdeems hir Inhalter voll personaliséierbar sinn, ginn dës Build Kontexter all geschriwwen no engem standardiséierte Format. D'Standardiséierung vun de Build-Kontexter erméiglecht en eenzele Build-System fir all Mikroservicer ze verschaffen.

Figur 1-1 Standardiséierte Bauprozess duerch de Builder Container

Fir déi maximal Konsequenz tëscht runtime Ëmfeld z'erreechen, gëtt de selwechte Build Prozess benotzt während der Entwécklung an Testphase. Dëst huet eng eenzeg Erausfuerderung opgeluecht wa mir e Wee huele mussen auszerechnen fir e konsequent Bauëmfeld iwwer der Plattform ze garantéieren. Als Resultat ginn all Buildprozesser an engem speziellen "Builder" Container ausgefouert.

D'Ëmsetzung vum Builder Container erfuerdert eng Rei vun fortgeschratt Docker Techniken. Dëse Builder Container ierft lokal Benotzer ID a Geheimnisser (z. B. SSH Schlëssel, AWS Umeldungsinformatiounen, etc.) wéi néideg fir Zougang zu Tinder private Repositories. Et montéiert lokal Verzeechnungen, déi de Quellcode enthalen, fir en natierleche Wee fir Artefakte ze bauen. Dës Approche verbessert d'Performance, well se d'Kopie vun gebauter Artefakte tëscht dem Builder Container an der Hostmaschinn eliminéiert. Gelagert Build Artefakte ginn d'nächst Kéier ouni weider Konfiguratioun nei benotzt.

Fir gewësse Servicer musse mir en aneren Container am Builder erstellen fir de Compil-Zäit Ëmfeld mat der run-time Ëmfeld ze passen (z. B. d'Node.js bcrypt Bibliothéik installéiert generéiert Plattformspezifesch binäre Artefakte). D'Zesummesetzungszäit Ufuerderunge kënnen ënnerschiddlech vun de Servicer sinn an de finalen Dockerfile ass komponéiert.

Kubernetes Cluster Architecture And Migration

Stärekoup Gréissten

Mir hunn decidéiert Kube-aws fir automatiséiert Clusterpräventioun op Amazon EC2 Instanzen ze benotzen. Ufanks lafe mer alles an engem allgemenge Node Pool. Mir hunn séier d'Noutwendegkeet identifizéiert fir Aarbechtsloaden a verschiddene Gréissten an Aarte vun Instanzen ze trennen, fir d'Ressourcen besser ze notzen. D'Ursaach war datt manner schwéier threaded Pods zesumme lafen, méi prévisibel Leeschtungsresultater fir eis geliwwert hunn wéi se mat enger méi grousser Zuel vun single threaded Pods ze coexistéieren.

Mir hu sech ofgesat op:

  • m5.4xlarge fir Iwwerwaachung (Prometheus)
  • c5.4xlarge fir Node.js Aarbechtslaascht (Single-threaded Aarbechtslaascht)
  • c5.2xlarge fir Java a Go (Multi-threaded Aarbechtslaascht)
  • c5.4 Vergréisserung fir de Kontrollfliger (3 Wirbelen)

Migratioun

Ee vun de Virbereedungsschrëtt fir d'Migratioun vun eiser Legacy Infrastruktur op Kubernetes war déi existent Service-to-Service Kommunikatioun z'änneren fir op nei Elastesch Load Balancers (ELBs) ze weisen, déi an enger spezifescher Virtual Private Cloud (VPC) Subnet erstallt goufen. Dëse Subnet gouf op de Kubernetes VPC geprägt. Dëst huet eis erlaabt Moduler granuléiert ze migréieren ouni Bezuch op spezifesch Bestellung fir Service Ofhängegkeeten.

Dës Endpunkte goufe erstallt mat Hëllef vu gewichte DNS-Rekord-Sets déi e CNAME op all neien ELB weisen. Fir Ausschnëtter hu mer en neie Rekord bäigefüügt, wat op den neie Kubernetes Service ELB hiweist, mat engem Gewiicht vun 0. Mir hunn dunn den Time To Live (TTL) op de Rekordset op 0 gesat. Déi al an nei Gewiichter goufen dunn lues ajustéiert op schlussendlech mat 100% um neie Server ophalen. Nodeems de Cutover komplett war, war den TTL op eppes méi raisonnabel agestallt.

Eis Java Moduler hunn niddereg DNS TTL geéiert, awer eis Node Uwendungen hunn et net. Ee vun eisen Ingenieuren huet en Deel vum Verbindungspoolcode iwwerschriwwen, fir se an engem Manager ze verschwannen, déi de Pool all 60er erfrëscht. Dëst huet ganz gutt fir eis mat kee présentiven Leeschtungshit geschafft.

Léieren

Netzwierk Stoff Limiten

An de fréie Mueresstonne vum 8. Januar 2019 huet Tinder's Plattform e persistent Ausbroch gelidden. Als Äntwert op eng net relatéiert Erhéijung vun der Plattform latency fréi datt de Moien, Pod an Node Grofe goufen op de Koup geschrappt. Dëst huet zu enger ARP Cache Erschöpfung op all eise Wirbelen.

Et ginn dräi Linux Wäerter relevant fir den ARP Cache:

Kredit

gc_thresh3 ass eng schwéier Cap. Wann Dir "Noper-Dësch Iwwerschwemmung" Log-Entréen kritt, gëtt dat ugewisen datt och no enger synchroner Dreckskollektioun (GC) vun der ARP Cache, net genuch Plaz war fir de Nopeschgang ze späicheren. An dësem Fall fällt de Kärel just de Packet ganz erof.

Mir benotzen Flannel als eise Netzwierk an de Kubernetes. Packagen ginn iwwer VXLAN weidergeleet. VXLAN ass e Layer 2 Overlay Schema iwwer e Layer 3 Netz. Et benotzt MAC Address-in-User Datagram Protokoll (MAC-in-UDP) Verschlësselung fir e Mëttel ze ginn fir Layer 2 Netzwierksegmenter ze verlängeren. Den Transportprotokoll iwwer de physikaleschen Datenzenter Netz ass IP plus UDP.

Bild 2–1 Flannendiagramm (Kredit)

Bild 2–2 VXLAN Packet (Kreditt)

All Kubernetes Aarbechternode verdeelt säin eegene / 24 virtuelle Adressraum aus engem gréissere / 9 Block. Fir all Node resultéiert dëst an 1 Routtabell-Entrée, 1 ARP-Tabell-Entrée (op Flannel.1 Interface), an 1 Forwarding Datebank (FDB) Entrée. Dës gi bäigefüügt wann den Aarbechternode als éischt lancéiert oder wéi all neie Node entdeckt gëtt.

Zousätzlech fléisst Node-to-Pod (oder Pod-to-Pod) Kommunikatioun schlussendlech iwwer d'eth0 Interface (am Flannel Diagramm uewen beschriwwen). Dëst wäert eng zousätzlech Entrée an der ARP Tabelle fir all entspriechend Nodequell an Node Destinatioun resultéieren.

An eiser Ëmfeld ass dës Zort Kommunikatioun ganz heefeg. Fir eis Kubernetes Service Objete gëtt en ELB erstallt an Kubernetes registréiert all Node mat dem ELB. Den ELB ass net bewosst an den ausgewielten Node ass vläicht net de Paket seng lescht Destinatioun. Dëst ass well wann de Node de Paket vum ELB kritt, bewäert se seng iptables Reegele fir de Service a wielt zoufälleg e Pod op engem aneren Node.

Zu der Zäit vum Auslaaf waren et 605 Gesamtnoden am Stärekoup. Aus de Grënn uewe beschriwwen, war dëst genuch fir de Standard gc_thresh3 Wäert ze verduebelen. Wann dëst passéiert, ginn net nëmme Päckchen erofgelooss, mee ganz Flannel / 24s virtuell Adressraum feelen an der ARP Tabelle. Node fir Pod Kommunikatioun an DNS Lookups feelen. (DNS gëtt am Stärekoup gehost, wéi et méi spéit wäert an dësem Artikel erkläert ginn.)

Fir ze léisen, ginn d'gc_thresh1, gc_thresh2, an gc_thresh3 Wäerter opgeworf a Flannel muss nei gestart ginn fir fehlend Netzwierker nei z'registréieren.

Onerwaart leeft DNS op Skala

Fir eis Migratioun z'empfänken, huele mir DNS schwéier fir de Verkéiersform z'erliichteren an déi inkrementell Ausschnëtter vun der Legacy op Kubernetes fir eis Servicer ze erliichteren. Mir setzen relativ niddereg TTL Wäerter op den assoziéierten Route53 RecordSets. Wann mir eis Legacy Infrastruktur op EC2 Instanzen lafen, huet eis Resolutiounskonfiguratioun op Amazon's DNS gezeechent. Mir hunn dat selbstverständlech iwwerholl an d'Käschte vun engem relativ nidderegen TTL fir eis Servicer an Amazon Servicer (zB DynamoDB) ware gréisstendeels net gesi ginn.

Wéi mir méi a méi Servicer u Kubernetes onboarding gemaach hunn, hu mir eis en DNS Service lafen, deen op 250.000 Ufroe pro Sekonn geäntwert huet. Mir stoungen intermitteréierend an impactful DNS Lookout Timeouts bannent eisen Uwendungen. Dëst ass trotz engem ustrengenden Tuning Effort geschitt an en DNS Provider wiesselt op e CoreDNS Deployement deen eemol zu enger Héicht vun 1000 Pods verbraucht huet, déi 120 Cores verbrauchen.

Wärend aner méiglech Ursaachen a Léisunge fuerschen, hu mir en Artikel fonnt deen e Rennkonditioun beschreift, deen de Linux Packet Filtering Framework Netfilter beaflosst. D'DNS Timeouts, déi mir gesi hunn, zesumme mat engem inkrementéierende Insert_failed Konter op der Flannel-Interface, ausgeglach mat de Resultater vum Artikel.

De Problem geschitt während der Quell an der Destinatioun Netzwierk Adress Iwwersetzung (SNAT an DNAT) a spéider Insertioun an d'Contrack Tabelle. Eng Léisung intern diskutéiert a proposéiert vun der Gemeinschaft war d'DNS op den Aarbechterknode selwer ze beweegen. An dësem Fall:

  • SNAT ass net néideg, well de Traffic bleift lokal um Node. Et brauch net iwwer de eth0 Interface weiderginn.
  • DNAT ass net néideg, well d'Destinatioun IP lokal zum Node ass an net e zoufälleg gewielte Pod pro iptables Reegelen.

Mir hunn decidéiert mat dëser Approche weiderzekommen. CoreDNS gouf als DaemonSet a Kubernetes ofgesat a mir hunn den lokalen DNS Server vum Node an all resolv.conf vum Pod geïnjektéiert andeems de kubelet konfiguréiert - Cluster-dns Kommando Fändel. D'Léisung wier effektiv fir DNS Timeouts.

Wéi och ëmmer, mir gesinn nach erofgeloossene Päckchen an d'Flannel Interface's insert_failed Konter Inkrement. Dëst wäert och no der uewe genannter Léisung bestoe bleiwen well mir nëmmen SNAT an / oder DNAT fir den DNS-Traffic vermeiden. De Rennkonditioun wäert nach fir aner Zorte vu Verkéier optrieden. Glécklecherweis sinn déi meescht vun eise Packagen TCP a wann d'Conditioun geschitt ass, ginn d'Päck erfollegräich weidergeleet. Eng laangfristeg Fix fir all Zorte vu Verkéier ass eppes dat mir nach diskutéieren.

Uwendung vun Envoy Fir Besser Belaaschtung ze Balance

Wéi mir eis Backend Servicer op Kubernetes migréiert hunn, hunn mir ugefaang ënner onbalancéierter Last iwwer Pods ze leiden. Mir hunn entdeckt datt wéinst HTTP Keepalive, ELB Verbindunge stieche mat den éischte prett Bunnen vun all Rolling Deployment, sou datt de gréissten Traffic duerch e klenge Prozentsaz vun de verfügbaren Pods fléisst. Eng vun den éischten Ofsenkungen, déi mir probéiert hunn, war en 100% MaxSurge op nei Usetzungen fir déi schlëmmst Verbriecher ze benotzen. Dëst war marginell effektiv an net nohalteg laangfristeg mat e puer vun de méi groussen Distributiounen.

Eng aner Ofsenkung, déi mir benotzt hunn, war kënschtlech Ressourceufroen op kritesch Servicer z'entwéckelen, sou datt colocéiert pods méi Sëtzraum hätten niewent anere schwéieren Pods. Dëst war och net laangfristeg ze halen wéinst der Ressource Offall an eis Node Uwendungen goufe single threaded an doduerch effektiv op 1 Kär ofgekappt. Déi eenzeg kloer Léisung war e besseren Lastbalancéierung ze benotzen.

Mir haten intern gesicht fir den Envoy ze evaluéieren. Dëst huet eis eng Chance ginn se op eng ganz limitéiert Manéier z'installéieren an direkt Virdeeler ze kréien. Envoy ass eng Open Source, héich performant Layer 7 Proxy fir grouss Service orientéiert Architekturen. Et ass fäeg fortgeschratt Lastbelaaschtungstechniken z'installéieren, dorënner automatesch Versich, Circuit Break, a global Taux Limit.

D'Konfiguratioun mat där mir entstane sinn war en Envoy Sidecar niewent all Pod ze hunn déi eng Streck an e Stärekoup huet fir de lokalen Container Hafen ze schloen. Fir potenziell Kaskadéierung ze minimiséieren an e klengen Héichradius ze halen, hu mir eng Flott vu Proxy Provo-Envoy Pods benotzt, eng Déplacement an all Disponibilitéit Zone (AZ) fir all Service. Dës hu mat engem klengen Service Entdeckungsmechanismus geschloen, deen ee vun eisen Ingenieuren zesummegesat huet, déi einfach eng Lëscht mat Pods an all AZ fir e bestëmmten Service zréckginn.

De Service front-Envoys huet dunn dëse Service Entdeckungsmechanismus mat engem Upstream Cluster a Route benotzt. Mir konfiguréieren raisonnabel Timeouts, hu all d'Circuit Breaker-Astellunge gestäerkt, an dann an eng minimal Konfirmatioun nei gesat fir ze hëllefen mat transiente Feeler a glat Deployment. Mir hunn all dës Front Envoy Servicer mat engem TCP ELB frontéiert. Och wann de Keepalive vun eiser Haaptfront Proxy Schicht op bestëmmte Envoy Pods gespullt gouf, ware se vill besser d'Fäegkeet ze verschaffen an waren konfiguréiert fir iwwer de minste_request zum Backend ze balanséieren.

Fir Distributiounen hu mir e PreStop Hook op der Applikatioun souwéi dem Sidecar Pod benotzt. Dësen Hook genannt den Sidecar Gesondheetscheck feelt den Admin Endpunkt, zesumme mat engem klenge Schlof, fir e bëssen Zäit ze ginn fir de Inflight Verbindungen ze kompletéieren an ze verrennen.

Ee Grond firwat mer sou séier konnte réckelen war wéinst de räiche Metriken déi mir fäeg sinn einfach mat eisem normalen Prometheus Setup z'integréieren. Dëst huet eis erlaabt ze gesinn wat genau geschitt ass wéi mir d'Konfiguratiouns-Astellunge widderhuelen an de Verkéier ofgeschnidden hunn.

D'Resultater waren direkt an offensichtlech. Mir hu mat de meescht onbalancéierten Servicer ugefaang an hunn de Moment et virun zwielef vun de wichtegsten Servicer an eisem Stärekoup. Dëst Joer plangen mir op e Vollservice Mesh ze réckelen, mat méi fortgeschrattem Service Entdeckung, Circuit Break, Outlier Detektioun, Ratebegrenzung, an Tracing.

Figur 3–1 CPU Konvergenz vun engem Service wärend der Ausschnëtt fir Envoi

D'Enn Resultat

Duerch dës Léierungen an zousätzlech Fuerschung hu mir e staarkt internt Infrastruktur Team entwéckelt mat grousser Vertrautheet wéi Dir grouss Kubernetes Cluster designt, implementéiert an bedreift. D'Tinder ganz Ingenieursorganisatioun vun Tinder huet elo Wëssen an Erfarung, wéi een hir Uwendungen op Kubernetes kontainéiert an ofdriwwen.

Op eiser Legacy Infrastruktur, wann zousätzlech Skala noutwendeg war, hu mir dacks duerch e puer Minutte gelaacht fir nei EC2 Instanzen online ze kommen. Behälter plangen elo a servéiere Verkéier bannent Sekonnen am Géigesaz zu Minutten. Multiple Container plangen op enger eenzeger EC2 Instanz gëtt och eng verbessert horizontale Dicht. Als Resultat projizéiere mir substantiell Käschte spueren op EC2 am Joer 2019 am Verglach zum Joer virdrun.

Et huet bal zwee Joer gedauert, awer mir hunn eis Migratioun ofgeschloss am Mäerz 2019. D'Tinder Plattform leeft exklusiv an engem Kubernetes Stärekoup, bestehend aus 200 Servicer, 1.000 Noden, 15.000 Pods, an 48.000 Lafen Container. Infrastruktur ass net méi eng Aufgab reservéiert fir eis Operatiounsteams. Amplaz hunn Ingenieuren an der ganzer Organisatioun dës Verantwortung deelen an hunn d'Kontroll iwwer wéi hir Uwendungen gebaut an ofgestallt ginn mat allem als Code.