Skip to content
About
Main content

Ordering and transactional grouping

Why does a source transaction not survive key-partitioned transport, and what are the escapes?

A transaction is atomic at the source. A transfer debits one account and credits another, and no state exists in between. The log preserves this: records are grouped by transaction and ordered by .

Transport does not preserve it. To get parallelism, you partition the stream by primary key. Then the two rows of the transfer (account A and account B) have different keys and land in different . They arrive in either order and commit to the sink independently.

So This is not a bug in any implementation. It is the ordering-versus-parallelism trade-off resolved in favor of parallelism, and the intermediate states are the bill.

The escapes

  1. Partition by transaction instead of key. Everything in one transaction stays together and ordered. But this serializes work per transaction and usually collapses throughput, and different transactions touching the same key can then land in different partitions and lose key order.
  2. Buffer per transaction at the sink and commit atomically. This costs latency proportional to the largest transaction, and unbounded memory for the pathological one (a bulk update of 50 million rows is one transaction).
  3. Accept the intermediate states and require downstream consumers to be eventually convergent (they become correct after all parts arrive).

The third is what nearly everyone chooses. That is why cross-row invariants are almost never preserved through , and why "the replica showed a transfer with money missing" is a recurring incident report and not an anomaly.

In one line: key-level order is cheap and transaction-level atomicity is not; CDC ships the first and quietly drops the second.