Crates.io | congestion-limiter |
lib.rs | congestion-limiter |
version | 0.1.0 |
source | src |
created_at | 2024-10-22 15:18:07.577376 |
updated_at | 2024-10-22 15:18:07.577376 |
description | Dynamic congestion-based concurrency limits for controlling backpressure |
homepage | https://github.com/ThomWright/congestion-limiter |
repository | https://github.com/ThomWright/congestion-limiter |
max_upload_size | |
id | 1418784 |
size | 192,047 |
Dynamic congestion-based concurrency limits for controlling backpressure.
A Rust library to dynamically control concurrency limits. Several algorithms are included, mostly based on TCP congestion control. These detect signs of congestion or overload by observing and reacting to either latency (delay) or load-based failures (loss), respectively. Beyond the limit, additional requests to perform work can be rejected. These rejections can be detected by upstream limiters as load-based failures, acting as an effective form of backpressure.
In general, systems serving clients by doing jobs have a finite number of resources. For example, an HTTP server might have 4 CPU cores available. When these resources become heavily utilised, queues begin to form, and job latency increases. If these queues continue to grow, the system becomes effectively overloaded and unable to respond to job requests in a reasonable time.
These systems can only process so many jobs concurrently. For a purely CPU-bound job, the server above might only be able to process about 4 jobs concurrently. Reality is much more complex, however, and therefore this number is much harder to predict.
Concurrency limits can help protect a system from becoming overloaded, and these limits can be automatically set by observing and responding to the behaviour of the system.
See background for more details.
This library aims to:
The congestion-based algorithms come in several flavours:
Algorithm | Feedback | Response | Fairness |
---|---|---|---|
AIMD | Loss | AIMD | Fair, but can out-compete delay-based algorithms |
Gradient | Delay | AIMD | TODO: ? |
Vegas | Loss and delay | AIAD (AIMD for loss) | Proportional until overload (loss) |
The example below shows two applications using limiters on the client (output) and on the server (input), using different algorithms for each.
Does this require coordination between multiple processes?
No! The congestion avoidance is based on TCP congestion control algorithms which are designed to work independently. In TCP, each transmitting socket independently detects congestion and reacts accordingly.
TODO:
use std::sync::Arc;
use congestion_limiter::{limits::Aimd, limiter::{DefaultLimiter, Limiter, Outcome}};
// A limiter shared between request handler invocations.
// This controls the concurrency of incoming requests.
let limiter = Arc::new(DefaultLimiter::new(
Aimd::new_with_initial_limit(10)
.with_max_limit(20)
.decrease_factor(0.9)
.increase_by(1),
));
// A request handler
tokio_test::block_on(async move {
// On request start
let token = limiter.try_acquire()
.await
.expect("Do some proper error handling instead of this...");
// Do some work...
// On request finish
limiter.release(token, Some(Outcome::Success)).await;
});
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.