Темы



Наблюдаемость на основе онтологии: создание сквозного графа знаний в масштабе Netflix

Коротко сгенерировано ИИ по тексту статьи
  • В обычный день Netflix обрабатывает более 2 млрд запросов и свыше 38 млн событий журналирования в секунду; бой Пола и Тайсона одновременно смотрели около 65 млн зрителей.
  • Observability Ontology объединяет данные об приложениях, инцидентах и развёртываниях в граф знаний на основе RDF, OWL, SHACL и SPARQL.
  • В примере один запрос к графу заменяет поиск в incident.io, Spinnaker и Radar; обсуждения инцидентов в Slack преобразуются в структурированные триплеты.

Почему это важно: При таком масштабе быстро понимать и обновлять системы важно для обеспечения хорошего взаимодействия с пользователями.

[не удалось получить полный текст]

Прасанна Виджаянатан, Ренцо Санчес-Силва

Когда в ноябре 2024 года Джейк Пол и Майк Тайсон вышли на ринг, мы обеспечили трансляцию боя примерно для 65 миллионов зрителей, смотревших его одновременно. В обычный день наша инфраструктура обрабатывает более 2 миллиардов запросов и свыше 38 миллионов событий журналирования в реальном времени каждую секунду. При таких масштабах вся картина не умещается в голове одной инженерной команды или на одной панели мониторинга. Чем больше у нас прямых трансляций, подкастов и потоков данных в реальном времени, тем важнее как можно быстрее понимать и обновлять наши системы, чтобы обеспечивать хорошее взаимодействие с пользователями. Понять работу системы такого масштаба в условиях ограниченного времени — зачастую задача сродни поиску иголки в стоге сена, в тёмных джунглях и с завязанными глазами.

Этот пост — о поиске этой иголки.

Четыре часа до исправления

Рассмотрим регрессию из тех, что случаются у нас на неделе. Домашний экран со списком подборок фильмов начинает загружаться примерно на 1,5 секунды дольше. Срабатывает оповещение. И тогда мы пытаемся выяснить, что вызвало проблему и как её исправить.

Как выясняется, регрессия в приложении может быть связана с чем угодно в системе: это может быть регрессия клиентского приложения после выпуска новой версии или запуска A/B-теста, снижение нагрузки в инфраструктуре, ответ GraphQL-запроса с некорректными данными из-за развёртывания сервиса на шесть переходов дальше по цепочке — на данном этапе подозрение падает на всё перечисленное. Поэтому, чтобы ответить на вопрос «Что вызвало проблему?», нужны данные со всей системы, а значит, необходимо тщательно просмотреть данные на всех её уровнях.

Уровень MELT

«Что вызвало проблему?»

Метрики, события, журналы и трассировки — или MELT, как их кратко называют в отрасли, — это необходимые исходные данные для такого расследования, и каждый из этих видов данных отвечает примерно на четверть вопроса. Мы собираем данные наблюдаемости по всем четырём направлениям и объединяем их в единый слой данных наблюдаемости. Благодаря этому мы можем в реальном времени наблюдать за системами: видеть, с чем сталкиваются пользователи, как работают приложения, а также что обрабатывают и на что отвечают наша серверная инфраструктура и сервисы.

MELT — метрики, события, журналы и трассировки, а также то, как их собирают в разных частях системы.

Дальнейшее расследование на каждом уровне может выглядеть так:

Что сообщает каждый уровень MELT и что остаётся за кадром

Хронология расследования

Сколько времени занимает расследование проблемы, поиск её первопричины и исправление, чтобы наши пользователи больше с ней не сталкивались?

Хронология расследования: около 4 часов

В нашем примере — четыре часа. Совсем немного времени ушло на сложные вычисления. Большую часть заняло восстановление связей, которые уже были известны нашим системам наблюдаемости, но нигде не были записаны так, чтобы человек или машина могли просто прочитать и обнаружить их.

В чём заключалось разногласие

В 2023 году интуитивным решением могло бы стать стремление получить больше данных или улучшить панели мониторинга. И то и другое помогает в отдельных случаях, но ни то ни другое не устраняет причину, из-за которой расследования затягиваются.

