Преместването на Тиндър към Кубернети

Написано от: Крис О'Брайън, инженер мениджър | Крис Томас, инженер мениджър | Jinyong Lee, старши софтуерен инженер | Редактиран от: Купър Джексън, софтуерен инженер

Защо

Преди почти две години Tinder реши да премести платформата си в Kubernetes. Kubernetes ни предостави възможност да насочим Tinder Engineering към контейнеризация и работа с ниско докосване чрез неизменно внедряване. Създаването, внедряването и инфраструктурата на приложенията ще бъдат дефинирани като код.

Също така търсехме да се справим с предизвикателствата на мащаба и стабилността. Когато мащабирането стана критично, ние често страдахме от няколко минути в очакване новите EC2 случаи да дойдат онлайн. Идеята за насрочване на контейнери и обслужване на трафика в рамките на секунди, за разлика от минути, ни беше привлекателна.

Не беше лесно. По време на нашата миграция в началото на 2019 г. достигнахме критична маса в нашия клъбер Kubernetes и започнахме да срещаме различни предизвикателства поради обема на трафика, размера на клъстера и DNS. Решихме интересни предизвикателства да мигрираме 200 услуги и пускаме клъстер Kubernetes в мащаб, който обхваща 1000 възли, 15 000 шушулки и 48 000 работещи контейнери.

как

От януари 2018 г. ние работихме по различни етапи на миграционните усилия. Започнахме с контейнерирането на всички наши услуги и ги разположихме в серия Kubernetes, хоствани сценични среди. В началото на октомври започнахме методично да преместим всички наши наследствени услуги към Kubernetes. До март следващата година завършихме миграцията си и платформата Tinder вече работи изключително на Kubernetes.

Изграждане на изображения за Kubernetes

Има повече от 30 хранилища на изходния код за микросервизите, които се изпълняват в клъстер Kubernetes. Кодът в тези хранилища е написан на различни езици (например Node.js, Java, Scala, Go) с множество среда за изпълнение на един и същ език.

Системата за сглобяване е проектирана да работи на напълно адаптивен „контекст на изграждане“ за всяка микросервиз, който обикновено се състои от Dockerfile и поредица командни черупки. Въпреки че съдържанието им е напълно адаптивни, всички тези контексти за изграждане се записват, като се следва стандартизиран формат. Стандартизацията на контекстите на изграждане позволява една система за изграждане да работи с всички микросервизи.

Фигура 1–1 Стандартизиран процес на изграждане чрез контейнера Builder

За да се постигне максимална съгласуваност между средата на изпълнение, по време на фазата на разработване и тестване се използва един и същ процес на изграждане. Това наложи уникално предизвикателство, когато трябваше да измислим начин да гарантираме последователна среда за изграждане в цялата платформа. В резултат на това всички процеси на изграждане се изпълняват в специален контейнер „Builder“.

Внедряването на контейнера Builder изискваше редица усъвършенствани Docker техники. Този контейнер на Builder наследява локални потребителски идентификатори и секрети (напр. SSH ключ, AWS идентификационни данни и т.н.), както е необходимо за достъп до частни хранилища на Tinder. Той монтира локални директории, съдържащи изходния код, за да има естествен начин за съхраняване на изграждането на артефакти. Този подход подобрява производителността, тъй като елиминира копирането на вградени артефакти между контейнера Builder и хост машината. Съхранените артефакти за изграждане се използват повторно следващия път без допълнителна конфигурация.

За някои услуги трябваше да създадем друг контейнер в Builder, за да съответстваме на средата на компилиране с средата на изпълнение (например, инсталирането на библиотека bcrypt на Node.js генерира специфични за платформата бинарни артефакти). Изискванията за време за компилиране могат да се различават при различните услуги и крайният Dockerfile се съставя в движение.

Кубернетическа клъстерна архитектура и миграция

Оразмеряване на клъстера

Решихме да използваме kube-aws за автоматизирано предоставяне на клъстери в случаи на Amazon EC2. В началото ние стартирахме всичко в един общ пул от възли. Бързо установихме необходимостта от разделяне на натоварването в различни размери и видове случаи, за да използваме по-добре ресурсите. Мотивите бяха, че пускането на по-малко силно резбовани шушулки заедно даде по-предсказуеми резултати от производителността за нас, отколкото да им позволим да съществуват съвместно с по-голям брой еднорезцови шушулки.

