ClickHouse 24.12: тестируем MaterializedMySQL для real-time репликации
ClickHouse 24.12 обновил движок MaterializedMySQL и добавил запись в Delta Lake. Проверяем корректность и задержку репликации из продуктивного MySQL в аналитический кластер.
ClickHouse 24.12 выходит с улучшениями движка MaterializedMySQL и поддержкой записи в Delta Lake
ClickHouse 24.12 вышел на прошлой неделе, и в release notes сразу два пункта, которые нас касаются напрямую: доработки движка MaterializedMySQL и поддержка Delta Lake writes - то есть теперь ClickHouse умеет не только читать из Delta Lake, но и писать туда. Начали с первого, потому что MaterializedMySQL у нас в активном использовании.
Зачем вообще MaterializedMySQL
Ситуация классическая: продуктивная MySQL-база, на которую сидит OLTP-приложение, и аналитический ClickHouse рядом. Данные нужны в аналитике с минимальной задержкой - в идеале минуты, не часы. ETL через ночные задачи не устраивает, CDC через Debezium + Kafka работает, но добавляет звенья в цепочке.
MaterializedMySQL - это движок базы данных в ClickHouse, который подключается к MySQL через binlog-репликацию (тот самый протокол, который использует MySQL slave) и тянет изменения в реальном времени. ClickHouse притворяется MySQL-репликой. Таблицы в MySQL превращаются в ReplacingMergeTree в ClickHouse, INSERT-ы прилетают как INSERT-ы, UPDATE и DELETE - через версионирование знакомым механизмом _version и _sign.
Подход не новый, движок есть в ClickHouse уже несколько лет, но раньше он был достаточно хрупким: терял репликацию при DDL-изменениях в MySQL, плохо переживал перезапуски, имел несколько известных кейсов с некорректной обработкой NULL-значений.
Что улучшили в 24.12
Release notes перечисляет несколько фиксов в MaterializedMySQL - не революция, но конкретные боли:
Обработка DDL на стороне MySQL. Раньше ALTER TABLE в MySQL (добавление столбца, изменение типа) мог поставить репликацию на паузу или вовсе её сломать с необходимостью пересоздавать базу с нуля. В 24.12 обработка части DDL-событий улучшена - ClickHouse теперь корректнее игнорирует несовместимые DDL или адаптирует схему. Точный список поддерживаемых операций в docs стал длиннее.
Надёжность при рестарте ClickHouse. Одна из регулярных жалоб: после рестарта сервера репликация начинала не с последней позиции в binlog, а отставала или дублировала данные. В 24.12 переработано сохранение checkpoint-а GTID-позиции.
Корректность при NULL в первичном ключе MySQL. Это был конкретный баг: таблицы с nullable-полями в части составного PK реплицировались некорректно. Починили.
Что мы проверяли
Тестовый стенд: MySQL 8.0 с продуктивной нагрузкой (несколько таблиц, суммарно несколько десятков гигабайт данных, активная запись), ClickHouse 24.12 на соседней машине. Binlog-репликация через MaterializedMySQL, режим GTID_MODE=ON на MySQL.
Корректность данных. Сравнивали COUNT(*) и SUM по нескольким ключевым полям между MySQL и ClickHouse каждые пять минут. Для этого написали простой скрипт, который параллельно делает snapshot в MySQL (через REPEATABLE READ транзакцию) и запрос в ClickHouse с FINAL (нужен для ReplacingMergeTree, чтобы дедуплицировать заменённые версии строк). Расхождений за двое суток теста не обнаружили - что само по себе результат, в 24.8 мы этот же тест не делали.
Задержка репликации. Смотрели на лаг через системную таблицу system.tables (там есть метаданные MaterializedMySQL-баз) и через system.processes во время активной записи. В спокойном режиме задержка - секунды, под нагрузкой (bulk insert 50к строк за раз) - до 20-30 секунд, пока ClickHouse переваривает пачку из binlog. Для наших задач это приемлемо.
DDL-тест. Специально добавили столбец в одну из реплицируемых таблиц MySQL через ALTER TABLE ... ADD COLUMN. В 24.8 это убивало репликацию. В 24.12 - ClickHouse добавил столбец в ClickHouse-таблицу и продолжил репликацию без остановки. Это конкретное улучшение, и оно важное.
Что не проверяли: DROP TABLE, RENAME TABLE, изменение типа существующего столбца. По документации часть этих операций по-прежнему требует пересоздания репликации.
Delta Lake writes: беглый взгляд
Вторая новинка 24.12 - поддержка записи в Delta Lake через DeltaLake движок. В 24.8 мы тестировали чтение Iceberg-таблиц, и там был ряд ограничений. Delta Lake writes - это уже другая история: ClickHouse может быть не только читателем, но и писателем в озеро.
Беглый тест с INSERT INTO delta_table SELECT ... работает. Записанные данные корректно читаются через Spark. Но глубокого тестирования в этом релизе не делали - нет конкретного заказчика, которому это нужно прямо сейчас. Фиксируем как «технически работает, надо пилотировать под конкретную задачу».
Что дальше
MaterializedMySQL в 24.12 стал заметно стабильнее по тем точкам, которые нас беспокоили. Берём его как основной кандидат для задач real-time репликации MySQL в аналитический DWH - там где CDC через Kafka избыточно сложен, а задержка в минуты устраивает бизнес.
Ограничения остаются: не все DDL-операции переживаются без пересоздания, FINAL в запросах необходим и на больших таблицах добавляет накладные расходы, мониторинг lag-а нужно строить самостоятельно - из коробки метрик мало. Но это уже рабочие инженерные задачи, не блокеры.
Следующий шаг - поднять тест на таблице с высокой частотой UPDATE (у нас есть заказчик с таблицей статусов, которая обновляется тысячи раз в минуту). ReplacingMergeTree под таким потоком мерджей - отдельная история.