Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 52 additions & 50 deletions streamer/src/nonblocking/stream_throttle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,13 +252,13 @@ pub mod test {
DEFAULT_MAX_UNSTAKED_CONNECTIONS,
DEFAULT_MAX_STREAMS_PER_MS,
));
// 25K packets per ms * 20% / 500 max unstaked connections
// 50K packets per ms * 20% / 500 max unstaked connections
assert_eq!(
load_ema.available_load_capacity_in_throttling_duration(
ConnectionPeerType::Unstaked,
10000,
),
10
20
);
}

Expand All @@ -272,73 +272,73 @@ pub mod test {

// EMA load is used for staked connections to calculate max number of allowed streams.
// EMA window = 5ms interval * 10 intervals = 50ms
// max streams per window = 250K streams/sec * 80% = 200K/sec = 10K per 50ms
// max_streams in 50ms = ((10K * 10K) / ema_load) * stake / total_stake
// max streams per window = 500K streams/sec * 80% = 400K/sec = 20K per 50ms
// max_streams in 50ms = ((20K * 20K) / ema_load) * stake / total_stake
//
// Stream throttling window is 100ms. So it'll double the amount of max streams.
// max_streams in 100ms (throttling window) = 2 * ((10K * 10K) / ema_load) * stake / total_stake
// max_streams in 100ms (throttling window) = 2 * ((20K * 20K) / ema_load) * stake / total_stake

load_ema.current_load_ema.store(10000, Ordering::Relaxed);
// ema_load = 10K, stake = 15, total_stake = 10K
// max_streams in 100ms (throttling window) = 2 * ((10K * 10K) / 10K) * 15 / 10K = 30
load_ema.current_load_ema.store(20000, Ordering::Relaxed);
// ema_load = 20K, stake = 15, total_stake = 10K
// max_streams in 100ms (throttling window) = 2 * ((20K * 20K) / 20K) * 15 / 10K = 60
assert_eq!(
load_ema.available_load_capacity_in_throttling_duration(
ConnectionPeerType::Staked(15),
10000,
),
30
60
);

// ema_load = 10K, stake = 1K, total_stake = 10K
// max_streams in 100ms (throttling window) = 2 * ((10K * 10K) / 10K) * 1K / 10K = 2K
// ema_load = 20K, stake = 1K, total_stake = 10K
// max_streams in 100ms (throttling window) = 2 * ((20K * 20K) / 20K) * 1K / 10K = 4K
assert_eq!(
load_ema.available_load_capacity_in_throttling_duration(
ConnectionPeerType::Staked(1000),
10000,
),
2000
4000
);

load_ema.current_load_ema.store(2500, Ordering::Relaxed);
// ema_load = 2.5K, stake = 15, total_stake = 10K
// max_streams in 100ms (throttling window) = 2 * ((10K * 10K) / 2.5K) * 15 / 10K = 120
load_ema.current_load_ema.store(5000, Ordering::Relaxed);
// ema_load = 5K, stake = 15, total_stake = 10K
// max_streams in 100ms (throttling window) = 2 * ((20K * 20K) / 5K) * 15 / 10K = 240
assert_eq!(
load_ema.available_load_capacity_in_throttling_duration(
ConnectionPeerType::Staked(15),
10000,
),
120
240
);

// ema_load = 2.5K, stake = 1K, total_stake = 10K
// max_streams in 100ms (throttling window) = 2 * ((10K * 10K) / 2.5K) * 1K / 10K = 8000
// ema_load = 5K, stake = 1K, total_stake = 10K
// max_streams in 100ms (throttling window) = 2 * ((20K * 20K) / 5K) * 1K / 10K = 16000
assert_eq!(
load_ema.available_load_capacity_in_throttling_duration(
ConnectionPeerType::Staked(1000),
10000,
),
8000
16000
);

// At 2000, the load is less than 25% of max_load (10K).
// Test that we cap it to 25%, yielding the same result as if load was 2500.
load_ema.current_load_ema.store(2000, Ordering::Relaxed);
// function = ((10K * 10K) / 25% of 10K) * stake / total_stake
// At 4000, the load is less than 25% of max_load (20K).
// Test that we cap it to 25%, yielding the same result as if load was 5000.
load_ema.current_load_ema.store(4000, Ordering::Relaxed);
// function = ((20K * 20K) / 25% of 20K) * stake / total_stake
assert_eq!(
load_ema.available_load_capacity_in_throttling_duration(
ConnectionPeerType::Staked(15),
10000,
),
120
240
);

// function = ((10K * 10K) / 25% of 10K) * stake / total_stake
// function = ((20K * 20K) / 25% of 20K) * stake / total_stake
assert_eq!(
load_ema.available_load_capacity_in_throttling_duration(
ConnectionPeerType::Staked(1000),
10000,
),
8000
16000
);

// At 1/40000 stake weight, and minimum load, it should still allow
Expand All @@ -364,69 +364,71 @@ pub mod test {

// EMA load is used for staked connections to calculate max number of allowed streams.
// EMA window = 5ms interval * 10 intervals = 50ms
// max streams per window = 250K streams/sec = 12.5K per 50ms
// max_streams in 50ms = ((12.5K * 12.5K) / ema_load) * stake / total_stake
// max streams per window = 500K streams/sec = 25K per 50ms
// max_streams in 50ms = ((25K * 25K) / ema_load) * stake / total_stake
//
// Stream throttling window is 100ms. So it'll double the amount of max streams.
// max_streams in 100ms (throttling window) = 2 * ((12.5K * 12.5K) / ema_load) * stake / total_stake
// max_streams in 100ms (throttling window) = 2 * ((25K * 25K) / ema_load) * stake / total_stake

load_ema.current_load_ema.store(10000, Ordering::Relaxed);
// ema_load = 10K, stake = 15, total_stake = 10K
// max_streams in 100ms (throttling window) = 2 * ((12.5K * 12.5K) / 10K) * 15 / 10K = 46.875
load_ema.current_load_ema.store(20000, Ordering::Relaxed);
// ema_load = 20K, stake = 15, total_stake = 10K
// max_streams in 100ms (throttling window) = 2 * ((25K * 25K) / 20K) * 15 / 10K = 93.75
// Loss of precision occurs here because max streams is computed for 50ms window and then doubled.
assert!(
(46u64..=47).contains(&load_ema.available_load_capacity_in_throttling_duration(
(92u64..=94).contains(&load_ema.available_load_capacity_in_throttling_duration(
ConnectionPeerType::Staked(15),
10000
))
);

// ema_load = 10K, stake = 1K, total_stake = 10K
// max_streams in 100ms (throttling window) = 2 * ((12.5K * 12.5K) / 10K) * 1K / 10K = 3125
assert!((3124u64..=3125).contains(
// ema_load = 20K, stake = 1K, total_stake = 10K
// max_streams in 100ms (throttling window) = 2 * ((25K * 25K) / 20K) * 1K / 10K = 6250
assert!((6249u64..=6250).contains(
&load_ema.available_load_capacity_in_throttling_duration(
ConnectionPeerType::Staked(1000),
10000
)
));

load_ema.current_load_ema.store(5000, Ordering::Relaxed);
// ema_load = 5K, stake = 15, total_stake = 10K
// max_streams in 100ms (throttling window) = 2 * ((12.5K * 12.5K) / 5K) * 15 / 10K = 93.75
load_ema.current_load_ema.store(10000, Ordering::Relaxed);
// ema_load = 10K, stake = 15, total_stake = 10K
// max_streams in 100ms (throttling window) = 2 * ((25K * 25K) / 10K) * 15 / 10K = 187.5
// Loss of precision occurs here because max streams is computed for 50ms window and then doubled.
assert!(
(92u64..=94).contains(&load_ema.available_load_capacity_in_throttling_duration(
(186u64..=188).contains(&load_ema.available_load_capacity_in_throttling_duration(
ConnectionPeerType::Staked(15),
10000
))
);

// ema_load = 5K, stake = 1K, total_stake = 10K
// max_streams in 100ms (throttling window) = 2 * ((12.5K * 12.5K) / 5K) * 1K / 10K = 6250
assert!((6248u64..=6250).contains(
// ema_load = 10K, stake = 1K, total_stake = 10K
// max_streams in 100ms (throttling window) = 2 * ((25K * 25K) / 10K) * 1K / 10K = 12500
assert!((12499u64..=12500).contains(
&load_ema.available_load_capacity_in_throttling_duration(
ConnectionPeerType::Staked(1000),
10000
)
));

// At 2000, the load is less than 25% of max_load (12.5K).
// Test that we cap it to 25%, yielding the same result as if load was 12.5K/4.
load_ema.current_load_ema.store(2000, Ordering::Relaxed);
// function = ((10K * 10K) / 25% of 12.5K) * stake / total_stake
// At 4000, the load is less than 25% of max_load (25K).
// Test that we cap it to 25%, yielding the same result as if load was 25K/4.
load_ema.current_load_ema.store(4000, Ordering::Relaxed);
// function = ((20K * 20K) / 25% of 25K) * stake / total_stake
assert_eq!(
load_ema.available_load_capacity_in_throttling_duration(
ConnectionPeerType::Staked(15),
10000
),
150
300
);

// function = ((12.5K * 12.5K) / 25% of 12.5K) * stake / total_stake
// function = ((25K * 25K) / 25% of 25K) * stake / total_stake
assert_eq!(
load_ema.available_load_capacity_in_throttling_duration(
ConnectionPeerType::Staked(1000),
10000
),
10000
20000
);

// At 1/400000 stake weight, and minimum load, it should still allow
Expand Down
4 changes: 2 additions & 2 deletions streamer/src/quic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ pub const MAX_UNSTAKED_CONNECTIONS: usize = 500;

pub const DEFAULT_MAX_UNSTAKED_CONNECTIONS: usize = 500;

/// Limit to 250K PPS
pub const DEFAULT_MAX_STREAMS_PER_MS: u64 = 250;
/// Limit to 500K PPS
pub const DEFAULT_MAX_STREAMS_PER_MS: u64 = 500;

/// The new connections per minute from a particular IP address.
/// Heuristically set to the default maximum concurrent connections
Expand Down
Loading