Skip to content

Latest commit

 

History

History
184 lines (98 loc) · 19 KB

INTERNALS.ru.md

File metadata and controls

184 lines (98 loc) · 19 KB

Внутреннее устройство

Общие замечания

Netflow-данные можно рассматривать как многомерные временные ряды.

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

Обратите внимание — многие коллекторы в названии или описании используют слова "быстрый", "высокопроизводительный" и т.п.

Для снижения нагрузки как на роутеры, так и на коллекторы используют семплирование трафика. Роутер учитывает только каждый N-й пакет (точнее, пакеты выбираются из потока случайно, но в среднем выборка дает 1:N). Частоту семплирования можно увеличить, тем самым уменьшится количество экспортируемых фловов в секунду и нагрузка. Нужно принимать во внимание, что например при частоте семплирования 1:1000 вы не увидите буквально 99.9% трафика. Чем выше частота, тем меньше точность отчетов и тем хуже видны аномалии в трафике.

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

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

Современные netflow-коллекторы с открытым кодом как правило получают фловы, декодируют их, экспортируют в Kafka, ClickHouse, Elastic-стек и дальше обрабатывают и визуализируют другими утилитами. Например:

https://github.com/robcowart/elastiflow

https://github.com/akvorado/akvorado

https://github.com/netsampler/goflow2

Из коллекторов старой школы выжило не так много. Одни из самых известных:

https://github.com/phaag/nfdump

https://github.com/pavel-odintsov/fastnetmon - детектирует превышения порогов с помощью экспоненциальных скользящих средних

xenoeye и по внутреннему устройству, и по способу настройки ближе к коллекторам старой школы.

Коллектор хранит всю конфигурацию в текстовых файлах. Для экспорта в базу данных генерируются тоже текстовые файлы. Идея была в том, чтобы не привязываться к какой-то определенной СУБД, а генерировать файлы экспорта для разных баз данных, не обязательно реляционных. Во время остановки СУБД (в случае ошибки или когда база данных нуждается в обслуживании), коллектор не удаляет данные. После восстановления работоспособности СУБД, можно экспортировать накопленные данные, они не потеряются.

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

Кроме этого, стало понятно, что сетевые инженеры очень занятые люди, часто проще настроить частоту семплирования на стороне коллектора, чем просить их настроить options template.

Мы смотрели на несколько современных time-series баз данных, но по разным причинам пока остановились на обычном PostgreSQL. Он вполне приемлемо работает даже не механических жестких дисках, не требователен к памяти, широко распространен и поддерживается.

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

Рабочие и вспомогательные потоки

При старте коллектор читает общие конфиги и файлы mo.conf. Запускаются рабочие потоки и несколько вспомогательных:

  • Поток, который экспортирует агрегированные данные в файлы для СУБД
  • Поток, запускающий скрипты при превышении лимитов скользящих средних и при возврате трафика в норму
  • Поток, который делает дампы скользящих средних

Рабочие потоки принимают netflow и обрабатывают его.

Объекты мониторинга и фильтры

После того, как коллектор прочитал конфигурационный файл mo.conf, он пытается скомпилировать фильтр объекта мониторинга в байткод. Если получается, байткод сохраняется в памяти.

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

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

Как добавить в коллектор новое Netflow-поле

В Netflow v9 и IPFIX существуют и описаны несколько сотен полей. Коллектор из коробки поддерживает только самые распространенные. Поля некоторых типов можно достаточно просто добавить.

Коллектор оперирует netflow-полями двух видов. Первый вид — поля IN_BYTES, IN_PKTS и подобные. Эти поля считаются агрегируемыми. Если они встречаются в конфиге в массиве полей для экспорта, то данные из этих полей будут суммироваться.

Остальные поля считаются не-агрегируемыми.

Сейчас используется такой подход к описанию netflow-полей: они задаются в коде, в файлах netflow.def, filter.def и filter-ag.def.

Формат файлов такой:

netflow.def

FIELD(internal_id,            "Description",              FIELD_TYPE,      netflow_id,  min_size,  max_size)
  • internal_id — внутренний идентификатор, ожидается валидное имя для поля структуры C
  • Description — текстовое описание поля
  • FIELD_TYPE — тип поля (сейчас поддерживаются NF_FIELD_INT(целое) и NF_FIELD_IP_ADDR(IP адрес))
  • netflow_record_id — идентификатор поля
  • min_size, max_size — минимальный и максимальный размер поля в байтах

