Балансування навантаження і відмовостійкість в «Однокласниках»

Ми продовжуємо пости з розшифровками виступів на конференції HighLoad++, яка проходила в підмосковному Сколково 7-8 листопада 2016 року.

Доброго дня, мене звуть Микита Духовний, і я працюю провідним системним адміністратором в проекті «Однокласники».

На даний момент інфраструктура «Однокласників» розташовується більш ніж на 11 тисячах фізичних серверів. Вони розташовані в 3-х основних дата-центрах в Москві. Також у нас є точки присутності CDN. За останніми даними в годину пік ми віддаємо нашим користувачам понад 1 терабіта трафіку в секунду.

У відділі системного адміністрування ми розробляємо і розвиваємо системи автоматизації. Ми займаємося багатьма дослідницькими завданнями. Ми допомагаємо розробникам запускати нові проекти.

Сьогодні ми поговоримо про балансування навантаження і стійкості на прикладі нашої соціальної мережі.

На зорі проекту перед «Однокласниками» стояло завдання зробити балансування навантаження між багатьма фронтендами. Проект проживав вибухонебезпечне зростання, і тому рішення було прийнято наступним. Користувач заходив на
www.odnoklassniki.ru
, у відповідь отримував редирект на конкретне ім'я сервера, наприклад,
wg13.odnoklassniki.ru
. Це ім'я було намертво прив'язана до фізичного сервера.

Такий підхід володіє очевидними недоліками. По-перше, у разі проблем з сервером, користувач отримував помилку у браузері. По-друге, якщо ми хотіли вивести сервер ротації, ми стикалися з тим, що багато користувачів додавали ім'я цього сервера в закладки. Щось потрібно було змінювати.

Тоді ми вирішили ввести в експлуатацію балансировщики навантаження. Нам було достатньо використовувати Layer 4 балансування. Що це означає? Це означає, що балансувальник обізнаний про IP-адресу і порт. Тобто користувач, приходячи на віртуальний IP, порт 80, буде відправлений на порт 80 реального сервера, приходячи на порт 443, буде відправлений на порт 443.

Ми розглядали різні опції. На той момент вибір був між власницькими рішеннями — причому як програмними, так і програмно-апаратними — і відкритим проектом LVS (Linux Virtual Server). За результатами тестування ми не знайшли жодної причини зупинитися на пропрієтарних рішеннях.

Як ми організували схему роботи LVS
Користувальницький запит потрапляє на мережеве обладнання, воно відправляє запит на LVS. LVS, у свою чергу, відправляє запит на один з фронтенд-серверів. Причому на LVS ми використовуємо налаштування персистентності, тобто наступний користувальницький запит буде відправлено на той самий фронтенд-сервер.



Ми хотіли, щоб наш кластер LVS був резервний, тому ми організували пари master/standby. Між парами master/standby постійно відбувається синхронізація сесій. Для чого це потрібно? Щоб при вильоті master-сервера, користувач, попадя на standby-сервер, був відправлений на той самий фронтенд.

Також між серверами запущений протокол VRRP засобами відомого демона keepalive. Це потрібно для того, щоб IP-адресу самого сервера LVS переїхав на standby. Таких пар master/standby у нас багато. Між ними ми балансуємо засобами протоколу ECMP. Причому наше мережеве обладнання також інформовано про налаштуваннях персистентності, і таким чином працює вся ланцюжок. Користувальницький запит буде відправлено на одну і ту ж пару LVS, пара LVS, в свою чергу, відправить на той самий фронтенд.

Потрібно було якимось чином управляти таблицею балансування. На той момент ми вибрали популярне рішення ldirector. Демон ldirecor додає реальні сервера в таблицю балансування на підставі свого конфига. Він також здійснює перевірки реальних серверів. І в разі, якщо якийсь із реальних серверів починає повертати помилку, ldirector коригує таблицю балансування, і цей сервер виводиться з ротації.

Все виглядало добре, але кількість серверів збільшувалася. На даний момент в кожному з наших дата-центрів у нас є двісті фронтендов типу web — це ті сервери, які обробляють запити
www.odnoklassniki.ru
.

Справа в тому, що ldirector здійснює свої перевірки в однопоточному режимі. У разі неполадок, коли сервера починають відповідати довше, ніж таймаут, відбувається наступне: запит приходить на перший сервер, чекає час таймауту (наприклад, 5 секунд), і тільки після цього перевірка приступає до другого сервера. Таким чином, при масштабній проблемі, наприклад, коли уражена половина серверів, висновок цієї половини займає більше 8 хвилин. Це було неприйнятно.

