Message Ordering
In one line: ordering is the requirement that quietly destroys throughput, and the reason so many production queues advertise "we do not guarantee order." Knowing why it is expensive is what lets you decide when to pay for it.
Best-effort ordering
In best-effort ordering, the system places messages in the queue in the order they arrive, regardless of their production sequence.
The worked example: a producer sends A, B, C, D. Network congestion delays B, so the server receives them as A, C, D, B. With best-effort ordering, the queue stores them in the order of their arrival rather than correcting the order.
Best-effort is not 'no ordering' — the distinction matters
Messages are still FIFO with respect to arrival. The queue does not shuffle anything; it simply declines to correct for network delay.
That is a meaningful guarantee in practice. For a single producer on a stable connection, arrival order usually is production order, and best-effort behaves like strict ordering almost all the time — it just does not promise to.
Which is exactly why relying on it is dangerous: the failure is rare, load-dependent, and will not appear in testing. If your correctness depends on order, "usually ordered" is the same as "unordered."
Strict ordering
Strict ordering ensures that messages are queued in the exact sequence in which they were produced.
To achieve this, the system must identify the production order, typically using a unique identifier or timestamp assigned by the producer.
Who assigns the sequence numbers?
The producer (client) is responsible. Before publishing, the producer assigns a sequence number — or another ordering identifier such as a timestamp — that reflects the order in which the messages were produced. The queue uses this information to preserve strict ordering when storing and delivering.
This has to be true, and it is worth being able to say why: only the producer knows the production order. By the time a message reaches the server, the information has already been destroyed by the network. Any ordering the server invents is ordering by arrival, which is the thing strict ordering exists to avoid.
Three approaches to ordering
| Approach | How it works | Drawbacks |
|---|---|---|
| The server assigns sequential numbers (1, 2, 3...) to messages as they arrive | Creates a bottleneck during traffic bursts. Does not account for network delays — a message produced earlier but arriving late gets a higher sequence number, violating the true production order |
| Messages are sorted by timestamps generated on the client side | Respects production time, but it is difficult to determine the correct order across multiple client sessions due to clock skew — differences in wall-clock time between machines |
| Assigns unique, sequential timestamps that reflect the global order. A unique process identifier can be tagged to the timestamp to handle concurrent requests. Allows the server to identify and wait for delayed messages | Requires clock synchronization infrastructure |
Among these options, synchronized clocks provide the most robust mechanism for generating unique, ordered IDs.
As discussed in the sequencer building block, these numbers serve as both sequence IDs and globally synchronized wall-clock timestamps.
This is unique ID generation's conclusion, arriving from a different direction
Read the three rows as the same progression that chapter made.
Approach 1 is a central counter: correct ordering of arrivals, but a single point of contention and blind to the network.
Approach 2 is local wall-clock time: no bottleneck, but clock skew between machines means two producers' timestamps are not comparable. Skew of even a few milliseconds inverts the order of messages produced close together.
Approach 3 is TrueTime's answer: bound the uncertainty so timestamps are globally comparable, and tag a process ID to break ties among genuinely concurrent events. The uniqueness comes from the process ID; the ordering comes from the synchronized clock.
Same trade-off table, different building block. If you can generate globally ordered IDs, you can order messages — which is why the sequencer is a prerequisite here.
Approach 1's flaw is worth stating out loud in an interview
"Just have the server number them as they arrive" is the first thing most candidates say, and it sounds reasonable.
It guarantees the wrong answer in exactly the case ordering exists for. Message B was produced second and arrives fourth; the server stamps it 4. The system has now not just failed to fix the reordering — it has recorded the wrong order as authoritative, and no downstream component can recover the truth.
A best-effort queue at least admits it does not know. A server-side counter launders arrival order into something that looks like production order.
Sorting
To enforce strict ordering, the server must sort messages by their timestamps before processing. The system uses an online sorting algorithm to maintain order as new messages arrive — sorting incrementally rather than in batches, since the stream never ends.
When an old message arrives late
"Suppose a message sent earlier arrives late due to a network delay. What is the proper approach?"
The simple solution is to reorder the queue. Two scenarios can arise. First, reordering puts the messages in the correct order. Second, we have already handed out newer messages to the consumers.
If an older message comes in after we have already handed out a newer one, we put it in a special queue, and the client handles that situation. The client may later decide whether to consume the message if it does not affect the intended operation, or discard it if it is not needed.
The second branch is an admission, and a good one
Once a newer message has been delivered, the ordering guarantee is already broken and cannot be repaired by the queue — you cannot un-deliver a message. So the system stops pretending: it hands the problem to the client, who has the application semantics to judge whether the late message still matters.
That is the right call, but be clear about what it means: strict ordering is best-effort under adversarial network conditions. The guarantee holds unless a message is late enough, at which point it degrades to "here it is, you decide."
Systems that need genuine total order pay for it differently — Kafka gets it by guaranteeing order only within a partition, so a single producer writing to one partition is genuinely ordered, and cross-partition order is simply not offered. Narrowing the scope of the guarantee is usually cheaper than enforcing it globally.
Key takeaway
Only the producer knows production order, so it must stamp the sequence. Server-side counters order arrivals and confidently record the wrong answer. Synchronized clocks plus a process ID are the robust option — the sequencer building block, reused. And once a newer message has shipped, a late arrival can only be handed to the client.
Interview signal by level
| Level | What a strong answer sounds like |
|---|---|
| L4 | "The queue is FIFO, so messages come out in order." |
| L5 | Separates arrival from production: "arrival order isn't production order — the network reorders. If we need strict ordering the producer has to stamp a sequence number and the server sorts on it." |
| Staff+ | Ranks the mechanisms and names the limit: "a server-side counter is worse than nothing, because it records arrival order as if it were production order. Client timestamps hit clock skew across sessions. Synchronized clocks plus a process ID is the robust option — that's the sequencer building block. And I'd scope the guarantee like Kafka does: strict within a partition, nothing across partitions, because global order is far more expensive than it's usually worth." |
Next: what strictness costs, and how to manage concurrent access.