Переїзд Тіндера в Кубернетес

Автор: Кріс О'Брайен, керівник інженерії | Кріс Томас, керівник інженерії | Джиньонг Лі, старший інженер програмного забезпечення | Редагував: Купер Джексон, інженер програмного забезпечення

Чому?

Майже два роки тому Tinder вирішив перенести свою платформу в Kubernetes. Kubernetes дала нам можливість підвести Tinder Engineering до контейнерної роботи та роботи з низьким дотиком через незмінне розгортання. Побудова, розгортання та інфраструктура додатків визначатимуться як код.

Ми також хотіли вирішити проблеми масштабу та стабільності. Коли масштабування стало критичним, ми часто страждали через кілька хвилин очікування появи нових екземплярів EC2 в Інтернеті. Ідея планування контейнерів та обслуговування трафіку протягом декількох секунд на відміну від хвилин була нам привабливою.

Це було непросто. Під час міграції на початку 2019 року ми досягли критичної маси у нашому кластері Kubernetes і почали стикатися з різними проблемами через обсяг трафіку, розмір кластера та DNS. Ми вирішили цікаві завдання з міграції 200 служб та запуску кластеру Kubernetes в масштабі загальної кількості 1000 вузлів, 15 000 стручків і 48 000 контейнерів, що працюють.

Як

Починаючи з січня 2018 року, ми пройшли свій шлях через різні етапи міграційних зусиль. Ми розпочали з контейнерного обслуговування всіх наших служб та розміщення їх у серії Kubernetes, де розміщувались інсценування. Починаючи з жовтня, ми почали методично переносити всі наші застарілі послуги до Kubernetes. До березня наступного року ми завершили нашу міграцію, і платформа Tinder тепер працює виключно на Кубернетах.

Створення зображень для Кубернетів

Існує понад 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 була зміна існуючої комунікації між послугами на обслуговування, щоб вказати на нові еластичні балансири навантаження (ELB), які були створені в конкретній підмережі Virtual Private Cloud (VPC). Ця підмережа була підглянута до VPC Kubernetes. Це дозволило детально мігрувати модулі, не зважаючи на конкретні замовлення залежностей від сервісу.

Ці кінцеві точки були створені за допомогою зважених наборів записів DNS, у яких CNAME вказував на кожний новий ELB. Для скорочення ми додали новий рекорд, вказуючи на нову службу Kubernetes ELB, вагою 0. Потім ми встановили час для життя (TTL) на записі, встановленому на 0. Старі та нові ваги потім повільно налаштовували на врешті-решт, на новому сервері надійде 100%. Після завершення перерізу TTL було встановлено на щось більш розумне.

Наші модулі Java отримали низький вміст DNS TTL, але наші програми Node цього не зробили. Один з наших інженерів переписав частину коду пулу підключень, щоб загорнути його в менеджер, який би оновлював пули кожні 60-ті. Це було дуже добре для нас, не маючи помітного хіта на продуктивність.

Навчання

Обмеження мережевої тканини

У ранні ранкові години 8 січня 2019 року платформа Tinder зазнала постійного відключення. У відповідь на незв'язане збільшення затримки платформи раніше цього ранку, кількість класів і вузлів було змінено на кластері. Це призвело до вичерпання кеш-пам'яті ARP на всіх наших вузлах.

Для кешу ARP є три значення Linux:

Кредит

gc_thresh3 - жорстка кришка. Якщо ви отримуєте записи журналу "переповнення сусідньої таблиці", це вказує на те, що навіть після синхронного збору сміття (GC) кешу ARP не було достатньо місця для зберігання запису сусіда. У цьому випадку ядро ​​просто повністю скидає пакет.

Ми використовуємо Flannel як мережеву тканину в Kubernetes. Пакети передаються через VXLAN. VXLAN - схема накладення рівня 2 в мережі 3 рівня. Він використовує інкапсуляцію MAC-в-UDP протоколу MAC-адреси в користувачеві для забезпечення способу розширення мережевих сегментів рівня 2. Транспортний протокол через мережу фізичного центру обробки даних - це IP плюс UDP.

Рисунок 2–1 Фланельна діаграма (кредит)

Малюнок 2–2 VXLAN-пакет (кредит)

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

Крім того, зв'язок між вузлом-поділом (або поділ-до-під) в кінцевому рахунку протікає через інтерфейс eth0 (зображений на діаграмі Фланеля вище). Це призведе до додаткового запису в таблиці 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 ядер.

Під час дослідження інших можливих причин та рішень ми знайшли статтю, що описує стан гонки, що впливає на netfilter рамки фільтрації пакетів Linux. Час очікування DNS, який ми бачили, разом із збільшенням лічильника insert_failed на інтерфейсі Flannel, узгодженого з висновками статті.