Ние се настанихме на:

  • m5.4 уголемяване за мониторинг (Прометей)
  • c5.4 уголемяване за натоварване на Node.js (едноредов работен товар)
  • c5.2 уголемяване за Java и Go (многонишково натоварване)
  • c5.4 увеличение за контролната равнина (3 възли)

миграция

Една от стъпките за подготовка за миграцията от наследената ни инфраструктура към Kubernetes беше да се промени съществуващата комуникация между обслужване и да се насочи към нови еластични балансиращи натоварвания (ELBs), които бяха създадени в конкретна подмрежа на виртуалния частен облак (VPC). Тази подмрежа беше надничана към VPC на Kubernetes. Това ни позволи да мигрираме модулни модули без оглед на конкретно подреждане на зависимости от услуги.

Тези крайни точки са създадени с помощта на претеглени набори DNS записи, които имат CNAME, сочещи към всеки нов ELB. За прекъсване добавихме нов запис, насочен към новата услуга Kubernetes ELB, с тегло 0. След това зададохме Time To Live (TTL) на записа, зададен на 0. Старите и новите тегла бяха бавно коригирани на в крайна сметка се окаже със 100% на новия сървър. След като прекъсването приключи, TTL беше настроен на нещо по-разумно.

Нашите Java модули почетоха нисък DNS TTL, но нашите приложения на Node не. Един от нашите инженери пренаписа част от кода на пула за връзка, за да го превърне в мениджър, който да освежава басейните на всеки 60-те. Това се справи много добре за нас без забележителен хит за изпълнение.

обмен с

Ограничения за мрежови тъкани

В ранните сутрешни часове на 8 януари 2019 г. платформата на Tinder претърпя постоянен прекъсване. В отговор на несвързано увеличаване на латентността на платформата по-рано тази сутрин, броят на шушулките и възлите е мащабиран в клъстера. Това доведе до изтощение на кеш ARP на всички наши възли.

Има три стойности на Linux, свързани с кеша на ARP:

кредит

gc_thresh3 е твърда капачка. Ако получавате записи в журнала за „препълване на съседна таблица“, това показва, че дори след синхронно събиране на боклук (GC) на кеша на ARP, няма достатъчно място за съхранение на съседния запис. В този случай ядрото просто изпуска пакета изцяло.

Ние използваме Flannel като нашата мрежа от мрежи в Kubernetes. Пакетите се препращат през VXLAN. VXLAN е схема за наслагване на слой 2 в мрежа от слой 3. Той използва капсулирането на MAC адрес в потребителски протокол (MAC-in-UDP), за да осигури средство за разширяване на мрежовите сегменти на ниво 2. Транспортният протокол през мрежата за физически центрове за данни е IP плюс UDP.

Фигура 2–1 Фланелна диаграма (кредит)

Фигура 2–2 VXLAN пакет (кредит)

Всеки възел на Kubernetes работник разпределя собствено / 24 виртуално адресно пространство от по-голям / 9 блок. За всеки възел това води до 1 запис на таблица на маршрута, 1 запис на ARP таблица (на интерфейс flannel.1) и 1 запис на база данни за препращане (FDB). Те се добавят при първото стартиране на възела на работника или при откриване на всеки нов възел.

Освен това комуникацията между възел-под-или (под-под-под) в крайна сметка преминава през интерфейса eth0 (изобразен в диаграмата на Flannel по-горе). Това ще доведе до допълнителен запис в ARP таблицата за всеки съответния източник на възел и дестинация на възела.

В нашата среда този тип комуникация е много често срещана. За нашите сервизни обекти на Kubernetes се създава ELB и Kubernetes регистрира всеки възел с ELB. ELB не е наясно и избраният възел може да не е крайното местоназначение на пакета. Това е така, защото когато възелът получава пакета от ELB, той оценява правилата си за iptables за услугата и на случаен принцип избира шушулка на друг възел.

Към момента на прекъсването в клъстера е имало 605 общо възли. По гореописаните причини това беше достатъчно, за да затъмни стойността по подразбиране gc_thresh3. След като това се случи, не само отпадат пакетите, но и цялото Flannel / 24s виртуално адресно пространство липсва от таблицата на ARP. Комуникацията между възел към под и DNS търсене не се проваля. (DNS се хоства в клъстера, както ще бъде обяснено по-подробно по-нататък в тази статия.)

