При внедрении новой технологии нужно задать себе очень важный вопрос: «Каковы варианты использования всего этого?» Вот почему мы решили взять интервью у создателей некоторых самых интересных проектов BPF, чтобы они могли поделиться своими идеями.
Sysdig — компания, которая создает одноименный инструмент для устранения неполадок Linux с открытым исходным кодом, — начала работать с eBPF в 2017 году под ядром 4.11.
Поначалу модуль ядра использовался для извлечения и выполнения всей работы на стороне ядра, но по мере увеличения базы пользователей и когда все больше и больше компаний начали экспериментировать, Sysdig признала, что это ограничивает большинство внешних участников процесса во многих аспектах.
• Растет число пользователей, которые не могут загружать модули ядра на свои машины. Облачные платформы становятся все более и более строгими в отношении того, что могут делать программы во время выполнения.
• И новые, и даже старые участники не понимают архитектуру модуля ядра. Это уменьшает их общее количество и является ограничивающим фактором для роста проекта.
• Обслуживание модулей ядра затруднено не только из-за написания кода, но и из-за усилий, необходимых для обеспечения его безопасности и правильной организации.
В связи с этим Sysdig решила попробовать подход, предусматривающий написание того же набора функций, что и в модуле, но с помощью программы eBPF. Еще одно преимущество, которое автоматически обеспечивает внедрение eBPF, — это возможность для Sysdig в дальнейшем использовать другие полезные функции трассировки eBPF. Например, довольно легко прикрепить программы eBPF к определенным точкам выполнения в приложении пользовательского пространства с помощью пользовательских зондов, как описано в разделе «Зонды пользовательского пространства».
Кроме того, теперь проект может задействовать собственные вспомогательные возможности в программах eBPF для отслеживания треков запущенных процессов, чтобы понять, что именно происходит в системе. Это дает пользователям еще больше информации для устранения неполадок.
Несмотря на то что сейчас все иначе, вначале Sysdig столкнулась с некоторыми проблемами из-за ограничений виртуальной машины eBPF, поэтому главный архитектор проекта Джанлука Борелло решил улучшить ее, добавив патчи для восходящих потоков к самому ядру, в том числе:
• возможность с самого начала работать со строками в программах eBPF (https://oreil.ly/ZJ09y);
• несколько патчей для улучшения семантики аргументов в программах eBPF 1 (https://oreil.ly/lPcGT), eBPF 2 (https://oreil.ly/5S_tR) и eBPF 3 (https://oreil.ly/HLrEu).
Последнее особенно важно для работы с аргументами системного вызова — вероятно, наиболее важного источника данных, доступного в инструменте.
На рис. 9.1 показана архитектура режима eBPF в Sysdig.
Ядром реализации является набор пользовательских программ eBPF, отвечающих за инструментарий. Эти программы написаны в подмножестве языка программирования С. Они скомпилированы с использованием последних версий Clang и LLVM, которые переводят высокоуровневый код C в байт-код eBPF.
Рис. 9.1. Архитектура Sysdig eBPF
Существует одна программа eBPF для каждой отдельной точки выполнения, где Sysdig использует ядро. В настоящее время программы eBPF привязаны к следующим статическим точкам трассировки:
• входной путь системного вызова;
• путь выхода системного вызова;
• переключение контекста процесса;
• завершение процесса;
• незначительные и основные ошибки страницы;
• процесс доставки сигнала.
Каждая программа принимает данные точки выполнения (например, для системных вызовов — аргументы, переданные вызывающим процессом) и начинает обрабатывать их. Обработка зависит от типа системного вызова. Для простых системных вызовов аргументы просто копируются дословно в карту eBPF для временного хранения, пока не будет сформирован весь кадр события. Для других, более сложных вызовов программы eBPF включают логику для перевода или дополнения аргументов. Это позволяет приложению Sysdig в пользовательском пространстве задействовать данные целиком.
Некоторые из дополнительных данных:
• данные, связанные с сетевым подключением (TCP/UDP, IPv4/IPv6, имена сокетов UNIX и т.д.);
• высокодетализированные метрики о процессе (показатели счетчиков памяти, количество сбоев страниц, длина очереди сокетов и т.д.);
• данные, специфичные для контейнера, такие как контрольные группы, к которым принадлежит процесс, выдавший системный вызов, а также пространства имен, в которых существует процесс.
Как показано на рис. 9.1, захватив все необходимые данные для определенного системного вызова, программа eBPF использует специальную встроенную функцию BPF для передачи данных в набор кольцевых буферов для каждого CPU, которые может задействовать приложение пользовательского пространства, читая с очень высокой пропускной способностью. Именно здесь применение eBPF в Sysdig отличается от типичной парадигмы применения карт eBPF для обмена с пространством пользователя небольшими данными, созданными в пространстве ядра. Чтобы узнать больше о картах и о том, как пространствам пользователя и ядра общаться между собой, обратитесь к главе 3.
С точки зрения производительности результаты хорошие! На рис. 9.2 показано, что затраты на инструментарий eBPF в Sysdig незначительно превышают расходы на классические инструменты модуля ядра.
Рис. 9.2. Сравнение производительности Sysdig eBPF
Вы можете попробовать применить Sysdig и воспользоваться его поддержкой eBPF, следуя инструкциям по использованию (https://oreil.ly/luHKp), и обязательно посмотрите код драйвера BPF (https://oreil.ly/AJddM).
Стартап Flowmill появился на основе научного исследовательского проекта Flowtune (https://oreil.ly/e9heR), основанного Джонатаном Перри. В рамках Flowtune изучали, как эффективно планировать отдельные пакеты в перегруженных сетях центров обработки данных. Одним из основных элементов технологии, необходимых для этой работы, был способ сбора сетевой телеметрии с чрезвычайно низкими издержками. Flowmill адаптировал эту технологию для наблюдения, агрегирования и анализа связей между каждым компонентом в распределенном приложении для решения следующих задач:
• обеспечения точного представления о том, как сервисы взаимодействуют в распределенной системе;
• определения областей, в которых произошли статистически значимые изменения в скорости трафика, ошибках или задержке.
Flowmill использует зонды ядра eBPF для отслеживания каждого открытого сокета и периодического сбора метрик операционных систем. Это сложно по ряду причин.
• Необходимо подключать как новые, так и существующие соединения, уже открытые на момент установления зондов eBPF. Кроме того, зонды должны учитывать TCP, UDP, а также пути кода IPv4 и IPv6 через ядро.
• Для систем на основе контейнеров каждый сокет должен быть отнесен к соответствующей контрольной группе и присоединен к метаданным соединителя с платформой, такой как Kubernetes или Docker.
• Трансляция сетевых адресов, выполняемая через conntrack, должна быть оснащена инструментами для установления соответствия между сокетами и их видимыми IP-адресами. Например, в Docker и Kubernetes общая сетевая модель задействует исходный NAT для маскировки контейнеров за IP-адресом хоста, а виртуальный IP-адрес службы используется для представления набора контейнеров.
• Данные, собранные программами eBPF, следует обработать, чтобы сопоставить сведения, полученные на двух сторонах соединения.
Добавление зондов ядра eBPF обеспечивает гораздо более эффективный и надежный способ сбора этих данных. При этом полностью исключается риск пропущенных соединений и все может быть сделано с минимальными издержками на каждом сокете в течение секунды. Подход Flowmill основан на агенте, который сочетает в себе набор зондов ядра eBPF и сбор метрик пространства пользователя, а также агрегирование и постобработку. Здесь активно используются кольца Perf для передачи метрик, собранных в каждом сокете, в пространство пользователя для дальнейшей обработки. Кроме того, он применяет хеш-карту для отслеживания открытых сокетов TCP и UDP.
Компания Flowmill обнаружила, что, как правило, существует две стратегии проектирования измерительных методик eBPF. Простой подход находит одну-две функции ядра, которые вызываются для каждого инструментованного события, но требует, чтобы код BPF поддерживал больше информации и выполнял больше работы за каждый вызов, причем очень часто. Чтобы уменьшить опасения по поводу того, что контрольно-измерительные средства влияют на производственные нагрузки, Flowmill применил другую стратегию: инструментам назначались более специфические функции, которые вызываются реже и обозначают важное событие. Это значительно снижает накладные расходы, но требует бо'льших усилий для охвата всех важных путей кода, особенно в разных версиях ядра по мере его развития.
Например, tcp_v4_do_rcv перехватывает весь трафик TCP RX по установленным соединениям и имеет доступ к носителю struct, но у него чрезвычайно большой объем вызовов. Вместо этого пользователи могут задействовать функции, связанные с ACK, обработкой пакетов не по порядку, оценкой RTT, и многие другие, которые позволяют обрабатывать определенные события, влияющие на известные метрики.
При таком подходе к TCP, UDP, процессам, контейнерам, conntrack и другим подсистемам система достигает чрезвычайно хорошей производительности с довольно низкими издержками, которые зачастую трудно измерить. Загрузка процессора обычно составляет 0,1… 0,25 % на ядро, включая eBPF и компоненты пользовательского пространства, и зависит главным образом от скорости создания новых сокетов.
Подробнее о Flowmill и Flowtune можно узнать на их сайте (https://www.flowmill.com).
Sysdig и Flowmill являются пионерами в использовании BPF для создания инструментов мониторинга и наблюдения, но они не единственные. В книге мы упоминали о других компаниях, например Cillium и Facebook, которые выбрали BPF в качестве основы для разработки высоконадежной и эффективной сетевой инфраструктуры. Мы будем очень рады узнать о том, что вам удалось создать с помощью BPF.