EnerOS v0.46.0 版本说明
- 发布日期:2026-07-03
- 版本代号:Stable
- 支持状态:稳定(Stable),长期支持候选
- Crate 总数:55
- 测试用例数:7200+
- 贡献者:30 人
版本概述
EnerOS v0.46.0 是「成熟优化」阶段的第六个版本,聚焦稳定性增强。在前五个版本完成性能基准、安全审计、开发者体验、文档系统与生态扩展后,本版本回归工程本质,集中精力解决长时间运行下的稳定性问题,为 v0.47.0 的最终收敛奠定坚实基础。
电力系统对可用性的要求极为严苛,省级调度中心要求系统年可用性达到 99.999%(即全年停机不超过 5 分钟)。这意味着 EnerOS 必须在长时间连续运行(数月乃至数年)下保持内存稳定、性能不退化、错误可恢复。v0.46.0 通过系统化的压力测试发现了 23 个内存泄漏点、12 个错误处理缺陷与 8 个资源未释放问题,并全部修复。
本版本引入了自动化压力测试框架 eneros-stress,能在 24 小时内模拟 7 天的真实负载,通过加速时钟与注入故障验证系统的长期稳定性。所有压力测试在 CI 中以周为周期运行,确保每次提交不会引入新的稳定性问题。
关键数据
| 指标 | 数值 | 说明 |
|---|---|---|
| Crate 数量 | 55 | 新增 eneros-stress |
| 测试用例 | 7200+ | 含 180+ 压力测试 |
| 内存泄漏修复 | 23 处 | 全部已修复 |
| 错误处理缺陷修复 | 12 处 | 全部已修复 |
| 连续运行测试 | 168 小时 | 无退化 |
| 内存增长(24h) | < 0.1% | 满载运行 |
| 可用性目标 | 99.999% | 年停机 < 5 分钟 |
新特性
1. 压力测试框架
新增 eneros-stress crate,提供系统化的压力测试能力。框架支持负载生成、故障注入、加速时钟与资源监控,能在短时间内模拟长时间运行场景。
框架架构
eneros-stress/
├── src/
│ ├── generator/ # 负载生成器
│ │ ├── topology.rs # 拓扑操作负载
│ │ ├── powerflow.rs # 潮流计算负载
│ │ ├── timeseries.rs # 时序写入负载
│ │ └── agent.rs # Agent 消息负载
│ ├── injector/ # 故障注入器
│ │ ├── network.rs # 网络故障
│ │ ├── disk.rs # 磁盘故障
│ │ └── process.rs # 进程故障
│ ├── monitor/ # 资源监控
│ │ ├── memory.rs # 内存增长检测
│ │ ├── fd.rs # 文件描述符泄漏
│ │ └── thread.rs # 线程泄漏
│ └── clock/ # 加速时钟
使用示例
use eneros_stress::{StressTest, StressConfig, LoadProfile, FaultInjector};
use std::time::Duration;
let stress = StressTest::new(StressConfig {
duration: Duration::from_secs(86400 * 7), // 模拟 7 天
accelerated_clock: 24.0, // 24 倍加速,实际运行 7 小时
load_profile: LoadProfile::Realistic {
peak_times: vec![8, 12, 18], // 每日高峰时段
base_load: 0.3, // 基础负载 30%
peak_load: 0.95, // 峰值负载 95%
},
fault_injection: FaultInjector::Chaos {
network_partition_prob: 0.001, // 0.1% 网络分区
disk_full_prob: 0.0005, // 0.05% 磁盘满
process_kill_prob: 0.002, // 0.2% 进程杀死
},
memory_leak_threshold: Duration::from_secs(3600), // 1 小时后检测
});
let report = stress.run().await?;
println!("测试结果:");
println!(" 总操作数: {}", report.total_ops);
println!(" 错误数: {}", report.errors.len());
println!(" 内存增长: {:.2}%", report.memory_growth_pct);
println!(" 可用性: {:.4}%", report.availability * 100.0);
for leak in &report.memory_leaks {
println!(" 内存泄漏: {} (增长 {:.2} MB/h)", leak.location, leak.rate_mb_per_hour);
}
压力测试场景
| 场景 | 负载模式 | 故障注入 | 持续时间 | 验证目标 |
|---|---|---|---|---|
| 满载运行 | 100% 持续 | 无 | 168 小时 | 内存稳定 |
| 峰谷波动 | 真实负载曲线 | 无 | 7 天(加速) | 性能不退化 |
| 混沌工程 | 真实负载 | 网络分区 | 24 小时 | 故障恢复 |
| 资源耗尽 | 递增负载 | 磁盘满 | 12 小时 | 优雅降级 |
| 长时连接 | 持续连接 | 进程杀死 | 48 小时 | 重连恢复 |
2. 内存泄漏修复
通过压力测试发现并修复了 23 处内存泄漏,涵盖拓扑快照、Agent 上下文、时序缓存、约束引擎与审计链五个模块。
主要泄漏点
| 模块 | 泄漏原因 | 影响速率 | 修复方式 |
|---|---|---|---|
| eneros-topology | 快照未释放 | 2.3 MB/h | 引用计数 + Drop |
| eneros-agent | 上下文缓存累积 | 1.8 MB/h | LRU 淘汰 |
| eneros-timeseries | 压缩缓冲区未回收 | 5.1 MB/h | 分级落盘 |
| eneros-constraint | 约束快照历史 | 0.7 MB/h | 限制历史深度 |
| eneros-trust | 审计日志缓冲 | 3.2 MB/h | 定期 flush |
| eneros-memory | Agent 记忆向量 | 4.5 MB/h | 分层压缩 |
| eneros-orchestrator | DAG 节点缓存 | 1.2 MB/h | 执行后清理 |
内存监控工具
use eneros_stress::monitor::{MemoryMonitor, LeakDetector};
let monitor = MemoryMonitor::new()
.sample_interval(Duration::from_secs(60))
.leak_detector(LeakDetector::LinearRegression {
min_samples: 60, // 至少 60 个样本(1 小时)
growth_threshold: 0.1, // 每小时增长 > 0.1% 报警
});
monitor.start().await?;
// 获取内存报告
let snapshot = monitor.snapshot().await?;
println!("当前 RSS: {:.1} MB", snapshot.rss_mb);
println!("24 小时增长: {:.2}%", snapshot.growth_24h_pct);
// 检测泄漏
if let Some(leaks) = monitor.detect_leaks().await? {
for leak in leaks {
eprintln!("疑似泄漏: {} 增长 {:.2} MB/h", leak.location, leak.rate);
}
}
3. 长时间运行优化
针对长时间运行场景进行了多项优化,确保系统在连续运行数月后性能不退化。
快照历史深度限制
use eneros_topology::{TopologyConfig, SnapshotPolicy};
let config = TopologyConfig {
snapshot_policy: SnapshotPolicy::Bounded {
max_history: 1000, // 最多保留 1000 个快照
max_age: Duration::from_secs(3600), // 最长保留 1 小时
eviction: EvictionPolicy::OldestFirst,
},
..Default::default()
};
Agent 上下文 LRU 淘汰
use eneros_agent::{AgentRuntime, CacheConfig};
let runtime = AgentRuntime::new(CacheConfig {
max_contexts: 500, // 最多缓存 500 个上下文
context_ttl: Duration::from_secs(300), // 5 分钟未使用即淘汰
eviction: EvictionPolicy::LRU,
});
时序数据分级落盘
use eneros_timeseries::{TsdbConfig, FlushPolicy};
let config = TsdbConfig {
flush_policy: FlushPolicy::Tiered {
hot_tier_size: 8 * 1024 * 1024, // 热层 8MB
warm_tier_size: 64 * 1024 * 1024, // 温层 64MB
cold_tier_path: "data/cold/",
flush_interval: Duration::from_millis(100),
backpressure_threshold: 0.8, // 80% 时触发背压
},
..Default::default()
};
4. 错误处理增强
系统化梳理了全部 crate 的错误处理路径,修复了 12 个错误处理缺陷,包括未处理的 panic、静默忽略的错误与不当的错误传播。
错误处理改进
| 缺陷类型 | 数量 | 影响 | 修复方式 |
|---|---|---|---|
| 未处理 panic | 3 | 进程崩溃 | 替换为 Result |
| 静默忽略错误 | 5 | 数据丢失 | 显式处理或传播 |
| 错误信息丢失 | 4 | 调试困难 | 保留错误链 |
| 资源未释放 | 8 | 资源泄漏 | RAII + Drop |
优雅降级机制
use eneros_core::resilience::{CircuitBreaker, FallbackPolicy};
let breaker = CircuitBreaker::new()
.failure_threshold(5) // 5 次失败后熔断
.reset_timeout(Duration::from_secs(30)) // 30 秒后尝试恢复
.fallback(FallbackPolicy::UseLastKnownGood); // 降级到最近可用值
match breaker.call(|| async {
ctx.syscall(SolvePowerFlow { /* ... */ }).await
}).await {
Ok(result) => { /* 正常结果 */ }
Err(CircuitBreakerError::Open) => {
// 熔断状态,使用降级值
let fallback = ctx.cache.get_last_powerflow().await?;
log::warn!("潮流计算熔断,使用缓存值");
}
}
背压机制
use eneros_core::resilience::{Backpressure, BackpressureConfig};
let bp = Backpressure::new(BackpressureConfig {
high_watermark: 0.8, // 80% 时开始背压
low_watermark: 0.5, // 50% 时停止背压
queue_capacity: 10000,
});
// 写入时检查背压
if bp.is_pressure_high() {
// 返回背压信号,上游应减速
return Err(BackpressureError::SlowDown);
}
bp.increment();
let result = do_work().await;
bp.decrement();
改进优化
Panic 捕获与恢复
所有 Agent 的执行入口增加 panic 捕获,防止单个 Agent 的 panic 导致整个运行时崩溃。panic 被捕获后记录完整调用栈,并触发 Agent 重启。
use eneros_agent::runtime::PanicGuard;
let guard = PanicGuard::new("dispatch-agent");
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
agent.run(ctx)
}));
match result {
Ok(Ok(())) => { /* 正常完成 */ }
Ok(Err(e)) => { /* Agent 返回错误 */ }
Err(panic) => {
let backtrace = guard.capture_backtrace(panic);
log::error!("Agent panic: {}", backtrace);
runtime::restart_agent("dispatch-agent").await?;
}
}
资源限额
每个 Agent 与插件增加资源限额,防止资源耗尽影响系统稳定性。
| 资源 | 默认限额 | 超限行为 |
|---|---|---|
| 内存 | 512 MB | OOM 告警 + 重启 |
| CPU | 4 核 | 限流 |
| 文件描述符 | 1024 | 拒绝新 FD |
| 网络连接 | 256 | 拒绝新连接 |
| 磁盘写入 | 1 GB/h | 限流 |
优雅关闭
系统关闭时按依赖顺序逐级优雅退出,确保所有在途请求完成、缓冲区落盘与状态持久化。
use eneros_os::shutdown::{ShutdownManager, ShutdownOrder};
let manager = ShutdownManager::new()
.timeout(Duration::from_secs(30))
.order(ShutdownOrder::Dependency)
.step("agents", |ctx| async { /* 停止所有 Agent */ })
.step("api", |ctx| async { /* 关闭 API 网关 */ })
.step("timeseries", |ctx| async { /* flush 时序数据 */ })
.step("topology", |ctx| async { /* 持久化拓扑 */ })
.step("kernel", |ctx| async { /* 内核清理 */ });
manager.shutdown().await?;
Bug 修复
- BG-701:拓扑快照在并发写入时引用计数错误,已修复为原子操作
- BG-705:Agent 上下文缓存无上限导致内存无限增长,已引入 LRU
- BG-709:时序压缩缓冲区在写入速度超过落盘速度时无限增长,已引入背压
- BG-713:约束引擎的历史快照未清理,已限制最大深度
- BG-717:审计日志缓冲区未定期 flush,已改为定时落盘
- BG-721:Agent 记忆向量无限累积,已引入分层压缩
- BG-725:DAG 编排节点缓存未清理,已执行后清理
- BG-729:panic 在 Agent 中未被捕获,已增加 PanicGuard
- BG-733:文件描述符在重连时泄漏,已修复 RAII 封装
- BG-737:优雅关闭时在途请求被丢弃,已增加 drain 期
破坏性变更
BC-251:AgentRuntime 新增资源限额配置
AgentRuntime::new 的配置参数新增 resource_limits 字段,需为现有代码补充该字段。
// v0.45.0(旧)
let runtime = AgentRuntime::new(RuntimeConfig::default());
// v0.46.0(新)
let runtime = AgentRuntime::new(RuntimeConfig {
resource_limits: ResourceLimits::default(),
..Default::default()
});
BC-252:TsdbConfig 的 flush_policy 字段变更
flush_policy 从简单的 FlushInterval 改为 FlushPolicy 枚举,支持分级落盘。
依赖升级
| 依赖 | 旧版本 | 新版本 | 说明 |
|---|---|---|---|
| rustc | 1.75 | 1.76 | panic hook 增强 |
| jemallocator | 0.5 | 0.5.4 | 内存分配器 |
| mimalloc | 0.1 | 0.1.39 | 备选分配器 |
| tracing | 0.1.40 | 0.1.40 | 无变化 |
升级指南
从 v0.45.0 升级
rustup default 1.76.0
cargo update
cargo test --workspace
处理破坏性变更:
// 补充资源限额配置
let runtime = AgentRuntime::new(RuntimeConfig {
resource_limits: ResourceLimits {
max_memory_mb: 512,
max_cpu_cores: 4,
max_file_descriptors: 1024,
},
..Default::default()
});
运行压力测试验证稳定性:
eneros-cli stress run --scenario full-load --duration 7h
eneros-cli stress report