За да разрешите, стойностите gc_thresh1, gc_thresh2 и gc_thresh3 се повишават и Flannel трябва да се рестартира, за да се регистрира отново липсваща мрежа.

Неочаквано стартиране на DNS в мащаб

За да приспособим нашата миграция, ние използвахме сериозно DNS, за да улесним оформянето на трафика и постепенното прекъсване от наследството към Kubernetes за нашите услуги. Ние задаваме сравнително ниски стойности на TTL на свързаните Route53 RecordSets. Когато стартирахме наследената си инфраструктура на EC2 инстанции, нашата резолюция конфигурация сочи DNS на Amazon. Приехме това за даденост и разходите за сравнително нисък TTL за нашите услуги и услугите на Amazon (напр. DynamoDB) останаха почти незабелязани.

Докато се качвахме на все повече и повече услуги на Kubernetes, се оказахме, че използваме DNS услуга, която отговаряше на 250 000 заявки в секунда. Срещахме периодични и въздействащи DNS изчакване за търсене в рамките на нашите приложения. Това се случи въпреки изчерпателните усилия за настройка и преминаването на доставчик на DNS към внедряване на CoreDNS, което по едно време достигна максимален 1000 шушулки, консумиращи 120 ядра.

Докато изследвахме други възможни причини и решения, ние открихме статия, описваща състезателно състояние, засягащо Linux филтрирането на пакети netfilter. Времето за изчакване на DNS, което видяхме, заедно с увеличаване на брояча insert_failed на интерфейса на Flannel, приведено в съответствие с констатациите на статията.

Проблемът се появява по време на превода на мрежови адреси на източници и назначения (SNAT и DNAT) и последващо вмъкване в таблицата на контракцията. Едно решение, обсъдено вътрешно и предложено от общността, е да се премести DNS върху работния възел. В такъв случай:

  • SNAT не е необходим, тъй като трафикът се задържа локално на възела. Не е необходимо да се предава през интерфейса eth0.
  • DNAT не е необходим, тъй като IP за местоназначение е локален за възела, а не е произволно избран под под правилата на iptables.

Решихме да продължим напред с този подход. CoreDNS беше внедрен като DaemonSet в Kubernetes и ние инжектирахме локалния DNS сървър на възела във всеки подсвет на resv.conf, като конфигурирахме командния флаг kubelet - cluster-dns. Решението беше ефективно за изчакване на DNS.

Въпреки това, все още виждаме отпаднали пакети и прираст на брояча на вмъкване на_файл интерфейса на Flannel. Това ще продължи дори след горното решение, защото избягвахме само SNAT и / или DNAT за DNS трафик. Състояние на състезанието все още ще има за други видове трафик. За щастие повечето от нашите пакети са TCP и когато състоянието се случи, пакетите ще бъдат успешно препредадени. Дългосрочното поправяне на всички видове трафик е нещо, което все още обсъждаме.

Използване на пратеник за постигане на по-добро балансиране на натоварването

Докато мигрирахме нашите резервни услуги към Kubernetes, започнахме да страдаме от небалансирано натоварване в шушулки. Открихме, че поради HTTP Keepalive, ELB връзките се задържаха към първите готови шушулки на всяко подвижно разгръщане, така че повечето трафик преминаваше през малък процент от наличните шушулки. Едно от първите смекчаващи мерки, които опитахме, беше да използваме 100% MaxSurge при нови внедрения за най-лошите нарушители. Това беше незначително ефективно и не устойчиво в дългосрочен план с някои от по-големите внедрения.

Друго смекчаване, което използвахме, беше да надуваме изкуствено заявките за ресурси на критични услуги, така че оцветените шушулки да имат повече място наред с други тежки шушулки. Това също няма да бъде в дългосрочен план поради загуба на ресурси, а нашите приложения на Node са с една нишка и по този начин ефективно са ограничени до 1 ядро. Единственото ясно решение беше да се използва по-добро балансиране на натоварването.

Вътрешно искахме да оценим пратеника. Това ни даде шанс да го разгърнем по много ограничен начин и да извлечем незабавни ползи. Envoy е високоефективен прокси сървър на Layer 7 с отворен код, предназначен за големи сервизно ориентирани архитектури. Той е в състояние да приложи съвременни техники за балансиране на натоварването, включително автоматични повторни опити, прекъсване на веригата и ограничаване на глобалната скорост.