Щоб вирішити цю проблему, ми написали власне рішення: ok-lvs-monitor. Воно володіє двома головними достоїнствами.

  1. Здійснює перевірки в багатопотоковому режимі. Це означає, що при описаної вище проблеми сервера будуть виведені з ротації одночасно.
  2. Інтегрується з нашою системою конфігурації порталу. Якщо раніше для зміни таблиці нам потрібно було редагувати конфіги на серверах, то тепер достатньо змінити конфігурацію в тій же самій системі, де ми управляємо налаштуваннями наших додатків.
У ході експлуатації LVS ми зіткнулися з рядом технічних проблем.

  • Ми натрапили на те, що при синхронізації сесій є досить велика розбіжність між master і standby.
  • Процес синхронізації працював тільки на першому ядрі процесора.
  • На standby-сервері він споживав понад 50% цього ядра.
  • Також були помічені різні дрібниці. Наприклад, утиліта керування таблицею балансування ipvsadm не розрізняла Active/InActive сесії у випадку з нашою конфігурацією.
Ми репортили баги розробнику проекту LVS, допомагали у тестуванні, і всі ці проблеми були усунені.

Налаштування персистентності
Раніше я згадував, що у нас використовуються налаштування персистентності. Для чого це нам?

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

LVS вміє робити персистування на підставі клієнтського IP-адреси. І ось тут-то ми зіткнулися з наступною проблемою. Популярність набирав мобільний інтернет, і багато оператори, в першу чергу, найбільший оператор Вірменії, ховали своїх користувачів всього за декількома IP-адресами. Це призводило до того, що наші mobile-web сервера стали дуже навантажені нерівномірно, і багато з них були перевантажені.

Ми вирішили забезпечувати персистування за cookie-файлу, який ставимо користувачеві. Коли мова йде про cookie-файлі, на жаль, неможливо обмежитися Layer 4 балансуванням, тому що мова йде вже про Layer 7, про рівні програми. Ми розглянули різні рішення, і на той момент найкращим був HAProxy. Популярний в наші дні nginx тоді не мав належними механізмами балансування.



Користувальницький запит, потрапляючи на мережеве обладнання, балансується все по тому ж протоколу ECMP, до цих пір нічого не змінилося. А от далі починається цікаве: без всякої персистентності, чистим Round-robin запит відправляється на будь-який з HAProxy серверів. Кожен з цих серверів в своїй конфігурації зберігає відповідності значення cookie-файлу до конкретного фронтенд-сервера. Якщо користувач прийшов перший раз, йому буде поставлений cookie-файл, якщо користувач прийшов другий і наступні рази, він буде відправлений на той самий мобільний фронтенд.

Почекайте, скажете ви, тобто «Однокласники» поставили кластер балансировщиков за кластером балансировщиков? Виглядає якось важкувато.



Насправді, давайте розберемося. Чому б і ні?

У випадку з нашою ситуацією відсоток трафіку, що проходить через HAProxy, становить менше 10% трафіку, що проходить через весь LVS. Тобто для нас це не якесь дороге рішення. А ось перевага такого підходу очевидна.

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

Аварії в дата-центрі
«Однокласники» за свою історію неодноразово стикалися з аваріями. У нас була історія, коли згоріли і основна, резервна оптика до дата-центру. Дата-центр став недоступний. У нас була історія, коли з-за неправильної проектування стала плавитися електрична проводка в дата-центрі, що призвело до пожежі. У нас була дуже захоплююча історія, коли ураган в Москві відірвав шматок даху, а він вивів з ладу систему охолодження в дата-центрі. Нам треба було приймати рішення, які сервера вимикати, а які залишати, тому що почався перегрів.

За результатами цих аварій ми сформулювали для себе правило: «Однокласники» повинні працювати в разі відмови будь-якого з дата-центрів.

Яким чином ми йшли до цієї мети?

  • Ми підготували наші системи зберігання даних. Ми імплементували функціонал, який дозволяє нашими систем даних розуміти в якому дата-центрі вони знаходяться.
  • Ми використовуємо replication factor=3. Разом ці два пункти призводять до того, що в кожному з дата-центрів з'являється своя репліка даних.
  • В наших системах ми використовуємо quorum=2. Це означає, що при вильоті одного з дата-центрів система буде продовжувати свою роботу.
Нам потрібно було розподілити наші фронтенд-сервера за трьома дата-центрам. Ми це зробили, причому з урахуванням запасу по потужності, щоб фронтенды в дата-центрі могли взяти на себе всі запити, які раніше припадали на той дата-центр, який зараз відмовив.



