Definition · Cross-shard transactionA transaction is local when every key it touches lives on one shard, and cross-shard otherwise. A local transaction commits with the store's ordinary single-node path. A cross-shard one needs an atomic commitment protocol across the participants, and two-phase commit is the standard one: a prepare round in which every participant durably votes, then a commit round.
Theorem · The local fractionIf k keys are hashed independently and uniformly over N shards, the probability that all of them land on the same shard is N¹⁻ᵏ.
Condition on the shard of the first key, whatever it is. Each of the remaining k − 1 keys is independently uniform over the N shards, so each lands on that same shard with probability 1/N.
By independence the probability that all k − 1 of them do is (1/N)ᵏ⁻¹ = N¹⁻ᵏ, and this does not depend on which shard the first key chose, so it is the unconditional probability as well.
At k = 1 this gives N⁰ = 1, which is the right answer: a single-key transaction is always local.
□
P(all k on one shard) = N¹⁻ᵏ
N k = 2, local crosses shards touched added latency
2 1/2 50.00% 50.00% 1.500 2.500 ms
4 1/4 25.00% 75.00% 1.750 3.750 ms
8 1/8 12.50% 87.50% 1.875 4.375 ms
16 1/16 6.25% 93.75% 1.938 4.688 ms
32 1/32 3.13% 96.88% 1.969 4.844 ms
64 1/64 1.56% 98.44% 1.984 4.922 ms
and in k, at N = 16
k = 2 1/16 = 6.2500% k = 3 1/256 = 0.3906%
k = 4 1/4096 = 0.0244%
The first table's second column barely changes after the first few rows — 93.75% at sixteen shards and 98.44% at sixty-four — which is what “collapses in k, not in N” looks like from the other side. Once N is past a handful, essentially every multi-key transaction crosses, and the remaining question is only what crossing costs.
The expected number of shards a transaction touches is a different count and a useful one: it is N(1 − (1 − 1/N)ᵏ), which at k = 2 and N = 16 is 1.938. That is the number of participants the commit protocol coordinates, and it stays close to k for any N much larger than k. A two-key transaction on a large fleet is a two-participant commit almost always, which is why the protocol's cost does not grow with the fleet.
What two-phase commit adds
round trip between shards = 2.00 ms an fsync = 0.50 ms
prepare 1 round trip + 1 fsync at each participant
commit 1 round trip + 1 fsync at each participant
round trips 2 × 2.00 = 4.00 ms
fsyncs 2 × 0.50 = 1.00 ms
total 5.00 ms per crossing transaction
mean over ALL transactions at k = 2, N = 16
0.9375 × 5.00 = 4.688 ms
Two numbers, two purposes. 5.00 ms is what a crossing transaction pays and it belongs in a tail budget, because at 93.75% crossing the p99 transaction certainly crosses. 4.688 ms is the mean over all transactions and belongs in a throughput calculation. Quoting the mean where the tail is wanted understates the p99 by the 6.25% of transactions that got off free.
Example · Why the fsyncs are worth itemising separatelyThe round-trip term scales with distance and the fsync term does not. Move the participants into one rack and the 4.00 ms may fall by an order of magnitude while the 1.00 ms of durable votes stays exactly where it is; move them across regions and the round trips dominate everything. Itemising the two means the same model answers both questions, and “The Speed-of-Light Floor” gives the round trip a lower bound that no amount of engineering moves.
The designs that avoid the question
Every practical answer is a way of making k = 1 rather than a way of making two-phase commit cheap. Partition by the entity the transaction is about — orders by customer, posts by author — so that a transaction touching several rows touches one shard. Or deliberately co-locate related keys by giving them a shared partition key prefix, which is the same idea stated as a schema choice. Both are decisions about the partitioning function, and both are much harder to make after the data is placed.
Where the transaction genuinely spans entities, the remaining levers are to weaken what is being asked for — an eventually-consistent compensating action instead of an atomic commit — or to accept the 5.00 ms and make sure it is in the budget. What is not a lever is the shard count: N¹⁻ᵏ is already near zero at any N worth having, and the protocol's cost does not depend on N at all.