When one player on a slow connection has a full send buffer and the server sends in blocking mode (a send call that doesn’t return until the buffer has room), the server thread waits on that one player.
Why A slow client’s send buffer is full → Effect With blocking sends, the server thread waits until the buffer has room → On screen Everyone that thread handles gets a freeze or slow motion
Use non-blocking sends, cap the send queue per client, drop stale updates.
On the graph
Random spikes · Server tick time, Send-Q per connection
Where to look
Connections whose Send-Q (bytes not yet ACKed or not yet sent) has filled up to the send buffer size, found with ss -tn; in a thread dump (stacks) of the game server taken when ticks spike, any thread stuck in a send call
Confirmed if
While a slow connection has a full Send-Q, the thread handling it is stuck in send, and only the players on that same thread stall with it
Ruled out if
Stalled threads waiting outside send (locks, DB calls): “Lock contention,” “Blocking calls on the game thread”
Check with
Infra tools (no game code needed)
Sources
send(2) — Linux manual pageLinux man-pages send() blocks when the send buffer has no room, and returns immediately with EAGAIN in non-blocking mode
send function (winsock2.h)Microsoft Winsock send also blocks when buffer space runs out, unless the socket is in non-blocking mode
net/ipv4/tcp_diag.c (Linux v6.12)Linux kernel Recv-Q and Send-Q in ss: for a listening socket, connections waiting for accept and the backlog limit; for a connected socket, bytes the app hasn’t read yet and sent bytes not yet ACKed