„Tinder“ perėjimas prie „Kubernetes“.

Pastaba. vert.: Visame pasaulyje žinomos „Tinder“ tarnybos darbuotojai neseniai pasidalino techninėmis savo infrastruktūros perkėlimo į „Kubernetes“ detalėmis. Procesas užtruko beveik dvejus metus ir jo rezultatas buvo labai didelio masto platforma K8, kurią sudaro 200 paslaugų, talpinamų 48 tūkst. konteinerių. Su kokiais įdomiais sunkumais susidūrė „Tinder“ inžinieriai ir kokių rezultatų jie pasiekė? Perskaitykite šį vertimą.

„Tinder“ perėjimas prie „Kubernetes“.

Kodėl?

Почти два года назад Tinder решил перевести свою платформу на Kubernetes. Kubernetes позволил бы команде Tinder провести контейнеризацию и перейти на эксплуатацию с минимальными усилиями посредством неизменного развертывания (nekintama dislokacija). В этом случае сборка приложений, их деплой и сама инфраструктура были бы однозначно определены кодом.

Taip pat ieškojome mastelio ir stabilumo problemos sprendimo. Kai mastelio keitimas tapo kritinis, dažnai turėjome palaukti kelias minutes, kol atsiras nauji EC2 egzemplioriai. Idėja paleisti konteinerius ir pradėti aptarnauti srautą per kelias sekundes, o ne minutes, mums tapo labai patraukli.

Procesas pasirodė sudėtingas. Per mūsų migraciją 2019 m. pradžioje „Kubernetes“ klasteris pasiekė kritinę masę ir pradėjome susidurti su įvairiomis problemomis dėl srauto apimties, klasterio dydžio ir DNS. Pakeliui išsprendėme daug įdomių problemų, susijusių su 200 paslaugų perkėlimu ir Kubernetes klasterio, susidedančio iš 1000 mazgų, 15000 48000 podų ir XNUMX XNUMX veikiančių konteinerių, priežiūra.

Kaip tai padaryti?

Начиная с января 2018-го, мы прошли через различные этапы миграции. Мы начали с контейнеризации всех наших сервисов и их развертывания в тестовых облачных окружениях Kubernetes. Начиная с октября, мы начали методически переносить все существующие сервисы в Kubernetes. К марту следующего года мы закончили «переселение» и теперь платформа Tinder работает исключительно на Kubernetes.

„Kubernetes“ vaizdų kūrimas

У нас более 30 репозиториев исходного кода для микросервисов, работающих в кластере Kubernetes. Код в этих репозиториях написан на разных языках (например, на Node.js, Java, Scala, Go) со множеством runtime-окружений для одного и того же языка.

Sukūrimo sistema sukurta taip, kad kiekvienai mikro paslaugai būtų visiškai pritaikomas „kūrimo kontekstas“. Paprastai jį sudaro Dockerfile ir apvalkalo komandų sąrašas. Jų turinys yra visiškai pritaikomas, o tuo pačiu metu visi šie kūrimo kontekstai yra parašyti pagal standartizuotą formatą. Standartizavus kūrimo kontekstus, viena kūrimo sistema gali tvarkyti visas mikropaslaugas.

„Tinder“ perėjimas prie „Kubernetes“.
1-1 pav. Standartizuotas kūrimo procesas naudojant Builder konteinerį

Norėdami pasiekti maksimalų vykdymo laiko nuoseklumą (vykdymo aplinkos) один и тот же процесс сборки используется во время разработки и тестирования. Мы столкнулись с очень интересной задачей: пришлось разработать способ, гарантирующий согласованность сборочной среды по всей платформе. Для этого все сборочные процессы проводятся внутри специального контейнера Statybininkas.