Конфигурацията, която измислихме, беше да имаме коляно на Envoy покрай всеки шушул, който имаше един маршрут и клъстер, за да се удари в локалния контейнер пристанище. За да сведем до минимум потенциалното каскадно и да запазим малък радиус на взрива, използвахме флота от предни прокси шушулки Envoy, по едно разполагане във всяка зона за наличност (AZ) за всяка услуга. Те удряха малък механизъм за откриване на услуги, който един от нашите инженери събра, който просто върна списък на шушулки във всяка AZ за дадена услуга.

След това сервизният фронт-Envoys използва този механизъм за откриване на услуги с един клъстер и маршрут нагоре. Конфигурирахме разумни изчаквания, засилихме всички настройки на прекъсвача и след това поставихме минимална повторна конфигурация, за да помогнем при преходни повреди и плавно разгръщане. Ние изправихме всяка от тези предни услуги на пратеника с TCP ELB. Дори ако keepalive от основния ни преден прокси слой беше прикован към определени шушулки на Envoy, те много по-добре можеха да се справят с товара и бяха конфигурирани да балансират чрез najmanj_request към бекъна.

За внедряване използвахме preStop кука както на приложението, така и на страничния сандък. Тази кука, наречена странична проверка на състоянието на здравия автомобил, не успява, заедно с малко сън, за да се даде известно време, за да се позволи на връзките с летене да се завършат и източат.

Една от причините да успеем да се движим толкова бързо се дължи на богатите показатели, които успяхме лесно да се интегрираме с нашата нормална програма за Прометей. Това ни позволи да видим какво точно се случва, докато повтаряхме настройките на конфигурацията и намаляхме трафика.

Резултатите бяха незабавни и очевидни. Започнахме с най-небалансираните услуги и към този момент го пускаме пред дванадесет от най-важните услуги в нашия клъстер. Тази година планираме да преминем към мрежа с пълна услуга, с по-усъвършенствано откриване на услуги, прекъсване на вериги, откриване на външни размери, ограничаване на скоростта и проследяване.

Фигура 3–1 Сближаване на процесора на една услуга по време на прекъсването на пратеника

Крайният резултат

Чрез тези обучения и допълнителни проучвания ние разработихме силен вътрешен инфраструктурен екип с голямо познаване на начина на проектиране, внедряване и работа с големи клъстер Kubernetes. Цялата инженерна организация на Tinder вече има знания и опит как да съхранява и разгръща приложенията си в Kubernetes.

В наследствената ни инфраструктура, когато се изискваше допълнителен мащаб, често страдахме от няколко минути в очакване новите EC2 случаи да дойдат онлайн. Сега контейнерите планират и обслужват трафика в рамките на секунди, за разлика от минути. Планирането на множество контейнери на един екземпляр EC2 също осигурява подобрена хоризонтална плътност. В резултат на това ние прогнозираме значителни икономии на разходи за EC2 през 2019 г. в сравнение с предходната година.

Това отне близо две години, но финализирахме миграцията си през март 2019 г. Платформата Tinder работи изключително на клъбер Kubernetes, състоящ се от 200 услуги, 1000 възли, 15 000 шушулки и 48 000 работещи контейнери. Инфраструктурата вече не е задача, запазена за нашите оперативни екипи. Вместо това инженерите в цялата организация споделят тази отговорност и имат контрол върху това как техните приложения са изградени и внедрени с всичко като код.

Вижте също

Как да спрете някой да ви споменава в Instagram?Приятелката се удря от човек на своя Snapchat. Тя няма да го изтрие или да му каже да се откаже от молбата ми, така че аз лично го изпращам в Instagram и му казвам да прекъсне всички контакти от нея. Сега тя е луда и ме нарича луда. Кой е прав?Стресирани ли сте заради своите ивици на SnapChat? Защо искате да ги продължите?Как мога да използвам Instagram BioLink, за да печеля пари?Защо мога да публикувам истории в Instagram?Има ли някакъв начин да забраните на гласовите съобщения да се изтеглят автоматично на WhatsApp? Ако да, какъв е процесът за това?Трябва ли да премахна бившия си като последовател от Instagram? Току-що открих, че това е възможно. Кратка история: това беше студено разпадане и не сме говорили оттогава (близо 3 години). Кой от тях би навредил повече: той да бъде актуализиран за живота ми или да бъде отрязан?Как да заглуша някой публикации в Instagram на Android?