Комментарии 25
Чрезвычайно годный контент. Все-таки когда люди на чем-то фокусируются, сразу видно компетенции.
Добрый день. Интересная статья. На сколько Вам был бы полезен такой инструмент?
https://www.youtube.com/playlist?list=PLCxvGZsc-aLnk79wFLUzdaO6_4eitiMym
Очень много полезной информации, спасибо!
К сожалению, ограничить права пользователей на создание дашбордов и использование конкретных датасорсов без графаны enterprise, по-моему, не возможно.
Полезная статья, сейчас в команде как раз внедряем grafana, правда источник данных influxdb. Но годные советы во время проектирования всегда хорошо!)
Спасибо за статью! Правильно ли я понял, что динамическое семплирование используется для контроля объема данных передаваемых между Clickhouse и Grafana?
Объем именно передаваемых данных скорее никак не поменяется, все агрегации и фильтрации происходят непосредственно в Clickhouse - Результатом запроса почти всегда будет уже готовый временной ряд.
Динамическое семплирование помогает ограничить количество прочитанных данных при выполнении запросов за большой промежуток времени.
3. Используйте динамическое семплирование. Чем больший промежуток смотрите, тем меньше данных читаете.
создаём колонку
sample
типаUInt16
и используем её в ключе сортировки;заполняем случайными значениями в диапазоне от 0 до 99.
В каждом запросе ограничиваем
sample
пропорционально количеству прочитанных днейТаким образом, при чтении данных за 2 дня мы прочитаем случайную половину от всего объёма, при чтении 10 дней прочитаем 1/10 и так далее.
Очень интересное решение, в своём проекте приходилось обрабатывать случай, когда в табличке хранится большой объём записей о трафике клиентов с точностью до миллисекунд, а клиент хочет посмотреть график за день/неделю/месяц или даже больше, поэтому идёт чтение большого куска данных.
Думали над таким же решением, но у нас оно практически постоянно давало неточность измерений для частных случаев:
Если за последний день основные всплески трафика записались с
sample
от 50 до 100. График "за день" их покажет, а вот "за последние 3 дня" их проигнорирует, т.к.where sample <= 100/days
возьмёт лишь треть трафика и в итоге выведет число, которое может отличаться от реального (или от того числа, которое выводится на графике "за день") более чем на 20%, что может быть критично.Если трафик неравномерный или импульсивный, например за день для конкретного клиента набегает всего 1к строк примерно равным количеством записей каждый час, то игнорировать половину из них, при запросе "за последние 2 дня" это примерно равно "заменить половину записей нулями".
Понятное дело что эту ошибку можно уменьшить если поиграться с диапазоном для sample
и условием where sample <=
, но у каждого клиента может быть разное поведение трафика и подобрать "ключ ко всем" не получится, ровно как и определить количество записей до начала запроса и скорректировать запрос.
А вы не сталкивались с подобными проблемами? Или в вашем случае различия в значениях на дневном и недельном графиках не критичны?
Да, это очень хорошее замечание, что такое решение не всегда подходит. Бывают случаи когда перед тем как рассчитать метрику, приходится агрегировать значения по какому-нибудь user_id или какому-то другому полю с высокой кардинальностью. В таком случае динамическое семплирование по случайному числу вовсе приведет к неверным результатам.
Но в обычных ситуациях, при достаточно большом количестве данных мы считаем что данные «размажутся» равномерно и не думаем о распределении
Масштабный материал, спасибо. Хотя я бы тут добавил, что Grafana для OLAP (для которого Clickhouse большей частью и используется) — это из раздела "сомнительно, но окей", так как когда задачи не time-series, а slice-and-dice, все эти time-series корни графаны начинают заметно мешаться под ногами. Жить можно, конечно, но можно рассмотреть и другие продукты.
Несколько вопросов по статье:
Старайтесь использовать колонки из ключа сортировки таблицы (секция ORDER BY при создании таблицы).
Можете разьяснить, это о чём? В чем разница чтения колонки из индекса и не из индекса?
К тому же, на основании данной фразы кто-то может подумать, что надо затянуть как можно больше колонок в sorting key (а лучше вообще все), что приведет к проблемам.
Используйте Materialized View или внешние системы по типу Airflow для вычисления агрегатов в фоне.
Там теперь еще есть production-ready проекции, которые и считают агрегаты в фоне без необходимости создания и поддержки дополнительных таблиц (но есть подвох для Replacing/Aggregating движков)
Интерпретируйте партицию как отдельный файл. На открытие и чтение каждого файла система тратит время. Чем меньше партиций используется в запросе, тем лучше
пишете вы, а потом используете партиционирование по toMonth(timestamp), складывая в одну партицию месяцы разных годов и лишая себя возможности использовать minmax индекс партиции.
Пример с партициямипо toMonth: https://fiddle.clickhouse.com/cd9fe46b-fedc-41e8-85e1-9893577d3729
Пример с партициями по toYYYYMM: https://fiddle.clickhouse.com/b6e5848d-a86f-4c8f-98f1-6772c13b4e59
Экспериментируйте с гранулярностью индекса
и не забывайте о последствиях, я бы добавил, дабы не возникло желание сделать гранулярность 1, "как в b-tree".
Спасибо за такой подробный комментарий!
OLAP в Grafana помогает нам не меняя источника вести как привычный timeseries мониторинг, так и погружаться в событийную аналитику. Где-то видел нагрузочное сравнение ts-хранилищ и Clickhouse, выглядело достойно)
Действительно, использовать все подряд в индексе не стоит. Это лишь к тому, что использование колонок из индекса оптимизирует запрос. Довольно простая идея, которую мне показалось уместно выделить
С партициями и вправду я ошибся, стоит использовать toYYYYMM()
Спасибо! За статью, попало прям в наш кейс))
Подскажите вы пробовали что-то типа grafana-as-code? В чем наша проблема - у нас есть несколько сред, разные роли, которые могут настраивать дашборды и сейчас мы подходим к точке когда тяжело отслеживать изменения всех дашбордов. Разработчик поменял фильтр в SQL запросе, сапорт одновременно изменил формат переменных и в итоге иногда тяжело понять комплексно, что поменялось.
Есть идея вынести дашборд в код, дашборды будет настраивать выделенная группа людей и пушить в репо. Из репо уже подтягивать свежие JSON файлы всех дашбордов и разливать по всем средам. Может если кто пробовал какие есть подводные камни))
А там ведь уже есть ролевая модель https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/
Можно накинуть роль редактора только редакторам, а остальным роль viewer. Или я не очень вопрос понял
К слову Grafana-as-code я пробовал, но вообще в другом направлении) Решал задачку автоматизации работы с Grafana, типо копирования строк целиком, перенос переменных из другой борды и всякое такое.
А кем решается вопрос , "кто обманывает"?
Я думаю, что единым источником данных для всего)
В нашем случае проблемы несогласованности метрик между дашбордами были по причине огромного количество различных условий для фильтрации в графиках. Мы решили проблему тем, что создали горячую таблицу, в которую попадают уже отфильтрованные для мониторинга данные.
спасибо за статью, всё круто, у нас такой же стек=) для себя подчерпнул интересное насчет:
данных о дешбордах, графиках и юзерах в with - планирую добавить тоже самое и потом трекать эффективность работы графиков и дешей и выявлять тех кто перегружает бд)
низкокардинальные столбцы - мб есть смысл пересоздать наши сырые таблицы с изменением типов данных со String на низкокардинальный стринг и то же с int - но таких немного у нас и видимо не сильно бустанет, потому не приоритетно
еще интересно насчет CH 23.1 - кеширование рез-тов выполнения запросов - пока не понимаю как это лучше использовать и стоит ли обновляться, т.к. кажется нам не сильно надо из-за использования отдельных витрин.
А вот вопрос: а почему в вашем стеке нет DBT (https://docs.getdbt.com/docs/introduction), он же очень удобен как раз для создания агрегатов различных и это кажется лучшим решением чем создание мат представлений - плюс так же можно и фильтры создавать не в виде вью а в виде закешированных табличек и словарей через .sql файлики в dbt. В курсе ли вы насчёт DBT и если да, то почему не дополняете им стек ?
Мы стараемся не использовать матвью именно для агрегирования. В наших задачах большинство метрик измеряется в квантилях, на больших данных использовать стейты для финальной агрегации квантилей оказывается не очень производительно. Имею ввиду построение графиков.
С задачей агрегирования у нас справляется Airflow. Этого нам пока более чем достаточно. Если короткий ответ, то пока просто не возникало самой потребности в dbt)
А как вы это делаете в airflow, написали свой код для создания и обновления данных (таблиц) и тригерите его чз PythonOperator? Или специальный какой то оператор используете? Я в свое время писал свой модуль для этой же цели и намучился с ним) Я это к чему, а все таки не проще dbt посмотреть и чз него и вью и агрегаты создавать? Если что не пытаюсь навязать dbt, но все же если вы создаете какието вью или таблицы то это кажется проще и делать и контролировать чз него) или мб у вас настолько элегантное решение в airflow, что даже и не думали в сторону других инструментов?) Вот тогда оч интересно как вы это делаете в airflow)
Если задача простая, например просто сгруппировать данные в таблице за последний день, то используем готовый плагин https://github.com/bryzgaloff/airflow-clickhouse-plugin , а именно ClickhouseOperator. Простой в использовании, работает стабильно.
Если что-то посложнее, например что-то чем-то дообогатить нужно, дополнить данными из других кластеров/источников, то используем PythonOperator и там уже крутим данные используя clickhouse_driver https://clickhouse-driver.readthedocs.io/en/latest/api.html#clickhouse_driver.Client.query_dataframe
Мы просто пока не столкнулись с проблемами, но возможно в будущем и придем в чему-то типо dbt :)
понял, спасибо за пояснения) по идее по сложности использования PythonOperator и ClickhouseOperator не сильно отличаются, т.к. PythonOperator все равно также чз clickhouse_driver придётся запускать)
а если дообогатить надо так, чтобы еще и учесть последовательность запусков - сначала запустить одну, затем другую - надо эту зависимость не забыть ещё и где-то указать, чтобы никто эту последовательность не изменил)
а если надо перезаписать часть таблицы, то тогда надо идти руками восполнять данные (если у вас привязка в airflow к лог. датам то чуть попроще) и еще и зависимость не забыть между другими таблицами)
простите за навязчивость, но очень кажется что вы многое теряете без dbt) да, правда все внешние источники надо сначала писать в одну бд перед тем, как использовать dbt, но это не кажется большой проблемой. Ставите себе его на сервер (open source), храните все модели в sql файликах а не дагах, все зав-ти учитываются самостоятельно и не надо их отслеживать, просто запускаете группы моделей или модели через dbt run --models +<model> (тогда все обновляется по очереди с учетом зав-тей благодаря "+"перед моделью), перезаписать витрину оч быстро и просто, версионирование sql файликов гораздо проще поддерживать чем скриптов с дагами. Так же запускаете обновление чз airflow (bash operator в одну строку) или github actions и обновляете либо по-таблично либо по группам витрин чз использование exposures. А ещё там есть макросы и автоматическая генерация документации по всем вашим таблицам с отображением графов зав-тей) главная проблема, которую надо решить - это как сделать инкрементальное обновление - писать внахлест + использовать ReplacingMergeTree() + view с дедупликацией на витрины, либо сразу писать в .sql файликах так, чтобы придерживаться правила идемпотентности (чтоб данные не писались повторно при новых запусках)
Спасибо за статью. Очень насыщенная.
Можете назвать количество и харектеристики серверов для обслуживания этих данных?
Именно самого железа не скажу точные характеристики, но касательно конфигурации Clickhouse нашей команды: мы поделили все данные на несколько кластеров (Кстати о разделении ответственности), у каждого разное железо и свой конфиг. Основной кластер состоит из 6 шардов с реплика-фактор 2. Каждая нода кластера это примерно 7-8Тб SSD и 20-30Тб HDD, получается где-то 1/3 соотношение.
В дополнении к статье — наткнулся на небольшую схемку, которую я составлял на первых этапах. Это может помочь в понимании важности каждого из кусочков мониторинга.
![](https://habrastorage.org/getpro/habr/upload_files/aa7/630/266/aa763026676bcdb76896c754d8e6ae47.png)
Спасибо! Действительно полезная статья, в отличие от сотен прочих.
Clickhouse, Grafana и 3000 графиков. Как построить систему быстрых дашбордов