Back to work
Resume Let's talk
Case study · Numerator

Near real-time
CDC search sync

Overnight full reindexes meant search could be up to a day stale. I replaced them with a change-data-capture pipeline that streams MySQL writes into Elasticsearch in under a minute — continuously, idempotently, and safe to replay.

Role Backend engineer
Context Billion-row search platform
Stack Debezium · Kafka · Elasticsearch · Python

The problem

Search was only as fresh as last night's batch job.

The product served search over a very large MySQL store, and the index was rebuilt by an overnight full reindex. That meant a price change, a new product or a corrected attribute could take hours — sometimes most of a day — to show up in results. The reindex was also expensive: it hammered the database, took a long window to run, and an intraday correction meant either waiting or triggering another costly rebuild.

What the platform actually needed was continuous sync: when a row changes in MySQL, that change should be reflected in search seconds later, without reprocessing everything else.

The approach

I moved from batch to a streaming change-data-capture pipeline. Instead of polling or dumping tables, the pipeline reads the database's binary log, turns each committed change into an event, and applies it to Elasticsearch.

Architecture

MySQL source DB Debezium binlog connector Kafka topic per table Consumers idempotent · retries · DLQ Elasticsearch search index Backfill replayable job binlog events consume idempotent upsert replay / backfill

Committed row changes flow from binlog to search in seconds; the log makes backfills a replay, not a rebuild.

Key decisions

Capture the log, don't poll the tables

Reading the binlog with Debezium gives an ordered, low-overhead stream of exactly what changed, in commit order. Polling would have added query load and still missed deletes and rapid successive updates.

Make writes idempotent

Every consumer upserts by document id, so redelivery — which will happen with at-least-once messaging — converges to the same result. That single property is what makes retries, restarts and backfills safe instead of scary.

Treat the log as the recovery tool

Because Kafka retains the change stream, rebuilding part of the index becomes a replay from an offset rather than another full, database-crushing reindex.

Outcome

<60s MySQL → search sync, down from an overnight batch
Continuous streaming sync replaced scheduled full reindexes
Replayable idempotent upserts make retries & backfills safe

Stack

DebeziumKafkaElasticsearchMySQLPythonCelery

More context on the search platform is on my resume.

Download resume Back to all work