Сейчас 2026 год, и мы могли бы сказать: «Эй, агенты!» Но без подходящего контекста ИИ-системы галлюцинируют. Особенно когда команды дежурят и исправление нужно «прямо сейчас», мы не можем позволить неточному анализу агентов увести нас по ложному следу. Нам нужна нужная иголка, а не какая попало.

Каждая из наших систем внутренне согласованна, но изолирована от остальных. Atlas, наша платформа телеметрии, знает о приложениях и их временных рядах. Radar, наша система оповещений, знает о пороговых значениях и истории срабатываний. incident.io знает о критичности инцидентов и ответственных за них. PagerDuty знает о графиках дежурств. Spinnaker знает, что и когда было выпущено. А в истории Slack хранится информация, недоступная ни одной поисковой системе: какой инженер в прошлом квартале решил похожую проблему и к чему он пришёл.

Проблема в том, что эти системы не согласны между собой в том, о чём именно говорят. То, что в одной системе называется приложением, в другой — сервисом, а в третьей — кластером; названия могут отличаться суффиксом, правилами регистра или переименованием, о котором помнят лишь пара человек (знакомо специалистам по предметной области?). Чтобы объединить данные из этих систем, нужен человек, который держит соответствия в голове. В таких междисциплинарных расследованиях именно он становится узким местом. Пожалуй, проблему сквозной наблюдаемости лучше понимать как задачу моделирования данных.

Нам не хватало явного, машиночитаемого соглашения об объектах нашего операционного мира.

Онтология

У такого соглашения есть название: онтология. Онтология — это формальная спецификация типов, их свойств и возможных отношений между ними. Её базовая единица — триплет: факт, выраженный в виде субъекта, предиката и объекта. Рассмотрим несколько примеров таких триплетов.

api-gateway   rdf:type       ops:Application .
api-gateway ops:ownedBy "Team Bedrock" .
api-gateway ops:deployedIn "us-east-1" .

INC-5377 rdf:type ops:Incident .
INC-5377 ops:affects api-gateway .
INC-5377 ops:severity "SEV 2" .

В этом примере мы уже закодировали шесть фактов и можем одним запросом ответить на вопрос, для которого раньше приходилось обращаться к трём инструментам.

«Какие инциденты затронули приложения, принадлежащие команде Bedrock в us-east-1?» — теперь это один запрос вместо поиска информации в incident.io, Spinnaker и Radar.

Наш слой онтологии называется Observability Ontology. Он служит схемой, набором правил и общим соглашением, стандартизирующим понимание разных системами таких сущностей, как приложения, сервисы, инциденты, развёртывания и т. д.

Для её создания мы использовали стек W3C: RDF в качестве модели данных, OWL для онтологии, SHACL для проверки и SPARQL для запросов. Эти стандарты хорошо описаны и широко внедрены, поэтому модель можно переносить между графовыми хранилищами.

Данные самой онтологии хранятся в виде графа знаний и сохраняются в QuipuDB — нашей собственной графовой базе данных RDF, распределённом хранилище квадов на основе redb, встраиваемой базы данных «ключ — значение» на Rust. Данные здесь создаются путём преобразования исходной телеметрии, журналов и обсуждений инцидентов в триплеты (факты в формате субъект — предикат — объект).

Каждый цикл сбора данных также создаёт полную сериализацию Turtle для архива. Она удобна для чтения людьми и сравнения изменений, что оказалось полезнее для отладки, чем мы ожидали.

Наша онтология состоит из двенадцати пространств имён, каждое из которых отвечает за отдельную операционную область:

При создании онтологии мы приняли два важных решения, о которых стоит рассказать.

Во-первых, мы отказались от универсального типа Service. В разных инструментах слово «сервис» означает четыре разных понятия, поэтому приложениям присваивается ровно один тип — ops: Application, и каждое приложение перед созданием сущности проходит проверку по нашему каталогу программного обеспечения, в котором около 49 000 записей. Непроверенные строки — например, имена пользователей и команд или зависимости, извлечённые из топологии сети, — никогда не становятся приложениями. Мы также ограничиваем количество зависимостей в обоих направлениях: один популярный сервис может иметь тысячи обратных зависимостей и иначе доминировал бы в графе.