Jo konteinerio diegimui reikėjo pažangių „Docker“ metodų. Builder paveldi vietinį vartotojo ID ir paslaptis (pvz., SSH raktą, AWS kredencialus ir kt.), reikalingus norint pasiekti privačias „Tinder“ saugyklas. Jis prijungia vietinius katalogus, kuriuose yra šaltinių, kad natūraliai saugotų kūrimo artefaktus. Šis metodas pagerina našumą, nes pašalina būtinybę kopijuoti kūrimo artefaktus tarp Builder konteinerio ir pagrindinio kompiuterio. Išsaugotus kūrimo artefaktus galima pakartotinai naudoti be papildomos konfigūracijos.

Для некоторых сервисов нам пришлось создавать еще один контейнер, чтобы сопоставить среду компиляции со средой выполнения (например, в процессе установки библиотека Node.js bcrypt генерирует специфичные для платформы бинарные артефакты). В процессе компиляции требования могут различаться для разных сервисов, и конечный Dockerfile составляется на лету.

Kubernetes klasterio architektūra ir migracija

Klasterio dydžio valdymas

Mes nusprendėme naudoti kube-aws automatiniam klasterio diegimui Amazon EC2 egzemplioriuose. Pačioje pradžioje viskas veikė viename bendrame mazgų telkinyje. Greitai supratome, kad norint efektyviau panaudoti išteklius, reikia atskirti darbo krūvius pagal dydį ir egzempliorių tipą. Logika buvo tokia, kad kelių įkeltų kelių sriegių rinkinių veikimas buvo labiau nuspėjamas našumo atžvilgiu, nei jų sambūvis su daugybe vienos sriegių talpyklų.

Galiausiai apsisprendėme:

  • m5.4xdidelis — stebėjimui (Prometėjas);
  • c5.4xdidelis - Node.js darbo krūviui (vienos gijos darbo krūviui);
  • c5.2xdidelis - „Java“ ir „Go“ (kelių gijų darbo krūvis);
  • c5.4xdidelis — valdymo pultui (3 mazgai).

Migracija

