Implementing Adaptive Backpressure in Rust with FlowGuard
Hey fellow Rustaceans! π
I recently open-sourced FlowGuard, a library for adaptive concurrency control and backpressure in Rust services. In this post, I'll share why static rate limiting fails and how FlowGuard solves it with TCP Vegas congestion control.
π€ The Problem with Static Limits
We've all done this:
rust
// "Maximum 100 concurrent connections"
let max_connections = 100;
But static limits are a trap:
Set too high? Your system crashes before reaching the limit
Set too low? You waste resources and refuse legitimate traffic
Guessing game? You're always tuning based on hunches
π The Solution: Dynamic Backpressure
Instead of guessing, what if your system could self-adjust based on real-time performance? That's where FlowGuard comes in.
Introducing FlowGuard
FlowGuard implements the TCP Vegas congestion control algorithm to dynamically adjust concurrency limits based on actual system latency.
π― How It Works
rust
use flow_guard::{FlowGuard, VegasStrategy};
use std::sync::Arc;
[tokio::main]
async fn main() {
// Start with 10 concurrent operations
let strategy = Arc::new(VegasStrategy::new(10));
let guard = FlowGuard::new(Arc::clone(&strategy));
println!("Initial limit: {}", guard.current_limit());
// Execute tasks with adaptive backpressure
let result = guard.run(async {
// Your database query, API call, etc.
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
Ok::<_, &str>("Success!")
}).await;
println!("Final limit: {}", guard.current_limit()); // Adjusted!
}
β¨ Key Features
- Real-time Adjustment rust // Watch limits adjust dynamically println!("Current limit: {}", guard.current_limit()); println!("Available permits: {}", guard.available_permits());
- Vegas Algorithm Based on the difference between expected and actual throughput:
β Increases limit when system has spare capacity
β Decreases limit when latency indicates congestion
β Self-tuning - no manual configuration needed
- Web Framework Integration rust // Axum 0.8 middleware let strategy = VegasStrategy::new(50); let flow_layer = FlowGuardLayer::new(strategy);
let app = Router::new()
.route("/api/data", get(handler))
.layer(flow_layer);
π¦ Getting Started
Add to your Cargo.toml:
toml
[dependencies]
flow-guard = "0.2.1"
With Axum/Tower support
flow-guard = { version = "0.2.1", features = ["axum", "tower"] }
π§ Under the Hood
FlowGuard replaces tokio::sync::Semaphore with a custom DynamicSemaphore that can adjust its limit up and down in real-time:
rust
pub struct DynamicSemaphore {
max_permits: AtomicUsize,
available_permits: AtomicUsize,
notify: Notify,
}
impl DynamicSemaphore {
pub fn set_limit(&self, new_limit: usize) {
// Adjusts permits dynamically based on Vegas calculations
}
}
π― Use Cases
- Database Protection rust // Prevent database overload let db_guard = FlowGuard::new(VegasStrategy::new(20));
async fn query_database() -> Result {
db_guard.run(|| async {
// Your database query here
database.query("SELECT * FROM users").await
}).await``
}
- API Rate Limiting rust // Adaptive rate limiting for external APIs let api_guard = FlowGuard::new(VegasStrategy::new(5));
async fn call_external_api() -> Result {
api_guard.run(|| async {
client.get("https://api.example.com/data").await
}).await
}
- Microservices rust // Protect services from cascading failures let service_guard = FlowGuard::new(VegasStrategy::new(100)); π Benchmarks In testing, FlowGuard showed:
5 β 12 limit adjustment under optimal conditions
Sub-millisecond overhead per request
Zero allocation in hot path
Thread-safe with atomic operations
π Try It Yourself
bash
Clone and run examples
git clone https://github.com/cleitonaugusto/flow-guard
cd flow-guard
cargo run --example basic_usage
π Resources
GitHub: https://github.com/cleitonaugusto/flow-guard
Crates.io: https://crates.io/crates/flow-guard
Documentation: https://docs.rs/flow-guard/0.2.1/
Examples: basic_usage.rs, server_demo.rs
π Why I Built This
After seeing too many services crash from static limits or waste resources with conservative settings, I wanted a solution that adapts to actual system performance. The TCP Vegas algorithm has been battle-tested for decades in networking - why not apply it to service concurrency?
π€ Contributing & Feedback
FlowGuard is open source under MIT license. I'd love your:
Feedback on the API design
Use cases from your projects
Contributions to the codebase
Ideas for improvements
What adaptive concurrency patterns have you used in your Rust projects? Share in the comments!
Top comments (0)