What "the Same Session" Means When the Transport Is Replaceable
Learn how stable session identity, monotonically increasing epochs, and fencing prevent stale connections and callbacks from corrupting recovered sessions.
The term "session" becomes significant when discussing the replaceability of transport in a system. Two interpretations of what constitutes a session recovery arise from this situation. Either the original transport remains operational after an interruption, or a new transport takes its place. The observable outcome, whether the system remains connected, healthy, and serving, remains unchanged, irrespective of the underlying cause.
However, the methods employed to reach this end state differ significantly. In contemporary designs, connections tend to be disposable. This necessitates a different approach to handling connections, treating them as "inventory" to facilitate swift recovery. Nevertheless, this approach introduces a gap: if the session's carrier can be swapped at any moment, the session cannot simply be the connection.
Instead, something must define what the session is. This answer is both unassuming and foundational. A session comprises a name, a monotonically increasing counter, and a rule governing its verification. Explicitly stating these components enables effective recovery telemetry and protection against a specific type of corruption.
The corruption occurs when work initiated by a non-existent transport is inadvertently processed by its replacement. Conversely, omitting these elements results in a convention rather than a guarantee, which is the more prevalent scenario. The address is not the session's identity. TCP identifies a connection using endpoint addresses.
This approach explains why a laptop switching from Wi-Fi to cellular service causes existing connections to drop: the addresses changed, rendering the connection no longer the same. The assignment of addresses based on the transport's current conditions is why moving a laptop from one network to another results in a different connection.
QUIC addresses this issue by incorporating connection IDs, which ensure that alterations in addressing at lower protocol layers (UDP, IP) do not result in packets intended for a QUIC connection being delivered to the wrong endpoint. Section 9 of RFC 9000 elaborates on the significance of this: QUIC connections are not strictly bound to a single network path.
Connection migration uses connection identifiers to enable connections to transfer to a new network path. This allows connections to continue functioning even when changes in network topology or address mappings occur, such as those caused by NAT rebinding. The critical takeaway is that the transport carrying the session should not be the entity that assigns it a name.
Kafka addresses this by introducing the "transactional.id" concept, a name assigned by the operator that persists beyond a single producer process. Similarly, server-sent events utilize the "Last-Event-ID" header, allowing reconnecting EventSource instances to resume a stream instead of starting anew. The underlying principle remains consistent across different layers.
The transport carrying the session should not be the entity responsible for naming it. Kafka implements this by assigning a transactional.id, a name that endures beyond any single producer process. Server-sent events adopt a similar approach by using the "Last-Event-ID" header, enabling reconnecting EventSource instances to resume a stream without restarting it.
These various layers illustrate the same fundamental concept: the identity of a session should be distinct from the transport carrying it. A stable name is essential but not sufficient. When a session can be carried by multiple transports, it is crucial to differentiate between these carriers, as the previous carrier may still be active and engaged in operations initiated before it was replaced.
TCP has contemplated this issue for a longer period. RFC 9293 introduces the concept of "incarnations" of a connection and raises the question of how TCP implementations can identify segments originating from previous incarnations of a connection. The solutions involve the initial sequence number generator and the prolonged TIME-WAIT state, each serving the purpose of ensuring that data transmitted by a deceased incarnation is not accepted by its successor.
At higher levels, the same principle manifests as an explicit counter. In Kafka producer initialization, the transaction coordinator increments the epoch for the producer ID associated with a transactional.id. KIP-98 describes this mechanism as "fencing," which prevents any prior zombie instances of the producer from progressing with their transactions.
In the case of Kafka 2.7 and later versions, this is referred to as "INVALID_PRODUCER_EPOCH," signifying that a producer attempted to produce data using an obsolete epoch. Kafka consumer generation employs a similar approach. Each rebalance increments a generation ID, and a member that heartbeats or commits offsets against a stale one will encounter an "ILLEGAL_GENERATION" error.
Raft terms serve a similar purpose, acting as a logical clock to detect stale information, such as a leader. Figure 2 in the Raft paper succinctly summarizes two mechanical rules: if an RPC request or response carries a term greater than the currentTerm, adopt it and transition to a follower state. Furthermore, in both RPC receiver implementations, there is a rule to reply with a false value if the term is less than or equal to the currentTerm.
Connection pool generation in MongoDB introduces a generation number for each pool and stamps every connection with the applicable generation when it is created. Clearing the pool does not involve walking the connection list; instead, it increments the generation, effectively marking existing connections as stale. A connection whose generation does not match the pool's is closed during its subsequent check-in or check-out. This mechanism ensures that connections utilizing an outdated generation are invalidated.
Written by urgent.news from HackerNoon's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.