Как Netflix мащабира своята система за топология на услугите в реално време

Изображение: Svetni.me / ИИ генерирано изображение
В съвременните разпределени облачни среди разбирането на сложните връзки между хиляди микроуслуги е критично предизвикателство за инженерите. Инженерите в Netflix наскоро споделиха детайли за това как са препроектирали архитектурата зад Service Topology – тяхната платформа за изграждане на обединена карта на зависимостите на услугите в реално време [1]. Системата комбинира три отделни слоя данни: мрежови потоци от eBPF, метрики за междупроцесно сътрудничество (IPC) и разпределено проследяване (distributed tracing) [1]. Тя осигурява на инженерите видимост за бързо отстраняване на смущения, анализ на обхвата на въздействие (blast radius), разбиране на зависимостите и управление на промените в продукционна среда [1].
Традиционните системи за топология разчитат на партидна обработка (batch processing), която генерира ежедневни или часови моментни снимки. По време на среднощен инцидент в продукция обаче, топологична карта на един час е еквивалентна на археология, а не на текуща наблюдаемост [1]. Затова ключовото решение на Netflix е изграждането на архитектура, базирана изцяло на стрийминг в реално време, която осигурява обновяване на данните в рамките на минути и поддържа постоянни актуализации при огромен мащаб, без да изпада в закъснения [1].

Изображение: Svetni.me / ИИ генерирана инфографика
Триетапният тръбопровод за обработка на мрежовия поток
Суровите мрежови потоци отчитат само транзитните мрежови скокове (network hops), а не логическата зависимост между приложенията [1]. Тъй като трафикът преминава през балансиращи устройства (load balancers), NAT шлюзове или API проксита, връзките App A -> Load Balancer и Load Balancer -> App B се виждат като отделни потоци. За да се разрешат тези посредници и да се покажат чистите логически връзки App A -> App B, Netflix внедрява триетапен разпределен тръбопровод:
- Етап 1: Първоначална агрегация (FlowLog Ingestion Service): Тази услуга консумира суровите мрежови потоци от многорегионални Apache Kafka теми, филтрира невалидните записи и ги групира в 5-минутни времеви прозорци, като създава първоначални обекти-агрегатори [1].
- Етап 2: Разрешаване на мрежови посредници (Intermediate GraphEntity Ingestion Service): На този етап се извършва същинското логическо разрешаване (intermediary resolution) [1]. За да се извърши обединяването на потоците, те трябва да се намерят на една и съща физическа инстанция (data locality). Етап 2 преразпределя агрегаторите чрез консистентно хеширане по идентификатора на проксито/балансиращото устройство, извършвайки класически map-reduce процес на събиране и разрешаване [1].
- Етап 3: Финално агрегиране и обогатяване (GraphEntity Ingestion Service): Този етап приема разрешените логически ребра от Етап 2, обогатява възлите в графа с информация за здравето на приложенията, собствеността и други метаданни, след което записва крайния резултат в разпределената графова база данни с контролирано ограничаване на скоростта на писане [1].
Справяне с горещи точки и разпределяне на товара
Първоначалната версия на системата е използвала двуетапен дизайн, при който Етап 2 е извършвал както разрешаването на посредниците, така и обогатяването и записа [1]. В реална среда обаче популярни услуги (като оторизационния слой или препоръчващия алгоритъм) се викат от стотици други системи, генерирайки огромна концентрация на данни [1]. Инстанциите, отговарящи за тези популярни дестинации, са се превръщали в горещи точки (hot nodes) със 100-кратно по-висок трафик и тежки I/O операции по обогатяване, което е водило до критични смущения в паметта и сривове [1].
Разделянето на процеса на три етапа позволява пълно изолиране на изчислително тежкото разрешаване на посредници от I/O интензивното обогатяване [1]. Чрез двукратното преразпределяне и компресиране на агрегаторите на по-ранните нива, натоварването се разпределя равномерно в целия клъстер, предпазвайки отделните инстанции от претоварване [1].
Реактивно обратно налягане (Backpressure)
Обработката на милиони събития в секунда изисква механизъм за контролирано забавяне, когато системите за съхранение не могат да поддържат темпото на запис. Netflix внедрява Apache Pekko Streams за управление на обратното налягане (backpressure) [1]. Когато графовата база данни се забави, сигналът за натоварване се предава автоматично нагоре по веригата: Етап 3 забавя Етап 2, който забавя Етап 1, а той временно спира четенето от Kafka [1]. Вместо срив на паметта или загуба на събития, системата реагира с краткотрайно забавяне в обновяването на топологичната карта [1]. Това гарантира пълнотата и верността на топологията дори по време на сериозни натоварвания [1].
Оптимизация на мрежата и паметта
За да намали разходите за сериализация, управление на връзките и паметта при огромен трафик, Netflix заменя gRPC протокола за комуникация между етапите на обработка със Server-Sent Events (SSE) [1]. SSE предлага лек, HTTP-базиран модел с минимални разходи за сериализация, който се интегрира естествено с реактивните потоци [1]. gRPC се запазва единствено като външен API слой за клиентите на Service Topology [1].
Освен тогава, екипът прави радикални промени в управлението на паметта в JVM [1]. Тъй като първоначално са използвани традиционните за Scala неизменяеми (immutable) структури от данни, постоянното заделяне и освобождаване на милиони обекти на секунда е претоварвало Garbage Collector-а, водейки до дълги паузи [1]. Промяната към мутиращи, предварително заделени структури в паметта (object pooling) и елиминирането на излишните конвертирания на обекти преди Етап 3 драстично намаляват използването на паметта и подобряват латентността [1].
Възстановяване на исторически състояния (Time-Travel)
За да помогне на инженерите при анализ на минали инциденти (напр. „Как изглеждаше графовата топология по време на срива в 3:00 часа?“), Netflix разработва функция за пътуване във времето [1]. Вместо скъпото съхранение на пълни моментни снимки на целия граф, системата комбинира три механизма:
- Времево-прозоречни моментни снимки на агрегаторите на всеки 5 минути, съхранявани с времеви марки [1].
- Проследяване на мутациите на ниво свойства на обектите, което записва единствено промените в стойностите [1].
- Динамична реконструкция при заявка чрез хронологично прилагане на мутациите върху базовите състояния [1].
Този подход спестява значително дисково пространство, осигурява бързо извличане на данните и позволява гъвкаво преагрегиране на исторически данни по произволни измерения по време на самата заявка [1].
Динамично консистентно хеширане
За определяне на собствеността на агрегаторите при автоматично мащабиране на клъстера, инстанциите на Netflix използват консистентно хеширане, обвързано с техния служебен регистър [1]. Всяка инстанция в Auto Scaling Group самостоятелно извлича актуалния списък на здравите машини от регистъра, подрежда го сортиран и изчислява собствениците на агрегаторите чрез хеш функция [1]. Това елиминира необходимостта от сложни разпределени координатори или ръчни процеси на пребалансиране, тъй като натоварването се разпределя автоматично и безпроблемно при добавяне или премахване на възли [1].
Заключение
Опитът на Netflix показва, че при изключителен мащаб стандартните добри практики – като сляпото използване на неизменяеми обекти, gRPC за всички услуги или двуетапни конвейери – могат да доведат до сериозни производствени проблеми [1]. Ключът към стабилността се крие в итеративното профилиране на производителността, разделянето на отговорностите на етапи за равномерно разпределение на товара и готовността за адаптиране на дизайна към реалните данни [1].
Източници: