Pull to refresh

Comments 12

А я правильно понимаю, что у вас в итоговом агрегате для одного пользователя осталась только одна строка. Грубо говоря, это результат запроса
select user_id, dt, count(), avg(),…
from table
group by user_id, dt
Всё верно, в агрегате по пользователям для конкретного сервиса: 1 строка на 1 пользователя на 1 дату.
dt, user_id,… cols_about_user ....,… metrics…
И этого уровня достаточно для аналитики?
1) Ведь вы сразу потеряли хотя бы что-то близкое к real-time
2) Теряется возможность посчитать достаточно много метрик, например перцентили, воронки.
Сырые данные остаются и хранятся достаточное время — от месяца до бесконечности в зависимости от кол-ва событий. Как правило хватает для решения всех задач.
Какой прекрасный семейный вечер на КДПВ.
Да, картинка с монитора товарища майора от камеры Алиса
Событие доставляется в буферную таблицу на нужный шард, исходя из остатка от деления некоторого hash от user_id на количество шардов в кластере. Далее буферная таблица сбрасывает данные в локальную ReplicatedReplacingMergeTree

Расскажите поподробнее пожалуйста как это реализовано? Есть какой-то тип буферной таблицы и как он сбрасывает данные периодически?

В общей сложности в каждой таблице у нас от 50 до 200 колонок, при этом во всех таблицах есть сервисные поля. Например, лог ошибки error_log — на самом деле ошибкой мы называем выход за диапазоны типа. На случай, если в поле с возрастом польются странные значения, выходящие за размеры типа

Можно еще поподробнее про это, если не затруднит? Вы как то обрабатываете ошибки? Имеется в виду, как вы ошибку записываете в отдельное поле?
Расскажите поподробнее пожалуйста как это реализовано? Есть какой-то тип буферной таблицы и как он сбрасывает данные периодически?

Речь идёт о движке Buffer(database, table, num_layers, min_time, max_time, min_rows, max_rows, min_bytes, max_bytes)

Из документации:
Данные сбрасываются из буфера и записываются в таблицу назначения, если выполнены все min-условия или хотя бы одно max-условие. min_time, max_time — условие на время в секундах от момента первой записи в буфер; min_rows, max_rows — условие на количество строк в буфере; min_bytes, max_bytes — условие на количество байт в буфере.

Обычно мы используем с такими параметрами:
Buffer(database, table, 2, 10, 10, 10000000, 10000000, 100000000, 100000000);

Можно еще поподробнее про это, если не затруднит? Вы как то обрабатываете ошибки? Имеется в виду, как вы ошибку записываете в отдельное поле?

У нас буквально в таблице есть has_errors Int8, который служит для быстрого фильтра на предмет наличия ошибок и их количества. Также есть error_log String — строковое поле…

Когда на бэкенде формируется запрос на вставку, то происходит валидация полей на предмет
а) соответствия заданному типу
б) на то, что значение не выходит за размер типа.
В случае, если что-то не выполняется, в error_log пишется сообщение с указанием, что именно пошло не так, само значение заменяется на default значение для типа данных, а получившаяся строка пытается вставиться.
Пример, если я в поле amount Int64 по каким-то причинам буду пытаться с backend вставить строку, то сам ивент вставится, а я получу has_error = 1, error_log = 'amount not numeric', а в поле amount = 0 — дефолтное значение типа.

Отличная статья, спасибо!
Скажите пожалуйста, какое количество типов продуктовых событий вы ожидаете?
Наш опыт проектирования подобной штуки показал, что при наличии более 300 событий начинает сильно деградировать система репликации, zookeeper, и т.д.

У меня есть наброски,- где-то 50 условных продуктовых структур. Допустим, я ошибаюсь и будет ещё 50. Так что, скорее всего, уложимся в 100
Кстати это вполне должно решаться путем увеличения интервала сброса буфера и/или разделением разных таблиц по разным серверам.
Sign up to leave a comment.