en

Tor Congestion Control and Flow Control for Relay Operators in 2026

Tor 0.4.7 introduced a new congestion control algorithm (Prop324) that replaced the previous XON/XOFF flow control mechanism with a more sophisticated approach inspired by modern TCP congestion control research. Understanding how congestion control works enables relay operators to configure their nodes appropriately and understand the performance and stability behaviors they observe in practice. This guide explains Tor's congestion control mechanisms and their implications for relay operation.

Need this done for your project?

We implement, you ship. Async, documented, done in days.

Start a Brief

SENDME Cells and Circuit-Level Flow Control

Tor uses SENDME cells for circuit-level flow control. When a destination relay receives a certain amount of data (one "window" worth), it sends a SENDME cell back to the source. The source must wait for SENDME acknowledgment before sending the next window. This prevents relays from being overwhelmed by fast senders before they can process and forward the data.

The congestion control improvements in Tor 0.4.7+ make the window size dynamic rather than fixed. Windows grow when the circuit shows spare capacity and shrink when delays increase, similar to how TCP's congestion window operates. This adaptive windowing allows circuits to use available bandwidth more efficiently while preventing congestion collapse when multiple circuits compete for the same relay bandwidth.

For relay operators, the visible effect of improved congestion control is more stable throughput under high load. Previous fixed-window flow control could result in relay buffer oscillation where queues would alternately build up and drain in waves. The new adaptive control produces smoother throughput curves that are easier to provision for and monitor.

KIST Scheduler and Cell Scheduling

KIST (Kernel-Informed Socket Transport) is Tor's cell scheduler that decides the order in which cells from different circuits are transmitted through a relay. The default scheduler (KIST or KISTLite depending on platform) uses kernel-level socket buffer information to minimize queuing delay while maximizing throughput.

Relay operators can configure the scheduler in torrc:

Schedulers KIST
SchedulerLowWaterMark__free_cell_fraction 0
SchedulerHighWaterMark__free_cell_fraction 0

KIST is enabled by default on Linux platforms. KISTLite is the fallback on platforms without kernel socket buffer visibility. The difference in performance between KIST and the older vanilla scheduler can be 10 to 20% in throughput at high circuit counts, making KIST enablement meaningful for high-capacity relays.

Monitor scheduler behavior by examining the relay's throughput graphs in nyx and comparing before and after scheduler changes. Scheduler effects are most visible under high load conditions when many circuits compete for relay bandwidth simultaneously.

Relay Buffer Sizing and Memory Tuning

Cell queuing in relay buffers contributes to latency under load. Larger buffers smooth throughput at the cost of higher queuing latency. Smaller buffers reduce latency but increase cell drop rates when bursts exceed instantaneous transmission capacity. The optimal buffer size depends on the relay's connection speed and typical traffic patterns.

Configure buffer sizes through the MaxMemInQueues setting:

MaxMemInQueues 2 GB

For a relay on a 1 Gbps port, 2 GB of queue memory allows approximately 2 seconds of full-port transmission rate in queue. This buffer depth is appropriate for absorbing short bursts while maintaining low latency. Smaller relays (100 Mbps ports) need proportionally smaller MaxMemInQueues values to prevent excessive latency from deep queuing. A rough guideline: MaxMemInQueues in MB = 2 * (PortSpeed in Mbps) / 8.

Monitoring Congestion Signals

Tor's new congestion control implementation adds new statistics to the control port output. Monitor these metrics to assess whether congestion control is working effectively on your relay:

Circuit throughput variance: a well-controlled relay shows relatively stable per-circuit throughput even under high total load. High variance (some circuits very fast, others very slow at the same time) indicates scheduling inefficiency or resource contention. Check in nyx by watching the circuit bandwidth distribution in the bandwidth graph during peak hours.

SENDME delays: if congestion control is working correctly, SENDME acknowledgments should arrive within a predictable time window. Very long SENDME delays (visible as circuit stalls in nyx) indicate that either your relay is overloaded or upstream/downstream relays in the circuit path are overloaded. Distinguish between these cases by checking whether the pattern appears on all circuits (your relay overloaded) or only some (specific path bottleneck).

Why Anubiz Host

100% async — no calls, no meetings
Delivered in days, not weeks
Full documentation included
Production-grade from day one
Security-first approach
Post-delivery support included

Ready to get started?

Skip the research. Tell us what you need, and we'll scope it, implement it, and hand it back — fully documented and production-ready.

Anubiz Chat AI

Online