EnerOS v0.11.0
发布日期:2024年11月03日 版本代号:DualExec Git Tag:v0.11.0 支持状态:稳定(Stable) Crate 总数:22(新增 4 个) 测试用例数:3100+(新增 480)
版本概述
EnerOS v0.11.0「DualExec」是 EnerOS 进入「运行时分层」阶段的关键版本,本版本的核心目标是引入双执行架构(Dual Execution Architecture),将电力系统的实时控制任务与分析型计算任务分离到两个独立的执行域中运行,从根本上解决「实时任务被分析任务阻塞」这一长期痛点。
在传统电力操作系统中,实时遥测采集、保护逻辑、AGC 调节等微秒级任务与潮流计算、负荷预测、报表聚合等秒级至分钟级任务共享同一调度器与线程池,导致在分析任务高负载时,实时任务的尾延迟会从微秒级退化至毫秒甚至十毫秒级,存在保护拒动、控制超时等安全风险。v0.11.0 通过物理隔离两个执行域,使实时域始终维持微秒级响应,分析域则可充分利用 CPU 资源进行批量计算。
本版本引入了 eneros-exec-rt(实时域运行时)、eneros-exec-batch(分析域运行时)、eneros-exec-bridge(域间数据同步桥)三个新 crate,并扩展了 eneros-sched 调度器以支持双域优先级抢占。设计哲学是「物理隔离优于逻辑优先级」——只有将两类任务调度到不同的 CPU 核心集合、不同的内存池、不同的 I/O 通道上,才能在硬件层面保证实时任务的确定性。
关键数据
| 指标 | v0.10.0 | v0.11.0 | 提升 |
|---|---|---|---|
| 实时任务 P99 延迟 | 2.4ms | 18μs | 133x |
| 实时任务 P99.9 延迟 | 12ms | 42μs | 285x |
| 分析任务吞吐 | 8 万 ops/s | 23 万 ops/s | 2.9x |
| CPU 利用率(满载) | 62% | 89% | +27pp |
| 尾延迟抖动 | 高 | 极低 | 显著改善 |
新特性
1. 双执行架构
引入 eneros-exec-rt 与 eneros-exec-batch 两个独立运行时,分别承载实时域(Realtime Domain)与分析域(Batch Domain)。两个域在启动时即绑定到不同的 CPU 核心集合,并通过 cgroup / CPU affinity 进行硬件级隔离。
执行域配置
use eneros_exec_rt::{RtRuntime, RtConfig};
use eneros_exec_batch::{BatchRuntime, BatchConfig};
use eneros_exec_bridge::Bridge;
// 配置实时域:绑定到 CPU 0-3,使用隔离内存池
let rt = RtRuntime::new(RtConfig {
cpu_set: vec![0, 1, 2, 3],
memory_pool: MemoryPool::isolated(256 * 1024 * 1024),
pre_allocated_buffers: 1024,
polling_interval: Duration::microseconds(50),
max_jitter: Duration::microseconds(10),
})?;
// 配置分析域:绑定到 CPU 4-15,可动态扩展
let batch = BatchRuntime::new(BatchConfig {
cpu_set: vec![4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
memory_pool: MemoryPool::dynamic(2 * 1024 * 1024 * 1024),
worker_threads: 12,
queue_capacity: 65536,
})?;
// 启动双域桥接器,负责域间数据同步
let bridge = Bridge::new(&rt, &batch)
.sync_interval(Duration::milliseconds(10))
.buffer_size(8192);
域间数据流向
| 数据流 | 方向 | 同步方式 | 延迟 |
|---|---|---|---|
| 遥测数据 | 实时域 → 分析域 | 无锁环形缓冲 | < 5μs |
| 派生指标 | 分析域 → 实时域 | 共享原子变量 | < 1μs |
| 控制命令 | 分析域 → 实时域 | 高优先级通道 | < 20μs |
| 告警事件 | 实时域 → 分析域 | 异步队列 | < 100μs |
2. 域间数据同步机制
引入 eneros-exec-bridge crate,提供实时域与分析域之间的安全数据交换通道。所有跨域数据均通过无锁数据结构传递,避免锁竞争对实时域造成抖动。
无锁环形缓冲
use eneros_exec_bridge::{RingBuffer, Producer, Consumer};
// 创建一个跨域共享的无锁环形缓冲
let (producer, consumer) = RingBuffer::<TelemetrySnapshot>::new(8192)
.split()?;
// 实时域生产者:写入遥测快照
producer.try_push(TelemetrySnapshot {
bus_id: 1,
voltage: 1.024,
current: 512.3,
timestamp: Instant::now(),
})?;
// 分析域消费者:批量读取
let batch: Vec<TelemetrySnapshot> = consumer.drain_up_to(256)?;
共享派生指标
use eneros_exec_bridge::SharedMetric;
// 分析域计算派生指标,写入共享原子变量
let metric = SharedMetric::new();
metric.store_load_forecast(1250.6); // MW
// 实时域读取(无锁,O(1))
let forecast = metric.load_load_forecast();
3. 隔离与优先级调度
扩展 eneros-sched 调度器,支持跨域优先级抢占。实时域任务拥有绝对优先级,可抢占分析域任务;分析域任务在实时域空闲时可「借用」实时域 CPU 资源。
优先级模型
| 优先级 | 域 | 典型任务 | 抢占能力 |
|---|---|---|---|
| P0(Critical) | 实时域 | 保护逻辑跳闸 | 抢占一切 |
| P1(Realtime) | 实时域 | AGC 调节 | 抢占 P2+ |
| P2(High) | 实时域 | 遥测采集 | 抢占 P3+ |
| P3(Normal) | 分析域 | 潮流计算 | 不可抢占实时 |
| P4(Low) | 分析域 | 报表聚合 | 不可抢占实时 |
调度器配置
use eneros_sched::{Scheduler, SchedConfig, Domain};
let sched = Scheduler::new(SchedConfig {
domains: vec![
Domain::realtime(rt_config),
Domain::batch(batch_config),
],
preemption: PreemptionPolicy::Strict,
borrowing: BorrowingPolicy::AllowWhenIdle,
starvation_timeout: Duration::seconds(30),
});
4. 实时域微秒级响应保证
实时域运行时采用预分配内存 + 轮询模式(Polling Mode),避免动态内存分配与中断响应带来的抖动。在标准 x86 服务器上,实时任务 P99 延迟稳定在 18μs 以内。
实时任务示例
use eneros_exec_rt::{RtTask, RtContext};
// 注册一个微秒级遥测任务
RtTask::new("telemetry-poll")
.priority(Priority::P2)
.period(Duration::microseconds(200))
.stack_size(64 * 1024)
.spawn(move |ctx: &RtContext| {
// 从共享内存读取 ADC 采样
let sample = ctx.shmem().read_adc(BUS_1)?;
// 校验物理约束
ctx.constraint().check_voltage(sample.voltage)?;
// 写入环形缓冲供分析域消费
ctx.bridge().push(TelemetrySnapshot::from(sample))?;
Ok(())
})?;
改进
- 调度器:重构
eneros-sched内部数据结构,使用crossbeam-deque替代std::sync::mpsc,工作窃取效率提升 40% - 内存管理:实时域引入
bumpalo区块分配器,避免分配抖动 - 观测性:新增
eneros-exec-trace子模块,提供域间数据流追踪 - 配置:支持通过
eneros.toml声明式配置双域拓扑
Bug 修复
- 修复
eneros-sched在 CPU 核心数变化时调度器 panic 的问题(#1124) - 修复
eneros-timeseries写入路径在高并发下偶发死锁的问题(#1131) - 修复
eneros-agent任务取消时未释放 CPU 亲和性绑定的问题(#1137) - 修复
eneros-constraint在批量校验时内存占用线性增长的问题(#1142)
破坏性变更
Scheduler::run签名变更:新增domains: &[Domain]参数,单域配置请使用Domain::single()Task::priority:优先级枚举从u8改为强类型Priority,需通过Priority::P2等构造eneros-execcrate 拆分:原eneros-exec拆分为eneros-exec-rt与eneros-exec-batch,旧代码迁移参考升级指南
性能提升
- 实时任务 P99 延迟从 2.4ms 降至 18μs(提升 133 倍)
- 分析任务吞吐从 8 万 ops/s 提升至 23 万 ops/s(提升 2.9 倍)
- 满载 CPU 利用率从 62% 提升至 89%
- 域间数据同步延迟稳定在 5μs 以内
贡献者
本版本由 18 位贡献者共同完成,提交 312 次。特别感谢:
- @rt-kernel:实时域运行时核心实现
- @lockfree-master:无锁环形缓冲设计
- @sched-guru:双域优先级抢占调度算法
- @memory-pool:实时域内存预分配方案
升级指南
从 v0.10.0 升级
1. 更新依赖
# Cargo.toml
[dependencies]
eneros-exec-rt = { version = "0.11", features = ["polling"] }
eneros-exec-batch = { version = "0.11" }
eneros-exec-bridge = { version = "0.11" }
eneros-sched = { version = "0.11" }
2. 迁移调度器配置
// v0.10.0 旧写法
let sched = Scheduler::new(SingleDomainConfig::default());
// v0.11.0 新写法
let sched = Scheduler::new(SchedConfig {
domains: vec![
Domain::realtime(rt_config),
Domain::batch(batch_config),
],
preemption: PreemptionPolicy::Strict,
borrowing: BorrowingPolicy::AllowWhenIdle,
starvation_timeout: Duration::seconds(30),
});
3. 标注任务域归属
所有任务需显式声明所属执行域:
// 旧:未声明域
Task::new("load-flow").priority(5).spawn(...);
// 新:声明域
Task::new("load-flow")
.domain(DomainKind::Batch)
.priority(Priority::P3)
.spawn(...);
4. CPU 绑核建议
推荐生产环境使用 taskset 或 cgroup 将实时域固定到独立 CPU 核心集合,并开启 isolcpus 内核参数以避免被其他系统进程干扰。详细配置参考运维手册「双执行架构部署」章节。