Replace per-session pool trimming with pressure hysteresis

Co-Authored-By: brekotis <93345790+brekotis@users.noreply.github.com>
This commit is contained in:
Alexey
2026-07-11 21:36:01 +03:00
parent fb042f826e
commit ea296bbdc8
8 changed files with 55 additions and 3 deletions
+1
View File
@@ -899,6 +899,7 @@ async fn run_telemt_core(
);
spawn_direct_buffer_budget_controller(
direct_buffer_budget,
buffer_pool.clone(),
stats.clone(),
shared_state.clone(),
config.server.max_connections,
+10
View File
@@ -595,6 +595,16 @@ async fn render_metrics(
"telemt_buffer_pool_buffers_total{{kind=\"in_use\"}} {}",
stats.get_buffer_pool_in_use_gauge()
);
let _ = writeln!(
out,
"# HELP telemt_buffer_pool_events_total Buffer-pool allocation lifecycle events"
);
let _ = writeln!(out, "# TYPE telemt_buffer_pool_events_total counter");
let _ = writeln!(
out,
"telemt_buffer_pool_events_total{{event=\"replaced_nonstandard\"}} {}",
stats.get_buffer_pool_replaced_nonstandard_total()
);
let direct_budget = shared_state.direct_buffer_budget.snapshot();
let _ = writeln!(
+29 -1
View File
@@ -5,6 +5,7 @@ use std::time::Duration;
use tokio::sync::watch;
use crate::stats::Stats;
use crate::stream::BufferPool;
use super::shared_state::ProxySharedState;
@@ -21,6 +22,8 @@ const AUTO_HARD_FALLBACK_BYTES: usize = 512 * 1024 * 1024;
const TARGET_FLOOR_MIN_BYTES: usize = 16 * 1024 * 1024;
const CONTROL_INTERVAL: Duration = Duration::from_secs(1);
const HEALTHY_RECOVERY_SAMPLES: u8 = 30;
const BUFFER_POOL_TRIM_LOW_WATERMARK: usize = 64;
const BUFFER_POOL_TRIM_HIGH_WATERMARK: usize = 128;
#[derive(Debug, Clone, Copy, Default)]
/// Lock-free observability snapshot of the Direct copy-buffer envelope.
@@ -337,9 +340,10 @@ pub(crate) async fn resolve_direct_buffer_hard_limit(configured: usize) -> usize
align_down(derived as usize).max(DIRECT_BUFFER_UNIT_BYTES)
}
/// Starts the single control-plane task that adjusts the runtime target.
/// Starts the single control-plane task for Direct budget and shared pool pressure.
pub(crate) fn spawn_direct_buffer_budget_controller(
budget: Arc<DirectBufferBudget>,
buffer_pool: Arc<BufferPool>,
stats: Arc<Stats>,
shared: Arc<ProxySharedState>,
max_connections: u32,
@@ -351,6 +355,13 @@ pub(crate) fn spawn_direct_buffer_budget_controller(
let mut previous_denied = 0u64;
let mut previous_fallback = 0u64;
let mut previous_rejected = 0u64;
let pool_trim_low = buffer_pool
.max_buffers()
.min(BUFFER_POOL_TRIM_LOW_WATERMARK);
let pool_trim_high = buffer_pool
.max_buffers()
.min(BUFFER_POOL_TRIM_HIGH_WATERMARK);
let mut pool_trim_armed = true;
loop {
interval.tick().await;
@@ -380,6 +391,23 @@ pub(crate) fn spawn_direct_buffer_budget_controller(
|| fallback_delta > 0
|| rejected_delta > 0;
if !pressure {
pool_trim_armed = true;
} else if pool_trim_armed && buffer_pool.pooled() > pool_trim_high {
buffer_pool.trim_to(pool_trim_low);
pool_trim_armed = false;
}
let pool_snapshot = buffer_pool.stats();
stats.set_buffer_pool_gauges(
pool_snapshot.pooled,
pool_snapshot.allocated,
pool_snapshot.allocated.saturating_sub(pool_snapshot.pooled),
);
stats.set_buffer_pool_replaced_nonstandard_total(
pool_snapshot.replaced_nonstandard,
);
let headroom_target = if sample.total_bytes == 0 {
snapshot.hard_limit_bytes
} else {
-1
View File
@@ -400,7 +400,6 @@ where
Err(e) => debug!(user = %user, error = %e, "Direct relay ended with error"),
}
buffer_pool_trim.trim_to(buffer_pool_trim.max_buffers().min(64));
let pool_snapshot = buffer_pool_trim.stats();
stats.set_buffer_pool_gauges(
pool_snapshot.pooled,
-1
View File
@@ -823,7 +823,6 @@ where
clear_relay_idle_candidate_in(shared.as_ref(), conn_id);
me_pool.registry().unregister(conn_id).await;
buffer_pool.trim_to(buffer_pool.max_buffers().min(64));
let pool_snapshot = buffer_pool.stats();
stats.set_buffer_pool_gauges(
pool_snapshot.pooled,
+6
View File
@@ -204,6 +204,12 @@ impl Stats {
self.buffer_pool_in_use_gauge.load(Ordering::Relaxed)
}
/// Returns the count of non-standard buffers replaced before pooling.
pub fn get_buffer_pool_replaced_nonstandard_total(&self) -> u64 {
self.buffer_pool_replaced_nonstandard_total
.load(Ordering::Relaxed)
}
pub fn get_me_c2me_send_full_total(&self) -> u64 {
self.me_c2me_send_full_total.load(Ordering::Relaxed)
}
+1
View File
@@ -274,6 +274,7 @@ pub struct Stats {
buffer_pool_pooled_gauge: AtomicU64,
buffer_pool_allocated_gauge: AtomicU64,
buffer_pool_in_use_gauge: AtomicU64,
buffer_pool_replaced_nonstandard_total: AtomicU64,
// C2ME enqueue observability
me_c2me_send_full_total: AtomicU64,
me_c2me_send_high_water_total: AtomicU64,
+8
View File
@@ -552,6 +552,14 @@ impl Stats {
}
}
/// Publishes the cumulative count of non-standard pool buffer replacements.
pub fn set_buffer_pool_replaced_nonstandard_total(&self, value: usize) {
if self.telemetry_me_allows_normal() {
self.buffer_pool_replaced_nonstandard_total
.store(value as u64, Ordering::Relaxed);
}
}
pub fn increment_me_c2me_send_full_total(&self) {
if self.telemetry_me_allows_normal() {
self.me_c2me_send_full_total.fetch_add(1, Ordering::Relaxed);