Vienas iš parengiamųjų žingsnių pereinant iš senosios infrastruktūros į „Kubernetes“ buvo peradresuoti esamą tiesioginį ryšį tarp paslaugų į naujus apkrovos balansavimo įrenginius (Elastic Load Balancers (ELB). Jie buvo sukurti tam tikrame virtualaus privataus debesies (VPC) potinklyje. Šis potinklis buvo prijungtas prie Kubernetes VPC. Tai leido mums perkelti modulius palaipsniui, neatsižvelgiant į konkrečią paslaugų priklausomybių tvarką.

Šie galiniai taškai buvo sukurti naudojant svertinius DNS įrašų rinkinius, kuriuose buvo CNAME, nukreipiantys į kiekvieną naują ELB. Norėdami perjungti, įtraukėme naują įrašą, nurodantį naują Kubernetes paslaugos ELB, kurio svoris yra 0. Tada nustatėme įrašo rinkinio laiką gyventi (TTL) į 0. Po to buvo nustatyti senieji ir naujieji svoriai. lėtai koreguojamas ir galiausiai 100% apkrovos buvo išsiųsta į naują serverį. Kai perjungimas buvo baigtas, TTL reikšmė grįžo į tinkamesnį lygį.

Mūsų turimi „Java“ moduliai galėjo susidoroti su žemu TTL DNS, bet „Node“ programos negalėjo. Vienas iš inžinierių perrašė dalį ryšio telkinio kodo ir įdėjo jį į tvarkyklę, kuri atnaujindavo telkinius kas 60 sekundžių. Pasirinktas metodas veikė labai gerai ir be jokio pastebimo veikimo pablogėjimo.

Pamokos

Tinklo audinio ribos

Ранним утром 8 января 2019 года платформа Tinder неожиданно «упала». В ответ на несвязанное увеличение времени ожидания платформы ранее тем же утром в кластере возросло число pod’ов и узлов. Это привело к исчерпанию кэша ARP на всех наших узлах.

Yra trys „Linux“ parinktys, susijusios su ARP talpykla:

„Tinder“ perėjimas prie „Kubernetes“.
(šaltinis)

gc_thresh3 – tai griežta riba. „Kaimyninės lentelės perpildymo“ įrašų atsiradimas žurnale reiškė, kad net ir po sinchroninio šiukšlių surinkimo (GC), ARP talpykloje nebuvo pakankamai vietos kaimyniniam įrašui saugoti. Šiuo atveju branduolys tiesiog visiškai išmetė paketą.

Mes naudojame Flanelė в качестве сетевой фабрики (network fabric) в Kubernetes. Пакеты передаются через VXLAN. VXLAN представляет собой L2-тоннель, поднятый поверх L3-сети. Технология использует инкапсуляцию MAC-in-UDP (MAC Address-in-User Datagram Protocol) и позволяет расширять сетевые сегменты 2-го уровня. Транспортный протокол в физической сети центра обработки данных — IP плюс UDP.

„Tinder“ perėjimas prie „Kubernetes“.
2-1 pav. Flanelės diagrama (šaltinis)

„Tinder“ perėjimas prie „Kubernetes“.
2-2 pav. VXLAN paketas (šaltinis)

Каждый рабочий узел Kubernetes выделяет виртуальное адресное пространство с маской /24 из большего блока /9. Для каждого узла это reiškia, одну запись в таблице маршрутизации, одну запись в таблице ARP (на интерфейсе flannel.1) и одну запись в таблице коммутации (FDB). Они добавляются при первом запуске рабочего узла или при обнаружении каждого нового узла.

Be to, mazgo-pod (arba pod-pod) ryšys galiausiai vyksta per sąsają eth0 (как показано на диаграмме Flannel выше). Это приводит к появлению дополнительной записи в таблице ARP для каждого соответствующего источника и адресата узла.

В нашей среде подобный тип связи весьма распространен. Для объектов типа сервис в Kubernetes создается ELB и Kubernetes регистрирует каждый узел в ELB. ELB ничего не знает о pod’ах и выбранный узел может не являться конечным пунктом назначения пакета. Дело в том, что когда узел получает пакет от ELB, он рассматривает его с учетом правил iptables konkrečiai paslaugai ir atsitiktinai pasirenka bloką kitame mazge.

На момент сбоя в кластере было 605 узлов. По причинам, изложенным выше, этого оказалось достаточно, чтобы преодолеть значение gc_thresh3, kuris yra numatytasis. Kai taip nutinka, ne tik pradedami numesti paketai, bet ir visa „Flanel“ virtualioji adresų erdvė su /24 kauke dingsta iš ARP lentelės. Nutrūksta mazgo-pod komunikacijos ir DNS užklausos (DNS yra priglobtas klasteryje; daugiau skaitykite šiame straipsnyje).

Norėdami išspręsti šią problemą, turite padidinti reikšmes gc_thresh1, gc_thresh2 и gc_thresh3 ir iš naujo paleiskite „Flanel“, kad iš naujo užregistruotumėte trūkstamus tinklus.

Netikėtas DNS mastelio keitimas

Perkėlimo proceso metu mes aktyviai naudojome DNS srautui valdyti ir palaipsniui perkelti paslaugas iš senos infrastruktūros į Kubernetes. Mes nustatėme palyginti mažas TTL reikšmes susijusiems įrašų rinkiniams maršrute53. Kai senoji infrastruktūra veikė EC2 egzemplioriuose, mūsų sprendiklio konfigūracija nurodė Amazon DNS. Laikėme tai savaime suprantamu dalyku, o žemo TTL įtaka mūsų paslaugoms ir „Amazon“ paslaugoms (pvz., „DynamoDB“) buvo beveik nepastebėta.

По мере переноса сервисов в Kubernetes мы обнаружили, что DNS обрабатывает по 250 тысяч запросов в секунду. В результате приложения стали испытывать постоянные и серьезные timeout’ы по DNS-запросам. Это произошло несмотря на неимоверные усилия по оптимизации и переключению DNS-провайдера на CoreDNS (который на пике нагрузки достиг 1000 pod’ов, работающих на 120 ядрах).

Tyrinėdami kitas galimas priežastis ir sprendimus, mes atradome straipsnis, aprašančios lenktynių sąlygas, turinčias įtakos paketų filtravimo sistemai tinklo filtras Linux sistemoje. Pastebėtas skirtasis laikas kartu su didėjančiu skaitikliu įterpti_nepavyko Flanel sąsajoje atitiko straipsnio išvadas.

Проблема возникает на этапе Source и Destination Network Address Translation (SNAT и DNAT) и последующего внесения в таблицу sutraukti. Одним из обходных путей, обсуждавшемся внутри компании и предложенным сообществом, стал перенос DNS на сам рабочий узел. В этом случае:

  • SNAT nereikia, nes srautas lieka mazgo viduje. Jo nereikia nukreipti per sąsają eth0.
  • DNAT не нужен, поскольку IP адресата является локальным для узла, а не случайно выбранным pod’ом по правилам iptables.

Мы решили придерживаться этого подхода. CoreDNS был развернут как DaemonSet в Kubernetes и мы внедрили локальный DNS-сервер узла в rezoliucija.conf kiekvieną ankštį nustatydami vėliavėlę --cluster-dns komandos kubelis . Šis sprendimas pasirodė esąs veiksmingas DNS skirtajam laikui.

Tačiau mes vis tiek matėme paketų praradimą ir skaitiklio padidėjimą įterpti_nepavyko в интерфейсе Flannel. Такое положение сохранялось и после внедрения обходного пути, поскольку мы сумели исключить SNAT и/или DNAT только для DNS-трафика. Race conditions сохранялись для других типов трафика. К счастью, большинство пакетов у нас — TCP, и при возникновении проблемы они просто передаются повторно. Мы до сих пор пытаемся найти подходящее решение для всех типов трафика.

Pasiuntinio naudojimas geresniam apkrovos balansavimui

Kai perkėlėme atgalines paslaugas į „Kubernetes“, pradėjome kentėti dėl nesubalansuotos apkrovos tarp podių. Pastebėjome, kad dėl HTTP Keepalive ELB ryšiai pakibo ant pirmųjų paruoštų kiekvieno įdiegimo blokų. Taigi didžioji srauto dalis vyko per nedidelę procentinę galimų rinkinių dalį. Pirmasis mūsų išbandytas sprendimas buvo MaxSurge nustatymas iki 100% naujiems diegimams blogiausiu atveju. Poveikis pasirodė esąs nereikšmingas ir nežadantis didesnių dislokacijų.

Kitas sprendimas, kurį naudojome, buvo dirbtinai padidinti svarbiausių paslaugų išteklių užklausas. Tokiu atveju šalia pastatytos ankštys turėtų daugiau erdvės manevruoti, palyginti su kitomis sunkiomis ankštimis. Ilgainiui tai taip pat neveiks, nes tai būtų išteklių švaistymas. Be to, mūsų „Node“ programos buvo vienos gijos ir atitinkamai galėjo naudoti tik vieną branduolį. Vienintelis tikras sprendimas buvo naudoti geresnį apkrovos balansavimą.

Mes jau seniai norėjome visapusiškai įvertinti pasiuntinys. Сложившаяся ситуация позволила нам развернуть его крайне ограниченным образом и получить незамедлительные результаты. Envoy — это высокопроизводительный прокси седьмого уровня с открытым исходным кодом, разработанный для крупных SOA-приложений. Он умеет применять передовые методы балансировки нагрузки, включая автоматические повторы, circuit breakers и глобальное ограничение скорости. (Pastaba. vert.: Daugiau apie tai galite perskaityti Šis straipsnis apie Istio, kuris yra pagrįstas pasiuntiniu.)

Mes sugalvojome tokią konfigūraciją: turėti Envoy šoninį priekabą kiekvienam blokui ir vienam maršrutui, ir prijungti klasterį prie konteinerio vietoje per prievadą. Siekdami sumažinti galimą pakopą ir išlaikyti nedidelį pataikymo spindulį, kiekvienai paslaugai naudojome Envoy priekinių tarpinių serverių parką, po vieną kiekvienoje prieinamumo zonoje (AZ). Jie rėmėsi paprastu paslaugų aptikimo varikliu, kurį parašė vienas iš mūsų inžinierių, kuris tiesiog pateikė kiekvienos AZ tam tikros paslaugos blokų sąrašą.

Tada tarnybų pasiuntiniai naudojo šį paslaugų aptikimo mechanizmą su vienu priešpriešiniu grupe ir maršrutu. Nustatėme tinkamus skirtuosius laikus, padidinome visus grandinės pertraukiklio nustatymus ir pridėjome minimalią pakartotinio bandymo konfigūraciją, kad padėtų kilti pavieniams gedimams ir būtų užtikrintas sklandus diegimas. Prieš kiekvieną iš šių tarnybų pasiuntinių padėjome TCP ELB. Net jei „Keepalive“ iš mūsų pagrindinio tarpinio serverio sluoksnio įstrigo kai kuriuose „Envoy“ blokuose, jie vis tiek galėjo daug geriau atlaikyti apkrovą ir buvo sukonfigūruoti taip, kad balansuotų naudojant „lest_request“ užpakalinėje sistemoje.

Diegimui naudojome „preStop“ kabliuką tiek ant aplikacijų, tiek ant šoninių priekabų laikiklių. Kablys sukėlė klaidą tikrinant administratoriaus galinio taško, esančio ant šoninio priekabos konteinerio, būseną ir kurį laiką užmigo, kad būtų galima nutraukti aktyvius ryšius.

Viena iš priežasčių, kodėl galėjome judėti taip greitai, yra dėl detalių metrikų, kurias galėjome lengvai integruoti į tipišką „Prometheus“ įrenginį. Tai leido mums tiksliai pamatyti, kas vyksta, kai koregavome konfigūracijos parametrus ir perskirstėme srautą.

Результаты были незамедлительными и очевидными. Мы начали с самых несбалансированных сервисов, а на данный момент он функционирует уже перед 12 самыми важными сервисами в кластере. В этом году мы планируем переход на полноценный service mesh с более продвинутым обнаружением сервисов, circuit breaking’ом, обнаружением выбросов, ограничением скорости и трассировкой.

„Tinder“ perėjimas prie „Kubernetes“.
3-1 pav. Vienos paslaugos procesoriaus konvergencija pereinant prie Envoy

„Tinder“ perėjimas prie „Kubernetes“.

„Tinder“ perėjimas prie „Kubernetes“.

Galutinis rezultatas

Pasitelkę šią patirtį ir papildomus tyrimus sukūrėme stiprią infrastruktūros komandą, turinčią stiprių įgūdžių projektuojant, diegiant ir eksploatuojant didelius „Kubernetes“ grupes. Visi „Tinder“ inžinieriai dabar turi žinių ir patirties pakuoti konteinerius ir įdiegti programas „Kubernetes“.

Kai senoje infrastruktūroje atsirado papildomų pajėgumų poreikis, teko laukti kelias minutes, kol bus paleistas naujas EC2 egzempliorius. Dabar konteineriai pradeda veikti ir srautas pradedamas apdoroti per kelias sekundes, o ne minutes. Suplanavus kelis konteinerius viename EC2 egzemplioriuje taip pat pagerinama horizontali koncentracija. Dėl to 2019 m., palyginti su praėjusiais metais, prognozuojame reikšmingą EC2 sąnaudų sumažėjimą.

Perkėlimas truko beveik dvejus metus, bet baigėme 2019 m. kovo mėn. Šiuo metu „Tinder“ platforma veikia tik „Kubernetes“ klasteryje, kurį sudaro 200 paslaugų, 1000 15 mazgų, 000 48 blokų ir 000 XNUMX veikiančių konteinerių. Infrastruktūra nebėra vienintelė operacijų komandų sritis. Visi mūsų inžinieriai dalijasi šia atsakomybe ir kontroliuoja savo programų kūrimo ir diegimo procesą naudodami tik kodą.

PS iš vertėjo

Taip pat skaitykite straipsnių seriją mūsų tinklaraštyje:

Šaltinis: www.habr.com

Добавить комментарий