MySQL → ClickHouse change-data-capture pipeline
Streaming row changes out of a transactional MySQL cluster into a columnar store so analytics stops competing with production traffic.
Reporting queries ran against the same MySQL primary that served the application. As the dataset grew, a single analyst refreshing a dashboard could add noticeable latency to ordinary writes. The goal was to move analytical reads off the transactional database without introducing a nightly batch window.
The pipeline reads the MySQL binary log with Debezium, publishes change events to Kafka, and materialises them in ClickHouse. Deletes and updates are handled with a ReplacingMergeTree keyed on the primary key plus a monotonic version column, so the analytics tables converge on the same state as the source without requiring in-place mutations.
The interesting part was not the happy path but the operational envelope: schema changes, snapshot restarts, replication lag alerting, and deciding what "eventually consistent" is allowed to mean for each dashboard.
Illustrative figures — example environment, not measured production results
- Change events / day
- ~5M
- End-to-end lag target
- < 30s
- Analytics tables
- 20+
- MySQL
- Debezium
- Kafka
- ClickHouse
- Docker
- Prometheus