Привет! Мы около года занимаемся фронтенд (на Angular) и бэкенд (на Scala) разработкой в Solar webProxy. Наш продукт является системой Secure Web Gateway и обеспечивает фильтрацию HTTP и SOCKS5 трафика, защиту от вредоносных программ и утечек данных, проверку SSL и многое другое.

Год назад панель управления нашим приложением представляла собой ExtJS-приложение, в которое встраивались компоненты на Angular, а отчеты строились с помощью «форкнутой» Grafana версии 4. Такой «зоопарк» технологий рождал целый ряд проблем:

  • сложный подбор новых сотрудников, т.к. требовались специалисты со знанием Angular, ExtJS и Grafana;

  • высокая точка входа в разработку, т.к. только настройка локальной сборки занимала четыре страницы;

  • долгая сборка приложения в Jenkins.

В связи с этим было решено избавиться от ExtJS-обертки в пользу Angular, а также разработать замену для Grafana на Angular на фронте и Scala + Clickhouse на бэкенд. Про замену для Grafana и пойдет речь в этой статье.

В нашем продукте Grafana используется для отображения статистики журнала соединений, топов запросов, журналов запросов и т.д., а также для мониторинга за состоянием кластеров.

Solar webProxy на Grafana
Solar webProxy на Grafana

Зачем заменять Grafana на что-то другое

Возникает вопрос – какой смысл было писать что-то свое, если Grafana в последних версиях и так предлагает практически безграничный функционал для отображения графиков? Отчасти мы в команде согласны с этим утверждением, однако в нашем продукте использовалась «форкнутая» версия Grafana, обновление которой практически совпадало по времени с разработкой ее замены, а недостатки текущей версии не давали развиваться продукту.

Вот несколько причин, почему мы разработали свое решение:

  • Solar webProxy для сертификации во ФСТЕК проходил моделирование атаки злоумышленника (penetration test), и самым «дырявым» компонентом в системе являлась Grafana, которая позволяла получить доступ к clickhouse практически из браузера.

  • Отсутствие в команде экспертов по Grafana.

  • Плохая расширяемость Grafana. В перспективе нам будут нужны такие виды графиков как WorldMap, Network Graph и т.д.

  • Кривой экспорт в PDF. У нас в проекте запускался скрипт NodeJS с pupetter и постранично делал скриншоты со страницы с Grafana с помощью Chrome Headless.

  • Неудобство редактирования дашбордов для разработчиков. Редактирование SQL запросов в формате JSON – не самое лучшее решение.

  • Некоторые виды графиков строятся не так как ожидается (об это чуть ниже).

Повторюсь – большинство этих недостатков относится к Grafana 4.

Архитектура нового решения

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

name = "desktop" # Название дешборда
title = "dashboards.desktop.title" # Заголовок дешборда
panels = [
  {
    id = "0" # Идентификатор панели
    name = "Заголовок панели"
    columns = [ # Колонки таблицы с опциями сортировок и пагинации
          {
            name = "acc_name"
            title = "Персона"
            show = false
            attr = {}
          }
        ]
    query = {} # SQL-запрос в удобном многострочном виде
    attr = {} # параметры для отображения панели (вид графика, расположение легенды и т.д.)
  }
]
params = [ # Массив с формой фильтров
  {
    name = "flt_host" # идентификатор фильтра
    type = "selectBox" # Тип фильтра - обычный dropdown, поле для ввода, чекбокс и т.д.
    elements = []
    query = { # REST-путь к данным фильтра (например содержимое dropdown)
      method = "get"
      path = "/api/filter-hosts"
    }
    value = ["main"], # Значение фильтра по-умолчанию
    attr = {} # Другие атрибуты, нужные front-end-у, такие как приоритет, placeholder и т.д.
  }
]

Алгоритм взаимодействия фронтенд и бэкенд представляет собой следующие шаги:

  • Сначала фронт запрашивает и получает конфигурацию дашборда в JSON-формате (Scala автоматически конвертирует HOCON в JSON, т.к. Angular не распознает HOCON без сторонних библиотек).

  • Фронт заполняет клиентские данные (сортировки, значения фильтров) в этой конфигурации и отправляем их обратно на бэк.

  • Бэк парсит все клиентские данные и запрашивает соответствующие данные из Clickhouse, при необходимости трансформирует нужные панели согласно данным.

  • Фронт получает конфигурацию с отфильтрованными и отсортированными данными и отображает нужные панели.

  • При взаимодействии пользователя с интерфейсом, алгоритм переходит на второй шаг.

Для отображения таблиц и фильтров мы используем библиотеку NgZorro, а для отрисовки графиков – библиотеку D3. На бэкенде использовалась Scala 3.

Экспорт в PDF теперь происходит без использования NodeJS и pupetter, а непосредственно в Scala. Если пользователь хочет экспортировать дашборд или отдельную панель, то сначала на фронте мы сохраняем все графики в формате SVG и отправляем их на бэк, где все данные собираются в окончательный PDF.

Преимущества нового решения

  • Закрыт прямой доступ к базе данных через REST API.

  • Бесконечная расширяемость благодаря использованию низкоуровневой SVG-библиотеки D3.

  • Экспорт в PDF теперь реализован без использования pupetter, что позволяет экспортировать дашборды любого размера.

  • Конфигурационные файлы теперь в формате HOCON, их гораздо удобнее читать и редактировать.

  • Все графики строятся верно.

На последнем пункте остановимся подробнее. При построении поминутной статистики запросов пользователей возникала проблема: при отсутствии активности пользователей какое-то время, данные из базы данных приходили не нулевые, а просто отсутствовали, что приводило вот к таким артефактам:

Так выглядела статистика в отсутствие пользовательской активности
Так выглядела статистика в отсутствие пользовательской активности

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

Так выглядит Solar webProxy с нашим решением по замене Grafana сейчас:

Solar webProxy на собственном решении
Solar webProxy на собственном решении

Дальнейшее развитие продукта

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

На горизонте одного года планируем создать настраиваемые пользователем дашборды, которые позволят добавлять/удалять отдельные панели с рабочего стола.

Заключение

При разработке нового решения мы решили ряд проблем, стоящих перед продуктом, и получили бесценный опыт. Спасибо, что дочитали! Будем рады комментариям и обратной связи.

Александр Савельев

Инженер программист ГК "Солар"

Владислав Булыгин

Старший разработчик ГК "Солар"

Комментарии (1)


  1. mirunn
    07.06.2024 20:12

    Отображение без интерполяции (когда отсутствие данных это 0 - функционал из коробки)

    Не хочу звучать негативно, но кажется это разработка ради разработки :)