Данные о полях (идентификатор, размер и т.д.) можно взять из NetFlow Version 9 Flow-Record Format - Cisco Systems или из IP Flow Information Export (IPFIX) Entities

Добавление поля в netflow.def изменит только парсер netflow. Чтобы использовать это поле в фильтрах и для экспорта в СУБД, нужно добавить его еще в filter.def

FIELD(ID,      "name",          TYPE,  src_netflow_field,   dst_netflow_field)
  • ID — внутренний идентификатор
  • name — строка, которая будет использоваться в фильтрах
  • TYPE — тип (сейчас поддерживается RANGE(диапазон целых), ADDR4 и ADDR6 - IP адреса)
  • src_netflow_field, dst_netflow_field — поля netflow с которыми нужно работать. То, что написано в internal_id из netflow.def. Если могут быть префиксы "источник" (src) и "назначение" dst, нужно указать соответствующие поля.

Для агрегируемых полей используется файл filter-ag.def:

FIELD(ID,   "name",       netflow_field,   SCALE)

SCALE это коэффициент, на который умножается значение поля. Используется только для одного случая — можно указать в списке полей bits и коллектор будет экспортировать значение in_bytes * 8.

После изменения файлов программу нужно перекомпилировать.

Источник времени

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

Фиксированные временные окна

Для экспорта в СУБД применяется классичская схема с двумя банками данных.

В начале активен первый банк, рабочий поток записывает в него данные.

После того как подошло время экспорта, вспомогательный поток атомарно переключает банки. Активным становится тот, который был неактивным и в него начинают писаться новые данные.

После переключения неактивный банк пересортировывается. Если в параметрах указано, что для экспорта нужно только N первых записей, то отбираются первые записи, остальные суммируются. Из результата формируется текстовый файл, который записывается на диск.

Вспомогательный поток ждет нужное время и процесс повторяется.

Скользящие средние

В коллекторе используются куммулятивные скользящие средние

Значение байт или пакетов в скользящем окне пересчитывается при получении каждого нового флова по формуле:

$$N = N - \frac{\Delta t}{T}\cdot N + V$$

где N — текущее количество байт/пакетов в скользящем окне

$\Delta t$ — разница между текущим временем и временем последнего обновления скользящей средней

T — размер скользящего окна

V — значение величины (количество байт/пакетов) в новом пришедшем флове

Для таких скользящих средних можно использовать временные окна почти произвольной длины. Не нужно хранить все фловы за промежуток времени. Нужно хранить только две величины — количество байт или пакетов в окне и время последнего обновления

Но если использовать очень большие окна и большой трафик, то можно потерять точность. В коллекторе есть возможность повысить точность "в лоб" - можно вместо машинного double использовать __float128. Для этого нужно изменить значение MAVG_TYPE в файле monit-objects.h

IP-списки

Списки сетей хранятся в виде bitwise trie. Возможно, это не самый быстрый способ хранения, но достаточно простой и эффективный. В списках может храниться довольно много сетей, как IPv4, так и IPv6.

Базы GeoIP и AS

Соответствие IP-сетей и данных GeoIP/AS тоже хранится в виде bitwise trie. Для IPv4 и IPv6 создаются разные деревья.

Для парсинга CSV-файлов и генерации этих деревьев (в виде файлов) есть отдельная утилита xemkgeodb. Такую двухэтапную загрузку сделали в основном по двум причинам:

  • Владельцы GeoIP-баз могут изменить формат своих CSV-файлов (и они уже это делали). Об этом лучше узнать до загрузки данных в коллектор
  • GeoIP-базы могут быть довольно большими. На системах (или виртуалках) с небольшим количеством памяти их сложно обрабатывать. Можно сгенерировать файлы на компьютере с достаточным количеством памяти и поместить их на сервер с коллектором

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

Утилита xemkgeodb строит дерево тоже с помощью отображения файла в память. Алгоритм такой: создается файл большого размера (по умолчанию 4G), отображается в память. В этом участке памяти строится дерево, после окончания процесса пустой хвост файла обрезается.