Второе решение касается того, что именно мы решили моделировать. В переписке об инциденте содержатся рассуждения о нём: проверенные и отброшенные гипотезы, сработавшие меры, сведения о том, кто и что знал. Вся эта информация хранится в канале инцидента в Slack, но исчезает из общего поля зрения, когда обсуждение затихает. Поэтому канал инцидента со 200 сообщениями, 50 участниками и 15 сервисами превращается в структурированную запись, упорядочивающую хаос инцидента в триплеты:

От недетерминированности к детерминированности

Чтобы построить этот граф, нужны инструменты, по своей природе стохастические. LLM суммируют обсуждения. Нечёткое сопоставление находит соответствия между названиями сервисов. Вероятностная система предлагает причинно-следственные цепочки. Ни один из этих инструментов не гарантирует одинаковый результат при каждом запуске, но на выходе наша система формирует детерминированный граф, который каждый раз одинаково отвечает на SPARQL-запрос.

Онтология обеспечивает детерминированность благодаря своему конвейерному подходу. Мы представляем конвейер в виде лестницы, по которой снижается энтропия, то есть доля информации, которая всё ещё остаётся в неструктурированной форме. Например, в начале конвейера LLM может выдать что угодно, но не может создать триплет, нарушающий систему типов. Мы настолько строго ограничиваем пространство возможных выходных данных, что стохастический процесс даёт детерминированный результат, которому можно доверять:

# The model may produce any prose. Its output MUST fit these predicates:
category IN ["incident", "question", "discussion", "decision"]
sentiment IN ["positive", "neutral", "negative", "urgent"]

# Result — a deterministic triple:
thread:123 slack:category "incident" .
thread:123 slack:isIncidentRelated "true"^^xsd:boolean .

Чтобы спуститься по этой лестнице, мы используем пять уровней. Каждый отдельный шаг недетерминирован, но в совокупности вся цепочка становится детерминированной. В этом и состоит весь секрет. Ниже мы расскажем о каждом уровне:

Пять уровней, обеспечивающих переход от недетерминированности к детерминированности

Обогатители: агенты, снижающие энтропию

Для снижения энтропии графа знаний мы используем то, что называем обогатителями. По графу работают десятки таких обогатителей. Каждый из них принимает зашумлённые входные данные и выдаёт типизированные триплеты, считывая при этом данные, добавленные предыдущими обогатителями. Контракт обогатителя намеренно ограничен:

class Enricher:
async def _enrich_async(self, ...):
raw = await self.fetch(...) # 1. read noisy input
result = self.analyze(raw) # 2. process (may be stochastic)
graph.add((uri, RDF.type, OPS.X)) # 3. emit TYPED triples
graph.add((uri, OPS.pred, Literal(result.value)))
return EnrichmentResult(success=True, triples_added=count)

Для всех обогатителей предусмотрены три неизменных правила:

  • каждая сущность имеет свойство rdf: type;
  • каждый URI соответствует единой схеме именования;
  • для каждого ops: Application проводится проверка по каталогу.

Стоит также упомянуть два операционных решения. Конвейер обогащения работает последовательно: загрузить граф, добавить триплеты и сохранить его.

Такая последовательность устраняет целый класс состояний гонки, и мы готовы платить за это временем выполнения. Вызовы внешних систем — метрик, журналов, событий и прочего — могут выполняться по принципу «по возможности», чтобы медленный API на нижестоящем уровне не блокировал сбор данных графа, хотя и мог вызвать некоторое ухудшение результата. Кроме того, мы работаем над переносом данных из этих отдельных систем в онтологию — например, создаём онтологии метрик и оповещений, — чтобы выполнять запросы ко всему непосредственно из онтологии.

Механизм корреляции: поиск цепочек взаимосвязей

Механизм корреляции объединяет огромное количество сигналов из разных источников и сводит их в причинно-следственные или корреляционные цепочки событий. Сейчас он обрабатывает тринадцать типов сигналов: ошибки в журналах, аномалии метрик, медленные и неудачные трассировки, оповещения, инциденты, развёртывания, изменения конфигурации, эксперименты, автомасштабирование, коммиты, сквозные узкие места и шаблоны ошибок. Затем он ищет связи между ними. Некоторые упорядоченные пары считаются причинно-следственными и имеют высокий априорный вес. Например: развёртывание предшествует ошибке в журнале, изменение конфигурации — аномалии метрик, неудачная трассировка — инциденту и так далее. Другие пары с высокой корреляцией формируют корреляционные цепочки. Такие цепочки оцениваются с учётом временной близости и критичности в пределах десятиминутного окна; цепочки с уверенностью ниже 0,6 отбрасываются.

