DEV Community

Cover image for TCP Exponential Backoff: Why Your Retries are Doubling
Doogal Simpson
Doogal Simpson

Posted on • Originally published at doogal.dev

TCP Exponential Backoff: Why Your Retries are Doubling

TCP prevents network meltdowns by doubling its wait time (Exponential Backoff) every time a packet fails to acknowledge. Instead of spamming a congested link, I look at how the protocol calculates a dynamic Retransmission Timeout (RTO) and then backs off to allow hardware buffers to clear and avoid total congestion collapse.

I find it wild that we can just download a file from a physical computer on another continent through a chaotic web of underwater cables and intermediary servers. When I think about TCP, I'm looking at the protocol responsible for taking that file, chopping it into chunks, and ensuring it arrives mostly reliably despite the physical insanity of the global internet infrastructure. The genius isn't just in the delivery, but in how the protocol knows when to stop talking so the network doesn't cave in on itself.

How does TCP handle packet loss?

I see TCP ensuring reliability by requiring a specific acknowledgment (ACK) for every data segment sent. If the sender transmits a chunk and doesn't receive an ACK within a set window, it assumes the packet was lost and initiates a retransmission.

I usually think of this like a microservice health check or a database heartbeat. If I send a request and don't get a response, I have to decide when that request has officially failed. If I retry after a single millisecond, I'm going to overwhelm a service that might just be slightly lagged. If I wait five seconds, I'm killing my application's throughput. I need TCP to find that precise "wait" window for every unique connection to keep the data moving as fast as possible without causing a bottleneck.

What determines the Retransmission Timeout (RTO)?

The RTO is a dynamic timer that I use to judge when a packet is officially "lost" based on previous Round Trip Time (RTT) measurements. It isn't a static value because the latency I see to a server in London is vastly different from the latency to a server in my own rack.

If my previous packets have been successfully acknowledged in 500ms, my TCP stack might set an RTO of 700ms to provide a buffer for minor jitter. But once that 700ms timer expires without an ACK, the logic has to change. If I just kept hitting the network at 700ms intervals during a failure, I'd be making a bad situation worse. This is why I rely on exponential backoff to handle the silence.

Why does TCP use exponential backoff?

I use exponential backoff to prevent "congestion collapse," a state where a network is so saturated with retransmissions that no actual work can get through. By doubling the RTO after every failure, I'm effectively using a circuit breaker to reduce the load on the network until the bottleneck clears.

To understand why I need this, we have to look at the hardware buffers. Every router between my machine and the destination has a finite amount of memory to queue incoming packets. When network traffic spikes and those buffers reach capacity, the router performs a "tail drop"โ€”it simply discards any new incoming packets because there is nowhere to put them.

If every device on that segment responded to a drop by immediately resending data at high frequency, they would create a broadcast storm. The buffers would stay at 100% utilization, and the router would spend all its resources dropping packets rather than routing them. By exponentially increasing the wait time, I'm giving those hardware buffers the space they need to drain and recover. It's about being a good neighbor to the rest of the traffic on the wire.

How does backoff scale across retries?

With every consecutive failure to receive an ACK, I double the previous RTO. This binary exponential backoff continues until I hit a maximum threshold or the operating system finally decides the connection is dead and kills the socket.

Retry Count Backoff Multiplier Example RTO (ms)
Initial Transmission 1x 700
1 2x 1,400
2 4x 2,800
3 8x 5,600
4 16x 11,200
5 32x 22,400

Eventually, the network does time out. There's a limit to how long I'll wait, but this aggressive backing off is what keeps a local network failure from cascading into a total blackout for every other user on that same infrastructure. Itโ€™s the difference between a minor lag and a total network shutdown.

FAQ

What is the difference between RTT and RTO?

RTT (Round Trip Time) is the actual measured time it takes for a packet to travel to the destination and back. RTO (Retransmission Timeout) is the calculated duration the sender will wait for an acknowledgment before assuming the packet was lost, typically derived from RTT plus a variance buffer.

Why not just use a fixed retry interval?

Fixed intervals lead to congestion collapse. If thousands of devices all retry at the same static interval, they can synchronize their retransmissions, creating massive spikes in traffic that keep router buffers full and prevent the network from ever recovering.

Can I tune the maximum number of TCP retries?

In Linux, I can tune this via sysctl using the net.ipv4.tcp_retries2 parameter. This setting dictates how many times the kernel will retry before giving up on an established connection. While I can lower this to fail faster, increasing it too much can lead to stale sockets hanging around for over half an hour on a dead link.

Top comments (0)