Легенда (сбор данных и аналитика метрик с промышленных датчиков).
Веб приложение по автоматизации процессов ремонта оборудования на условном металлургическом заводе.
Два главных сервиса, обеспечивающих расчеты для аналитики:
- Сервис по мониторингу датчиков станков - принимал данные по Кафке, данные отправлялись командой смежников с завода, которая структурировала данные в JSONB и отправлялись в timescale формате.
В этом сервисе показания анализировались и отправлялись в БД. Eсли были отклонения от допустимых значений, то создавался объект Аномалии и объект Событие, который эту аномалию содержал и отправлялся в другой сервис по управлению заявками на ремонт по REST.
Данные старше 15 дней (управляется retention policy параметром внутри базы расширения timescale db) отправлялись в архив в виде статистических данных (Data view). Статистические данные отправлялись в сервис, который занимался Документацией и Аналитикой.
В сервисе также был реализовано прогнозирование отказов оборудования, по передаче заявок в сервис по плановому обслуживанию оборудования.
- Сервис по управлению заявками на ремонт, общался по REST с фронтом и другими сервисами, отправлял заявки на ремонт автоматически по email и во внутреннее приложение на фронт. По алгоритму приоритизации аномалий и заявок.
Возможные вопросы и описание подробное описание архитектуры проекта
1. Откуда берешь данные ?
данные отправляются через kafka в нашу базу данных в формате time series данные + структурированные данные в виде json
От одного датчика каждые 5 секунд 1кб данных. Например у нас 1157 датчиков. За сутки 1157кб*12*60*24=2160000/10^-6 = 20Гб в сутки.
Данные хранятся 15 дней, хранение определяется retention policy в timescaleDB.
Кратко о kafka connector для postgres
https://www.timescale.com/blog/create-a-data-pipeline-with-timescaledb-and-kafka/
2. Как считали производительность?
Распределение данных между партициями позволяет значительно увеличить производительность. Чем больше партиций, тем больше потребителей может одновременно обрабатывать данные. Рекомендуется стремиться к тому, чтобы каждая партиция не превышала 1-2 ГБ данных.
Если партиция будет иметь около 1–2 ГБ данных, то для этого нам потребовалиось примерно 10–20 партиций.
Подробнее про расчет количества сообщений
Теперь найдем частоту, с которой такие сообщения должны поступать:
Количество топиков партиций и потребителей
- Использовали по топику на каждый из вариантов типов данных принимаемых от датчика (температора, давление итд)
- Чтобы обеспечить стабильную производительность, рекомендуется использовать большее количество партиций. Например, чтобы обрабатывать 243 сообщений в секунду, потребуются несколько потребителей. Если распределять нагрузку между 10 потребителями, каждый из них должен обрабатывать около 25 сообщений в секунду.
- В идеале, 10-20 партиций помогут обеспечить необходимую производительность и параллелизм обработки.
- наш bottleneck это запись в базу, поэтому для самой лучшей производительности нужно установить количество консумеров равному кол-ву партиций, в нашем случае это зависит от кол-ва подключения к БД (max_connection_pool в postgres по дефолту это 100) у нас может быть например 15-20.
- в итоге случае будет 20 партиций распределенных на 6 топиков с данными от датчиков + около 15-20 консумеров.
producer(датчик с метрикой) -> топик/партиция ( с id определяющим вид метрики) -> 2-3 партиции -> группа из двух консумеров.
ПС: посмотри вкратце как примерно выглядит код для подготовки producer:
3. Сколько у вас было инстансов приложения?
У нас работал сервер, где можно было развернуть резервную копию инстанса
если несколько инстансов -> у нас сервис дискавери (ip серваков с инстансами) -> определять какой инстанс работает будем по health чек паттерн
4. Как хранишь данные?
Использовал Postgres с расширением timescaleDB сбора данных с датчиков
Кратко о kafka connector для postgres
https://www.timescale.com/blog/create-a-data-pipeline-with-timescaledb-and-kafka/
В моих данных две колонки: TIMESTAMP поле “time” и JSON поле с данными датчиков “data” где собраны данные в с определенного сенсора. Данные слишком часто меняются и следить за динамикой проще, когда данные приходят в JSON и конкретном блоке данных синхронизированным по времени.
(Для data view данные с JSON можно распарсить и вытащить данные о конкретном датчике в отдельную колонку)
выглядит примерно так, колонка time + это плоский json со списком данных во float формате:
FYC: создание и insert в нашу таблицу для сбора данных выглядит примерно так:
Можно даже индекс задать на колонке JSONB на конкретное поле:
если вдруг будет вопрос по железу: Кластер postgres на два сервера, один резервный сервер с двумя дисками процы xeon, 32 ГБ RAM, при объеме данных в 2Tb.
5. Почему Postgres + timescaleDB ?
Мы знали, что есть несколько подобных решений, например клик хаус, но это была бы отдельная база, только для чтения и сбора аналитики, для чего пришлось бы обучать или нанимать новых специалистов, но мы решили использовать TimescaleDB, чтобы работать с данными в одном стеке с Postgres. Основная база данных у нас — PostgreSQL, мы активно собираем данные с помощью нее, также используем эти же данные для чтения. Поэтому мы решили не создавать дополнительных слоев для передачи и складирования данных, а использовать timescaleDB, для ускорения работы с временными данными, а также создания data view слоя для выгрузки и трекинга аналитики. Мы решили, что правильнее будет не выходить за рамки экосистемы и не ошиблись. А также это решение оказалось быстрее остальных.
TimescaleDB показывает высокие результаты производительности, как в своем весе, так и среди колоночных СУБД. Кроме этого, решение может использовать экосистему PostgreSQL, что снижает порог входа и не вынуждает учить диалекты SQL. Область применения СУБД достаточно обширная.
К тому же есть множество кейсов где timescale используется для анализа Интернет вещей (IoT)
Сбор данных с датчиков: TimescaleDB отлично подходит для хранения и обработки данных, поступающих от множества IoT-устройств, таких как датчики температуры, давления и другие.
Анализ данных в реальном времени: Обработка и визуализация данных в реальном времени для принятия оперативных решений.
краткий бенчмарк https://questdb.io/blog/2022/05/26/query-benchmark-questdb-versus-clickhouse-timescale/
На всякий случай: пример проекта с timescale
https://habr.com/en/companies/selectel/articles/756146/
6. А как читали данные и что там с аналитикой??
Мы использовали паттерн Data View для сбора данных, это денормализованное представление данных для отчетов и аналитиков, которое легко использовать потому что формат колонок уже будет подготовлен для них. Может использоваться для реализации механизмов, таких как кэширование и агрегация данных, чтобы обеспечить более быстрое извлечение информации.
- Мы использовали представления (Views), которые агрегируют данные из одной или нескольких таблиц, чтобы предоставить более удобный формат для чтения. Это помогает упростить запросы и скрыть сложность схемы.
- Также мы использовали материализованные представления по запросам, c использованием индексации по ним, на случай если нам нужны дополнительные агрегированные значения
7. Какие паттерны использовал в своем проекте?
В итоге у нас по сути готовый микросервисный паттерн CQRS. У нас есть модель(паттерн data view) для чтения. А для записи мы используем другую схему бд:
- Схема для записи (Command Model): используется для обработки всех операций записи (создание, обновление, удаление) и хранит данные в модели, оптимизированной для изменения.
- Схема для чтения (Query Model): ориентирована на операции чтения данных и имеет совершенно другую денормализованную структуру, которая оптимизирована для выполнения запросов и извлечения информации. (паттерн data view)
Для проверки инстансов используем stability pattern health check.
8. У вас микросервисный проект, как осуществлялась связь между сервисами?
Для синхронизированных запросов у нас применяется rest, + в качестве нотификации у нас рассылка email происходит с помощью планировщика cron с подготовленными python скриптами и темплейтами.
(Можно добавить, что при выявлении и загрузки объекта аномалии в таблицу аномалий, внутри БД срабатывал триггер, который постоянно мониторил эту таблицу, помогал формировать отчеты и запускал планировщик скриптов
https://postgrespro.ru/docs/postgresql/9.6/plpgsql-trigger#plpgsql-dml-trigger ).
Что тебя еще могут спросить
Подключил прометеус, метрики собирал для интеграции с графаной, добавил источник данных("Data Sources") Prometheus в конфигурации Grafana.
Это также было нужно, чтобы получить алерты при определении пороговых значений и вычисления "аномалий"
это разделение базы данных на несколько узлов для повышения производительности и масштабируемости, что важно для систем с большой нагрузкой на чтение.
Но на проекте не потребовалось и не использовалось ничего кроме репликации
Дополнительные материалы:
- Что такое time-series data и примеры использования: https://www.timescale.com/blog/time-series-introduction/
- краткий бенчмарк timescale vs clickhouse vs questDB: https://questdb.io/blog/2022/05/26/query-benchmark-questdb-versus-clickhouse-timescale/
- На всякий случай: пример проекта с timescale: https://habr.com/en/companies/selectel/articles/756146/
- Кратко о kafka connector для postgres: https://www.timescale.com/blog/create-a-data-pipeline-with-timescaledb-and-kafka/