Механизм корреляции

Задача механизма — предлагать гипотезы, подкреплённые доказательствами, а не делать выводы. Поэтому он хранит цепочки вместе с записями графа, на основе которых они были созданы.

Цепочка с оценкой 0,87 в примере выше — сильная гипотеза, которую может проверить человек или агент. Граф сохраняет оценку уверенности рядом с утверждением, чтобы пользователи могли понять, почему цепочка выглядит именно так, и взвесить варианты, принимая решение.

Маховик знаний

Каждый цикл сбора данных проходит одни и те же четыре этапа, и с каждым оборотом граф становится богаче. Это и есть маховик знаний, обеспечивающий непрерывное обогащение и улучшение контекста о нашей системе, хранящегося в графе знаний.

Маховик знаний

На этапе наблюдения собираются сигналы. На этапе обогащения добавляются типизированные триплеты. На этапе вывода находятся закономерности, незаметные в исходных данных. На этапе адаптации знания возвращаются в систему, чтобы установленные закономерности становились правилами обнаружения. Совместное действие этих четырёх этапов ведёт к созданию самообучающейся системы. Причинно-следственная цепочка, обнаруженная во время одного инцидента, становится известной закономерностью для следующего, и онтология постепенно перестаёт быть просто схемой и превращается в память.

Рассмотрим пример выше. Когда мы впервые сталкиваемся с инцидентом в api-gateway, вызванным тайм-аутом, и устраняем его, мы преобразуем полученные знания в записи онтологии. Так знания кодируются. По мере прохождения нескольких циклов кодирования граф начинает выявлять закономерности. После N циклов закономерности становятся опытом: «развёртывания api-gateway становятся причиной 40% инцидентов уровня SEV-2» и »30% проблем с развёртыванием api-gateway связаны с тайм-аутами соединения». Если представить это как аналитический вывод, мы сможем заблаговременно сокращать число инцидентов, а не только быстро реагировать на новые.

Применение графа на практике

На основе графа работает AutoRCA — наше внутреннее решение на базе ИИ-агентов, в котором специализированные агенты координируют действия вокруг одного вопроса. Если проследить за регрессией домашнего экрана, с которой мы начали этот пост, цепочка рассуждений агентной системы могла бы выглядеть примерно так:

Каждый специалист по отдельному типу входных данных создаётся людьми, глубоко разбирающимися в соответствующей области. Такое разделение труда работает только в том случае, если специалисты могут передавать друг другу результаты, не договариваясь о терминах общения и даже не зная друг о друге. Интерфейсом для них служит онтология. Каждый специалист осваивает один словарь — словарь графа. Команда, разрабатывающая специализированные сценарии использования трассировок, записывает результаты в виде триплетов об ops: Application; специалист по журналам считывает триплеты об этом же ops: Application, и ни одному из них не нужно знать о существовании другого. Новый специалист осваивает тот же словарь один раз и сразу может читать всё, что записали остальные шесть.

Если сравнить с расследованием, с которого мы начали, изменения не так масштабны, как может показаться. Оповещение по-прежнему срабатывает в 15:30, инженеру всё так же нужно оценить доказательства, а исправление по-прежнему должен написать человек, понимающий код. Онтология и граф берут на себя ту часть работы, на которую раньше уходил час или два: поиск ответственной команды, восстановление истории развёртываний, сопоставление сведений из разных частей системы и воспоминания о том, что похожее уже случалось в прошлом квартале. Мы пока на раннем этапе, поэтому ранжированные гипотезы иногда оказываются неверными. Именно поэтому каждая из них сопровождается доказательствами, на которых она основана. Но теперь, приступая к расследованию, инженер уже видит картину, на составление которой раньше уходила половина рабочего дня.

Если вы хотите создать что-то подобное