Проблема виникає під час трансляції мережевих адрес джерел та цільових адрес (SNAT та DNAT) та подальшого вставки в таблицю континтрації. Одне вирішення, яке обговорювалося всередині країни та пропонувалося громадою, було переміщення DNS на робочий вузол. В цьому випадку:

  • SNAT не потрібен, оскільки трафік знаходиться локально на вузлі. Його не потрібно передавати через інтерфейс eth0.
  • DNAT не є необхідним, оскільки IP-адреса призначення локальна для вузла, а не випадково вибраного стручка за правилами iptables.

Ми вирішили рухатися вперед з таким підходом. CoreDNS було розгорнуто як DaemonSet у Kubernetes, і ми ввели локальний DNS-сервер вузла у кожен pod-resv.conf, конфігуруючи прапорець kubelet - cluster-dns. Вирішення було ефективним для тайм-аутів DNS.

Однак ми все ще бачимо скинуті пакети та приріст лічильника інтерфейсу insert_failed для збільшення лічильника. Це збережеться навіть після вищезазначеного рішення, оскільки ми уникали лише SNAT та / або DNAT для трафіку DNS. Стан гонки все ще буде мати місце для інших типів руху. На щастя, більшість наших пакетів є TCP, і коли виникає умова, пакети будуть успішно передані. Довгострокове виправлення всіх видів трафіку - це те, що ми все ще обговорюємо.

Використання посланця для досягнення кращого балансування навантаження

Коли ми перенесли наші сервісні служби на Kubernetes, ми почали страждати від незбалансованого навантаження на стручки. Ми виявили, що завдяки HTTP Keepalive з'єднання ELB застрягли на перших готових стручках кожного розгортання, тому більша частина трафіку протікала через невеликий відсоток наявних стручків. Одним з перших пом'якшень, які ми намагалися, було використання 100% MaxSurge для нових розгортань для найгірших злочинців. Це було незначно ефективним і не стійким довгостроковим періодом при деяких великих розгортаннях.

Ще одне пом’якшення, яке ми використовували, було штучним завищенням запитів на ресурси для критичних служб, щоб кольорові стручки мали більше місця для запасів поряд з іншими важкими стручками. Це також не буде прийнятним у довгостроковій перспективі через відходи ресурсів, і наші додатки у вузлі були однопоточні і, таким чином, ефективно обмежувались на 1 ядрі. Єдиним чітким рішенням було використання кращого балансування навантаження.

Ми внутрішньо шукали, щоб оцінити Посланника. Це дало нам шанс розгорнути його дуже обмеженим чином і отримати негайну вигоду. Envoy - це високоефективний проксі-сервер Layer 7 з відкритим кодом, розроблений для великих архітектур, орієнтованих на сервіс. Він здатний реалізувати передові методи балансування навантаження, включаючи автоматичні спроби, розрив ланцюга та обмеження глобальної швидкості.

Конфігурація, яку ми придумали, полягала в тому, щоб поруч з кожним стручком, який мав один маршрут і кластер, щоб потрапити на місцевий контейнерний порт, було коляска посланця. Щоб мінімізувати потенційний каскад і утримати невеликий радіус вибуху, ми використовували флот фронтових проксі-сервісів-підлітків, по одному розгортанню у кожній зоні доступності (AZ) для кожної послуги. Вони потрапили в невеликий механізм виявлення сервісу, який склав один з наших інженерів, який просто повернув список стручків у кожному AZ за певну послугу.

Тоді службовий фронт-Посланці використовував цей механізм виявлення служби одним кластером і маршрутом вище. Ми налаштували розумні тайм-аути, підсилили всі настройки автоматичного вимикача, а потім ввели мінімальну конфігурацію для повторної спроби, щоб допомогти з тимчасовими відмовами та плавними розгортаннями. Кожну з цих служб переднього посланника ми зіткнулися з TCP ELB. Навіть якщо киепалів з нашого основного переднього проксі-шару був зафіксований на певних стручках Envoy, вони набагато краще змогли впоратися з навантаженням і були налаштовані на балансування через мінімальний_запит до бекенда.

Для розгортання ми використовували гачок 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 для заробітку?Чому я можу публікувати публікації \ u201cs Instagram?Чи є якийсь спосіб вимкнути автоматичне завантаження голосових повідомлень на WhatsApp? Якщо так, то який процес це зробити?Чи слід видалити свого колишнього як підписника з Instagram? Я щойно виявив, що це можливо. Довга коротка історія: це був холодний розрив, і ми не говорили з тих пір (майже 3 роки). Хто б більше зачепив: його оновлюють у моєму житті чи відрізають?Як відключити чиїсь публікації Instagram на Android?