У процесі переходу від монолітної програми до мікросервісної архітектури ми стикаємося з новими проблемами.
У монолітному додатку зазвичай досить легко визначити, який частині системи сталася помилка. Швидше за все, проблема у коді самого моноліту, або у базі даних. Але коли ми починаємо шукати проблему в мікросервісній архітектурі, то все вже не так очевидно. Потрібно знайти весь шлях, який пройшов запит від початку до кінця, виділити його із сотень мікросервісів. Причому багато хто з них ще й має власні сховища, в яких також можуть виникати як логічні помилки, так і проблеми з продуктивністю та стійкістю до відмови.
Я довго шукав інструмент, який би допоміг упоратися з такими проблемами (писав про це на Хабрі:
Розподілений tracing є поширеним вирішенням проблеми пошуку помилок у розподілених системах. Але що якщо в системі ще не впроваджено такий підхід до збору інформації про мережеві взаємодії, або, що гірше, в частині системи він уже справно працює, а в частині його немає, оскільки він не доданий до старих послуг? Для визначення точної кореневої причини проблеми необхідно мати повну картину того, що відбувається у системі. Особливо важливо розуміти, які саме мікросервіси беруть участь у основних критичних для бізнесу шляхах.
Тут до нас на допомогу може прийти service mesh підхід, який займеться всією машинерією зі збору мережної інформації на рівні нижче, ніж працюють самі послуги. Цей підхід дозволяє нам перехоплювати весь трафік та аналізувати його на льоту. Причому, додатки про нього навіть не повинні нічого знати.
Service mesh підхід
Головною ідеєю service mesh підходу є додавання ще одного інфраструктурного шару над мережею, який дозволить нам робити будь-які речі із міжсервісною взаємодією. Більшість реалізацій працюють наступним чином: до кожного мікросервісу додається додатковий sidecar контейнер із прозорим проксі, через який пропускається весь вхідний та вихідний трафік сервісу. І це те місце, де ми можемо робити клієнтське балансування, застосовувати політики безпеки, вводити обмеження на кількість запитів і збирати важливу інформацію щодо взаємодії сервісів у production.
Розв'язки
Вже є кілька реалізацій цього підходу:
У результаті ми подивилися на те, які саме можливості нам потрібні прямо зараз, і вирішили, що основне, через що ми почали впроваджувати подібні рішення, була можливість збирати tracing інформацію з усієї системи прозоро. Також нам хотілося мати контроль над взаємодією сервісів та робити різні маніпуляції із заголовками, що передаються між сервісами.
У результаті ми дійшли свого рішення:
Netramesh
Головними цілями нового рішення були невеликий overhead за ресурсами та висока продуктивність. З основних можливостей ми хотіли мати можливість прозоро відправляти tracing span'и в нашу Jaeger систему.
Сьогодні більшість хмарних рішень реалізується на Golang. І, звісно, на це є свої причини. Писати на Golang мережеві додатки, що працюють асинхронно з введенням-виводом і що масштабуються за потребою на ядра, зручно і досить просто. І, що також дуже важливо, продуктивність виходить достатньою для вирішення цього завдання. Тому ми також обрали Golang.
Продуктивність
Ми сфокусували наші зусилля на досягненні максимальної продуктивності. Для рішення, яке деплоїться поряд з кожним екземпляром сервісу, потрібне невелике споживання оперативної пам'яті та процесорного часу. І, звичайно, затримка на відповідь має бути також малою.
Давайте подивимося, які результати вийшли.
Оперативна пам'ять
Netramesh споживає ~10Mb без трафіку та 50Mb максимально з навантаженням до 10000 RPS на одну instance.
Istio envoy proxy завжди споживає ~300Mb у наших кластерах з тисячами instance'ів. Це не дозволяє масштабувати його на весь кластер.
З Netramesh ми отримали зменшення споживання пам'яті в ~10 разів.
центральний процесор
Використання CPU відносно рівне під навантаженням. Воно залежить від кількості запитів в одиницю часу до sidecar. Значення при 3000 запитах на секунду в піку:
Є ще один важливий момент: Netramesh – рішення без control plane та без навантаження не споживає процесорний час. З Istio sidecar'и завжди оновлюють endpoint'и сервісів. У результаті ми можемо бачити таку картину без навантаження:
Ми використовуємо HTTP/1 для взаємодії між сервісами. Збільшення часу відповіді у Istio під час проксування через envoy було до 5-10ms, що досить багато для сервісів, які готові відповідати за мілісекунду. З Netramesh цей час зменшився до 0.5-2ms.
масштабованість
Невелика кількість ресурсів, що витрачається кожним проксі, дає можливість розміщувати його поряд із кожним сервісом. Netramesh навмисно був створений без control plane компонента для простої підтримки легковажності кожного sidecar'а. Часто в сервісних mesh рішеннях управління планом розповсюджує сервісну інформацію на кожну сторонуавтомобіля. Разом з нею приїжджає і інформація про timeout'ах, налаштування балансування. Все це дозволяє робити багато корисних речей, але, на жаль, роздмухує sidecar'и в розмірі.
Відкриття служби
Netramesh не додає будь-яких додаткових механізмів для служби discovery. Весь трафік проксірується прозоро через netra sidecar.
Netramesh підтримує HTTP/1 прикладний протокол. Для його визначення використовується конфігурований список портів. Зазвичай у системі є кілька портів, якими відбувається взаємодія по HTTP. Наприклад, у нас для взаємодії сервісів та зовнішніх запитів використовуються 80, 8890, 8080. У такому разі їх можна задати за допомогою змінного оточення NETRA_HTTP_PORTS
.
Якщо ви використовуєте Kubernetes як оркестратора та його механізм Service сутностей для внутрішньокластерної взаємодії між сервісами, то механізм залишається таким самим. Спочатку мікросервіс отримує service IP-адресу за допомогою kube-dns і відкриває нове з'єднання до нього. Це з'єднання встановлюється спочатку з локальним netra-sidecar і всі TCP пакети спочатку прилітають саме до netra. Далі вже netra-sidecar встановлює з'єднання з початковою точкою призначення. NAT на pod IP на ноді залишається так само як і без netra.
Розподілений tracing та прокидання контексту
Netramesh надає функціональність, необхідну для відправки tracing span'ів про HTTP взаємодію. Netra-sidecar парять HTTP протокол, вимірюють затримки запитів, дістають необхідну інформацію з HTTP header'ів. Нарешті ми отримуємо всі trace'и у єдиній Jaeger системі. Для тонкої конфігурації також можна використовувати змінні оточення, які надає офіційна бібліотека
Але є проблема. Поки сервіси не генеруватимуть і прокидатимуть спеціальний uber заголовок, ми не побачимо з'єднані tracing span'и в системі. А це те, що нам потрібне для швидкого пошуку причини проблем. Тут Netramesh знову має рішення. Проксі читають заголовки HTTP і, якщо в них немає uber trace id, генерують його. Netramesh також зберігає інформацію про вхідні та вихідні запити в sidecar і зіставляє їх шляхом збагачення необхідними заголовками вихідних запитів. Все, що потрібно робити в сервісах - прокидати лише один заголовок X-Request-Id
, який можна налаштувати за допомогою змінного оточення NETRA_HTTP_REQUEST_ID_HEADER_NAME
. Для керування розміром context'а в Netramesh можна задавати наступні змінні оточення: NETRA_TRACING_CONTEXT_EXPIRATION_MILLISECONDS
(час, протягом якого зберігатиметься контекст) та NETRA_TRACING_CONTEXT_CLEANUP_INTERVAL
(Періодичність підчищення контексту).
Також можна комбінувати декілька шляхів у вашій системі шляхом маркування їх спеціальним сесійним маркером. Netra дозволяє встановити HTTP_HEADER_TAG_MAP
для перетворення HTTP заголовків у відповідні tracing span теги. Це може бути особливо корисним для тестування. Після проходження функціонального тесту можна подивитися яка частина системи була порушена, відфільтрувавши за відповідним session ключем.
Визначення джерела запиту
Для визначення того, звідки надійшов запит, можна скористатися функціоналом автоматичного додавання заголовка із джерелом. За допомогою змінної оточення NETRA_HTTP_X_SOURCE_HEADER_NAME
можна встановити ім'я заголовка, яке буде автоматично встановлюватися. За допомогою NETRA_HTTP_X_SOURCE_VALUE
можна встановити значення, в яке буде встановлюватися X-Source заголовок на всі вихідні запити.
Це дозволяє уніфіковано по всій мережі розповсюдження цього корисного заголовка. Далі можна використовувати його в сервісах і додавати в логи, метрики.
Роутінг трафіку та нутрощі Netramesh
Netramesh складається з двох основних компонентів. Перший netra-init встановлює мережеві правила для перехоплення трафіку. Він використовує INBOUND_INTERCEPT_PORTS, OUTBOUND_INTERCEPT_PORTS
.
Також в інструменті є цікава можливість - імовірнісний роутинг. Якщо використовувати Netramesh виключно для збору tracing span'ів, то в production оточенні можна заощадити ресурси та включити ймовірнісний роутинг за допомогою змінних NETRA_INBOUND_PROBABILITY
и NETRA_OUTBOUND_PROBABILITY
(Від 0 до 1). Значення за промовчанням дорівнює 1 (перехоплюється весь трафік).
Після успішного перехоплення netra sidecar приймає нове з'єднання та використовує SO_ORIGINAL_DST
опцію сокету отримання початкової точки призначення. Потім Netra відкриває нове з'єднання до початкової IP-адреси і встановлює двостороннє TCP-спілкування між сторонами, слухаючи весь трафік. Якщо порт визначено як HTTP, Netra намагається парсить його і трейсить. Якщо парсинг HTTP виявляється неуспішним, Netra робить фоллбек на TCP і прозоро проксіює байти.
Побудова графа залежностей
Після отримання великої кількості tracing інформації у Jaeger, хочеться отримати повний графік взаємодій у системі. Але якщо ваша система досить навантажена і за день накопичуються мільярди tracing span'ів, зробити їхню агрегацію стає не таким простим завданням. Є офіційний спосіб для цього:
Якщо ви використовуєте Elasticsearch для зберігання tracing span'ів, можна скористатися
Як використовувати Netramesh
Netra можна просто додати до будь-якого сервісу, який працює під управлінням будь-якого оркестратора. Можна подивитися приклад
На даний момент у Netra немає можливості автоматичного впровадження sidecar'а до сервісів, але є плани на реалізацію.
Майбутнє Netramesh
Головною метою
У майбутньому Netramesh отримає підтримку інших протоколів прикладного рівня, крім HTTP. Найближчим часом з'явиться можливість L7 роутингу.
Використовуйте Netramesh, якщо ви стикаєтеся з подібними проблемами, та пишіть нам питання та пропозиції.
Джерело: habr.com