Якщо ви зробите DNS-запит на
www.ok.ru
, то ви побачите, що вам віддається 3 IP-адреси. Кожен з цих адрес якраз і відповідає одному дата-центру.

Ми обробляємо ситуацію з аварією в дата-центрі автоматично. Тут ви можете бачити приклад такої перевірки:



Видно, що у разі якщо 10 з 20 останніх перевірок були неуспішні, IP-адресу дата-центру перестане віддаватися. 10 — це досить багато, висновок дата-центру — це важка операція. Ми хочемо бути впевненими, що правда почалася аварія. Тут можна побачити, що автоматично дата-центр буде заведений у ротацію у разі 20 з 20 успішних перевірок. Так, висновок — це операція важка, але ми хочемо бути впевненим, що все в порядку, перед тим як заводити користувачів.

За нашими підрахунками, при такій методиці за 5 хвилин з дата-центру піде 80 % аудиторії. Є припущення, звідки взялася цифра 5 хвилин?



Мережа. На рівні мережі ми використовуємо досить цікавий трюк. Насправді прикордонні раутеры кожного з дата-центрів анонсують всі мережі в світ.

Уявімо, що користувач йде на IP-адресу
217.20.156.159
. Користувач потрапить в один з дата-центрів. Інший користувач, звертаючись до того ж IP-адресою, насправді може потрапити в сусідній дата-центр. Для чого це потрібно? У разі відмови одного з прикордонних раутеров користувачі не помітять ніякого ефекту.

Тут є тонкий момент. Я вам тільки що розповідав про те, що у нас в кожному дата-центрі буде свій IP-адресу для сервісу і начебто даю вам суперечить інформацію. Насправді немає. На рівні ядра мережі в кожному дата-центрі все-таки свій набір мереж, і просто прикордонні раутеры, використовуючи або пряме з'єднання, або своє кільце, мають можливість відправити запит в потрібний дата-центр.



З приводу ядра мережі. Всі мережеве обладнання у нас зарезервовано з таким запасом потужності, щоб бути здатним взяти на себе навантаження вилетів сусіда. Тільки аварія з усім ядром мережі правда призведе до ситуації, коли нам доведеться виводити трафік з дата-центрів.

Важкий контент
Під важким контентом я маю на увазі музику, відео і фотографії.

Справа в тому, що значна частина аудиторії «Однокласників» не може похвалитися такою ж якістю Інтернет-з'єднання, як жителі столиці. По-перше, велика частина нашої аудиторії проживає за межами Російської Федерації. У багатьох країнах швидкість зарубіжного інтернету і внутрішнього дуже сильно розрізняється. По-друге, користувачі у віддалених регіонах в принципі часто не можуть похвалитися стабільним каналом. Навіть якщо він стабільний, це зовсім не означає, що він не повільний.

Ми хотіли зробити так, щоб користувачам було комфортно працювати з «Однокласниками». Тому ми задумалися про власний вирішенні CDN.

Ідея CDN досить проста. Ви берете їх сервера і ставите їх близько до користувача. При побудові CDN зазвичай використовується один з двох класичних підходів.

IP Anycast. Його суть полягає в тому, що кожна з ваших майданчиків анонсує в світ одну і ту ж мережу, одні і ті ж адреси. І те, на яку майданчик потрапить ваш користувач, визначає поточна топологія Інтернету. Плюси такого підходу очевидні: вам не потрібно імплементувати жодну логіку для того, щоб користувач потрапив на оптимальну майданчик.



Мінуси також добре видно. Уявімо, що у вас є CDN у Воронежі, ви хочете провести з ним серйозні сервісні роботи. Для цього вам потрібно відправити всіх користувачів на якусь конкретну майданчик, наприклад, в Санкт-Петербург. Використовуючи IP Anycast у чистому вигляді, у вас немає прямих механізмів, як ви можете це зробити. Крім того, ви повинні будете готувати ваш додаток до такого повороту подій, як несподіваний перехід користувача. У топології Інтернету щось змінилося, і користувач наступний запит надсилає на інший майданчик.

Інша класична технологія заснована на використанні геолокаціі і DNS. В чому суть?



Москвич, роблячи запит за статичним контентом, за ім'ям сервісу, який віддає статичний контент до DNS, отримає у відповідь московський IP-адресу і буде відправлений на майданчик в Москві. Житель Новосибірська, роблячи аналогічний запит, отримає IP-адреса майданчика в Новосибірську і буде відправлений туди.

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

