Clickhouse
одна из самых крутых вещёй, с которыми я сталкивался в IT.
Невероятно быстрая OLAP база данных, которая отлично работает как в облаке
(есть решения через AWS
), так и локально в составе одного единственного бинарника,
который можно легко запустить из CLI.
Но сейчас будет заметка о проблемной части - а именно потенциальных потерях данных при вставке.
По природе OLAP баз данных они обычно не предоставляют механизма транзакций - это значит что если бы производим, например, серию различных вставок используя данные из разных таблиц, консистентность данных строго говоря никак не гарантирована. Например:
- Имеем таблицу A и B
- Производим вставку в таблицу A новых данных.
- Сразу же после окончания
INSERT
а производим вставку в B данных, которая производится с JOIN операцией с данными:
INSERT INTO
db.B
SELECT
*
FROM
db.some_source t
INNER JOIN
db.A ON t.field = db.A.field
После этих действий можно с удивлением обраружить, что некотрой части данных в B не хватает. Или хватает - предсказать довольно сложно.
Приходилось обращаться в поддержку Clickhouse
с вопросом, почему такое может происходить, и 100% точного ответа получено не было,
но предположительно источниками проблемы могу быть:
async_insert
: настройка вClickhouse
которая позволяет ему накапливать данные в буфере перед вставкой (бд проще вставлять данные партиями, поскольку она создаёт отдельный файл для этой партии перед мерджем). На момент обращения к следующей таблице данные всё еще могут оставаться в этом буфере.deduplication
механизм который позволяет Кликхаусу улавливать дублирующиеся блоки данных и удалять их. По-видимому это несовершенная система, поскольу иногда удаляются данные которые на самом деле не являются дублями.Clickhouse
решает это на основе первичного ключа таблицы и в зависимости от её движка. Происходит это или нет можно узнать из системной таблицыsystem.query_log
(колонкаProfileEvents
должна содержать информацию оDuplicatedInsertedBlocks
).
На самом деле 2 настройки, которые мы добавили к проблемным запросом на текущий момент почти решили наши проблемы с вставкой данных (на самом деле мы ещё включили небольшой делей при серийной вставке данных).
-- Тело запроса
SETTINGS
insert_deduplicate = 0,
wait_for_async_insert = 1
Мне не приходилось наблюдать такой же проблемы с использованием MATERIALIZED VIEW
, которые в Clickhouse
позволяют делать автоматическую вставку на постоянной основе - но зачастую нам хочется контроля за ситуацией.
С MATERIALIZED VIEW
если её по какой-то причине нельзя обновить (например, дропнулась таблица с которой был JOIN
),
она блокирует вставку в изначальный источник данных, а это, мягко говоря, неприятно (представьте терять получаемые в реальном времени сотни тысяч сторок данных).
В любом случае, надеюсь если кто-то ещё столкнётся с похожей проблемой, эта инфомация поможет её решить.