ClickHouse 1.1.54310: Materialized Views с фильтрами и ARRAY JOIN для сетевых flow-данных
Внедряем ClickHouse для хранения NetFlow/IPFIX: Materialized Views с фильтрами и улучшенный ARRAY JOIN сократили агрегацию 100 млн записей с 20 минут до секунд.
ClickHouse 1.1.54310 - Materialized Views с WHERE-фильтрами, расширены табличные движки, улучшен ARRAY JOIN
Yandex выкатил ClickHouse 1.1.54310. На фоне всего что мы сейчас делаем с сетевым flow - это не просто патч-релиз.
Контекст: зачем вообще ClickHouse для NetFlow
У заказчика - телеком-оператор регионального уровня - поток NetFlow/IPFIX с нескольких граничных маршрутизаторов. Раньше это собиралось в MSSQL Server 2014, потом аналитик формировал отчёт через Excel-надстройку. Ждать приходилось от 15 до 25 минут. Запрос «топ-20 источников трафика за сутки» мог занять полчаса, если база не была свежеперезапущена.
Мы предложили ClickHouse как основное хранилище для аналитики flow-данных. Заказчик смотрел скептически - продукт относительно молодой, документация местами дырявая, Yandex его не позиционирует как «enterprise». Но у заказчика не было выбора объяснять директору почему отчёт за прошлый месяц нельзя посмотреть быстрее чем выпить чашку кофе.
Что изменилось в 1.1.54310
Три вещи попали точно в нашу задачу.
Materialized Views с WHERE. Раньше Materialized View в ClickHouse - это по сути триггер-INSERT в другую таблицу, куда идут все строки из источника. Фильтровать на этапе MV было нельзя. В 1.1.54310 появилась возможность добавить WHERE в тело MV - строки, не прошедшие фильтр, просто не попадают в целевую таблицу. Для нас это значит: можно держать «сырой» поток в одной таблице, а предагрегированные срезы по критичным префиксам IP или конкретным AS - в отдельных таблицах, без написания ETL-скрипта.
Улучшенный ARRAY JOIN. Flow-данные часто приходят пачками - один UDP-пакет содержит несколько flow-записей. У нас коллектор раскладывает их в массивы перед вставкой. ARRAY JOIN превращает строку с массивом в несколько строк - по одной на элемент. В прежних версиях ARRAY JOIN с несколькими массивами давал неожиданные результаты при разных длинах массивов. В 54310 поведение исправлено и задокументировано - LEFT ARRAY JOIN теперь работает предсказуемо, и мы перестали городить обходные костыли на стороне коллектора.
Расширение табличных движков. В частности, улучшения в Buffer-движке: теперь можно явнее контролировать условия сброса буфера в основную таблицу по числу строк и по времени. Для нас это позволяет принимать burst от коллектора без деградации вставок.
Как это выглядит в проде
Схема примерно такая: коллектор получает NetFlow, нормализует поля (src_ip, dst_ip, src_port, dst_port, protocol, bytes, packets, start_ts, end_ts, router_id), вставляет через Buffer-таблицу в основную MergeTree-таблицу. Партиционирование по дате. Сортировочный ключ - (router_id, toStartOfMinute(start_ts), src_ip) - это под большинство оперативных запросов.
Поверх сидят два Materialized View: один считает агрегаты по /24-подсетям за минуту (суммарные bytes/packets), второй - агрегаты по AS-номерам (добавили GeoIP-словарь для резолва). Оба теперь с WHERE - отбрасываем внутренние RFC1918-адреса из агрегата публичного трафика, это делалось раньше постфактум в запросе.
Результат который заказчик увидел первым: запрос «топ-20 AS по трафику за сутки» на таблице агрегатов. Не миллионы строк, а несколько тысяч в агрегированной таблице - ответ мгновенный. На сырой таблице, с сотнями миллионов записей за сутки - секунды. Заказчик переспросил трижды, думал что мы ему показываем кешированный результат.
Для сравнения: тот же запрос на MSSQL с тем же объёмом данных - мы не проверяли напрямую, потому что там данные уже не в той же форме, - но по словам аналитика «раньше это было минут двадцать».
Что пока не идеально
ClickHouse не умеет UPDATE и DELETE в обычном смысле. Для flow-данных это не проблема - поток иммутабельный. Но если приходит коррекция от коллектора (у некоторых вендоров бывает) - вставляем новую строку с флагом correction и учитываем в запросах. Небольшое усложнение логики приложения.
Мониторинг самого ClickHouse - через системные таблицы system.metrics и system.events. Мы прикрутили экспорт в Prometheus через простой скрипт-exporter. Штатного экспортера нет, пришлось написать самим.
Документация по Buffer-движку местами устарела и не отражала поведение в 54310 сразу после релиза. Разобрались через исходники и GitHub issues.
Итог
Заказчик согласился на расширение: добавляем хранение DNS-логов и DHCP lease-table рядом с flow. Для корреляции IP - имя хоста в реальном времени это отдельная задача, но ClickHouse с Dictionary-движком закрывает lookup достаточно быстро.
Для подобных задач - высокая скорость вставки, аналитические запросы по широким временным диапазонам, иммутабельные данные - инструмент работает именно так как ожидаешь по описанию. Это не всегда так бывает.