У «Однокласників» була ще одна задача: ми хотіли запускати проекти виду «трафік до «Однокласників» безкоштовно». Тобто, вибираючи, наприклад, мобільне підключення нашого партнера, все те, що ви робите через мобільний додаток Однокласників, не враховується як витрата трафіку. Щоб здійснити таку задачу, наш CDN повинен був мати функціонал, що дозволяє відправляти тільки ті мережі на майданчик, які хоче бачити там наш партнер.

Класичні рішення для такого завдання не підходять. Що ми зробили?



На майданчику CDN наш сервер за BGP встановлює з'єднання з Route Server провайдера, отримуючи від нього список тих мереж, які провайдер хоче на ньому бачити. Далі список префіксів передається на наш GSLB DNS, і тоді вже користувач, звертаючись DNS-запит, отримує IP-адреса якраз в тій площадці, що потрібно. Майданчик, у свою чергу зрозуміло весь контент забирає з основних дата-центрів.



Всередині майданчика між серверами ми балансуємо, використовуючи досить тривіальний підхід. У кожного з них є свій IP-адресу, DNS-запиту віддаються обидва IP-адреси. Таким чином, користувачі будуть розподілені між серверами приблизно порівну. У разі відмови одного з серверів засобами все того ж протоколу VRRP IP-адреса буде прозоро переведений на іншу ноду. Користувачі нічого не помітять.



Зрозуміло, ми здійснюємо перевірки всіх наших майданчиків. У випадку, якщо майданчик перестає повертати статус ОК, ми перестаємо віддавати її IP-адреса. В такому випадку користувач з Новосибірська піде в дата-центри в Москві. Це буде трохи повільніше, але це буде працювати.

На наших CDN-майданчиках ми використовуємо внутрішньо розроблені програми для відео, музики і фото, а також у додатку до цього nginx. Хотів би згадати основний момент оптимізації, який застосовується в наших програмах. Уявімо, що у вас є кілька серверів, які віддають важкий контент. Користувач приходить на один сервер і запитує у нього цей контент. Контента там не знаходиться. Тоді сервер забирає цей контент з майданчика в Москві. Але що буде, коли наступний користувач прийде за тим же самим контентом на другий сервер? Ми не хотіли б, щоб сервер йшов знову за тим же самим контентом в Москву. Тому в першу чергу він сходить на свій сусідній сервер і забере контент з нього.

Майбутнє
Хотів би розповісти про декількох проектах, якими нам було б дуже цікаво зайнятися і що нам було б дуже цікаво реалізувати.

Ми хотіли б бачити, щоб кожен з наших сервісів, наприклад,
www.odnoklassniki.ru
, все-таки жив за однією IP-адресою. Для чого?

  • У разі відмови дата-центру в такому разі для користувачів все відбувалося прозоро.
  • Ви позбулися б проблеми з некоректно себе провідними кэширующими DNS, які продовжують віддавати IP-адреса виведеної майданчики, незважаючи на те, що ми його вже не віддаємо.
  • Раз в TTL часу (тобто в нашому випадку раз в 5 хвилин) користувач все-таки може перейти на інший майданчик.
Це не дуже технічно складна операція, але тим не менш від неї хотілося б позбутися. Це дуже амбітний проект, в його рамках треба вирішувати багато завдань. Як забезпечувати налаштування персистентності? Як непомітно проводити сервісні роботи? Як виводити дата-центр? Зрештою, як підготувати наше додаток до такого повороту подій? Всі ці питання треба вирішити.

Інша цікава тема. Це балансировщики Layer 4, які працюють в user space. У чому полягає їх суть?

Насправді, коли балансувальник використовує мережевий стек Linux, він постійно перемикається між user space і kernel space. Це досить дорога операція для CPU. Крім того, network stack Linux — це універсальне рішення. Як будь-універсальне рішення, воно не ідеально підходить для даної конкретної задачі. Балансировщики user space Layer 4 самостійно реалізують той необхідний функціонал network stack, який їм потрібен. За рахунок цього, за чутками, все працює дуже швидко.

Відкрию вам невеличкий секрет: насправді зараз один з партнерів проводить для нас дослідження і деякі доопрацювання, і ми могли переконатися самостійно у величезній різниці в швидкості.

Це тільки два проекти з можливого майбутнього, які я зараз назвав. Насправді їх набагато більше. І зрозуміло більша їх частина пов'язана з іншими темами, не тільки з балансировской навантаження і відмовостійкості.



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

Спасибі за увагу!


Останні дев'ять хвилин виступу Микита Духовний відповідав на запитання з залу.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.