Многому из того, что мы построили, мы научились, сначала совершив ошибки. Вот принципы, которыми мы руководствовались бы при второй попытке с учётом полученного опыта.

  • Сначала моделируйте идентичность. Для каждого типа сущностей выберите один авторитетный каталог и проверяйте сущности по нему до их создания.
  • Считайте онтологию кодом. Ведите версии, проводите ревью и тестирование, вносите изменения через пул-реквесты. Такой подход упрощает разработку с помощью агентов и позволяет масштабировать работу над онтологией и вовлекать в неё команды.
  • Разделяйте понятия и экземпляры. Понятия меняются в человеческом темпе, а экземпляры — непрерывно. Если смешивать их, развивать и те и другие будет сложнее.
  • Используйте открытые стандарты. RDF, OWL, SHACL и SPARQL описаны в спецификациях, многократно реализованы и переносимы. Специально разработанная модель графа привязывает будущих пользователей к одной реализации.
  • Ограничивайте стохастические инструменты системой типов. Именно этот принцип мы отстаивали бы особенно решительно. Модели полезны как раз там, где детерминированность невозможна. Достаточно строго ограничив формат результата, можно преобразовать их вывод в данные, которым сможет доверять система запросов.
  • Выполняйте обогащение по возможности и в заданном порядке. Медленная зависимость должна в худшем случае ухудшать граф, но не блокировать его. А упорядочивание обогатителей, при котором каждый строится на результате предыдущего, повышает точность — и это стоит компромисса с параллелизмом, который даёт выигрыш в скорости.
  • Моделируйте человеческие рассуждения наряду с машинной телеметрией. Самые ценные связи в нашем графе появились благодаря обсуждениям. Телеметрия фиксирует действия системы, а обсуждения — то, как люди их понимали и интерпретировали. Эти рассуждения особенно ценно хранить и использовать как накопленный опыт, когда он нам понадобится.
  • Оставляйте за людьми право утверждения. Пусть агенты предлагают исправления, обогатители и изменения онтологии, но направляйте каждое предложение на рассмотрение с участием человека.

Что дальше

Граф открывает три возможности. Первая — автоматический анализ первопричин, при котором регрессия сопровождается ранжированным списком гипотез, подтверждённых графом. Вторая — автоматическое устранение проблем: при достаточно высокой уверенности в диагнозе система предложит конкретное действие, например выборочный откат, перенаправление трафика или изменение кода. И наконец, инфраструктура, способная самостоятельно восстанавливаться и реагировать на предсказанные сбои до того, как их заметят пользователи.

Кроме того, мы планируем интегрировать Observability Ontology с Upper — языком моделирования предметных областей, лежащим в основе унифицированной архитектуры данных Netflix (UDA). Upper позволяет командам описывать бизнес- и системные области как взаимосвязанные машиночитаемые модели, сохраняя их смысл и ограничения при преобразовании в конкретные схемы и системы. Такая интеграция свяжет операционные понятия — например, приложения, оповещения, развёртывания и инциденты — с более широким набором областей, моделируемых в Netflix, и предоставит инженерам и агентам общий семантический уровень для запросов, проверки и рассуждений. Мы начнём с проверки концепции, в рамках которой смоделируем инциденты в Upper, а затем на основе полученного опыта определим, как две системы должны объединиться.

Благодарности

Ничего этого не было бы без команд, которые делятся данными и опытом и проявляют терпение к молодой системе. Мы особо хотим отметить вклад членов нашей команды, благодаря которым эта работа стала возможной на самых ранних этапах: Каэла Маршек и Адитья Гаур. Мы также особенно благодарны участникам рабочей группы Netflix по онтологиям, Питеру Ройалу и Алексу Хаттеру, а также Александру Бертайсу и участникам команды Unified Data Architecture (UDA)/Knowledge Foundations за то, что поделились Upper и опытом моделирования предметных областей, а также помогли нам изучить, как Observability Ontology может стать частью более широкой семантической основы Netflix.

Наблюдаемость на основе онтологии: создание сквозного графа знаний в масштабах Netflix — первоначально опубликовано в Netflix TechBlog на Medium, где читатели продолжают обсуждение, выделяя фрагменты статьи и отвечая на них.

© Netflix Tech Blog