diff --git a/nodelite-server/src/load_test/scenarios.rs b/nodelite-server/src/load_test/scenarios.rs index 9c4d75c..47991da 100644 --- a/nodelite-server/src/load_test/scenarios.rs +++ b/nodelite-server/src/load_test/scenarios.rs @@ -413,6 +413,22 @@ async fn run_reconnect_storm_scenario(node_count: usize) -> Result>, server_handle: JoinHandle>, temp_dir: PathBuf, @@ -93,6 +94,7 @@ impl TestServer { ) .await?; let history = state.history.clone(); + let registry = state.registry.clone(); let shared = state.shared.clone(); let protected_routes = Router::new() @@ -126,6 +128,7 @@ impl TestServer { addr, shared, history, + registry, shutdown_tx: Some(shutdown_tx), server_handle, temp_dir, diff --git a/nodelite-server/src/registry.rs b/nodelite-server/src/registry.rs index 36bce27..9221c89 100644 --- a/nodelite-server/src/registry.rs +++ b/nodelite-server/src/registry.rs @@ -215,6 +215,9 @@ pub struct NodeRegistry { token_verify_limiter: Arc, /// Token 验证结果缓存:减少重连场景的 Argon2id 开销。 token_cache: Arc>>, + /// Token 缓存诊断计数器 (issue #306)。 + token_cache_hits: Arc, + token_cache_misses: Arc, #[cfg(test)] token_verify_probe: Option>, } diff --git a/nodelite-server/src/registry/auth.rs b/nodelite-server/src/registry/auth.rs index 8f49654..a757a0c 100644 --- a/nodelite-server/src/registry/auth.rs +++ b/nodelite-server/src/registry/auth.rs @@ -1,6 +1,7 @@ use std::sync::Arc; +use std::sync::atomic::Ordering; #[cfg(test)] -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::AtomicUsize; #[cfg(test)] use std::time::Duration; use std::time::Instant; @@ -127,6 +128,7 @@ impl NodeRegistry { if let Some(entry) = cache.get(&cache_key) { let age = entry.cached_at.elapsed(); if age < TOKEN_CACHE_TTL { + self.token_cache_hits.fetch_add(1, Ordering::Relaxed); return Ok(entry.verified); } // TTL 过期,移除旧条目 @@ -157,12 +159,14 @@ impl NodeRegistry { if let Some(entry) = cache.get(&cache_key) { let age = entry.cached_at.elapsed(); if age < TOKEN_CACHE_TTL { + self.token_cache_hits.fetch_add(1, Ordering::Relaxed); return Ok(entry.verified); } } } - // 执行实际的 Argon2id 验证 + // 缓存未命中,执行实际的 Argon2id 验证 + self.token_cache_misses.fetch_add(1, Ordering::Relaxed); let input = input.to_string(); let token_hash = token_hash.to_string(); #[cfg(test)] diff --git a/nodelite-server/src/registry/lifecycle.rs b/nodelite-server/src/registry/lifecycle.rs index bb97c29..379b21f 100644 --- a/nodelite-server/src/registry/lifecycle.rs +++ b/nodelite-server/src/registry/lifecycle.rs @@ -40,6 +40,8 @@ impl NodeRegistry { token_cache: Arc::new(ParkingLotMutex::new(LruCache::new( std::num::NonZeroUsize::new(TOKEN_CACHE_CAPACITY).expect("cache capacity > 0"), ))), + token_cache_hits: Arc::new(AtomicU64::new(0)), + token_cache_misses: Arc::new(AtomicU64::new(0)), #[cfg(test)] token_verify_probe: None, }) @@ -50,6 +52,31 @@ impl NodeRegistry { self.registry_revision.load(Ordering::Acquire) } + /// Token 缓存命中计数(累积值,issue #306)。 + #[cfg(test)] + pub fn token_cache_hits(&self) -> u64 { + self.token_cache_hits.load(Ordering::Relaxed) + } + + /// Token 缓存未命中计数(累积值,issue #306)。 + #[cfg(test)] + pub fn token_cache_misses(&self) -> u64 { + self.token_cache_misses.load(Ordering::Relaxed) + } + + /// Token 缓存命中率(百分比,issue #306)。 + #[cfg(test)] + pub fn token_cache_hit_rate(&self) -> f64 { + let hits = self.token_cache_hits() as f64; + let misses = self.token_cache_misses() as f64; + let total = hits + misses; + if total == 0.0 { + 0.0 + } else { + (hits / total) * 100.0 + } + } + /// 刷新节点的 Token:生成新明文 token, 哈希入库,代次 +1, 延长过期时间。 /// 返回 (new_plaintext_token, expires_at, new_generation)。明文只在 /// 进程内存里短暂存在,从这里被传递给 WS 端发送给 agent。