EnerOS v0.29.0 Release Notes
Release Date: 2025-12-07 Codename: Distributed Git Tag: v0.29.0 Support Status: Stable Total Crates: 78 (4 new) Test Cases: 10000+ (500+ new)
Overview
EnerOS v0.29.0 “Distributed” is a distributed-deployment-focused release that enables EnerOS to run across multiple nodes. Provincial dispatch centers can have grid scales reaching tens of thousands of nodes, which a single machine cannot support with complete topology, power flow, and timeseries workloads. v0.29.0 upgrades EnerOS from a single-node system to a distributed system, achieving horizontal scaling through four capabilities: node discovery, data sharding, distributed transactions, and consistency guarantees.
This release introduces five core capabilities: Distributed Deployment, Node Discovery, Data Sharding, Distributed Transaction, and Consistency Guarantee. The cluster can scale from 3 nodes to 64 nodes, supporting real-time operation of 100,000-scale grid nodes.
In terms of design philosophy, v0.29.0 adheres to “partition tolerance first” — prioritizing availability during network partitions (AP), with critical operations ensuring consistency through quorum; “data locality” — sharding by electrical topology so most computation completes locally; “transparent scaling” — application-layer APIs remain unchanged, with distributed details handled by the kernel.
Key Metrics
| Metric | Value | Description |
|---|---|---|
| Max cluster size | 64 nodes | Horizontal scaling |
| Node discovery latency | < 2s | New node joining |
| Shard migration time | < 30s | Per shard |
| Distributed transaction latency | 15ms | 2PC |
| Data locality | 92% | Local access rate |
| New Crates | 4 | Distributed-related |
New Features
1. Distributed Deployment
Introduces the eneros-distributed Crate, providing distributed cluster management. Multiple nodes form a cluster, sharing topology, power flow, and timeseries data.
Cluster Creation
use eneros_distributed::{Cluster, ClusterConfig, NodeRole};
let cluster = Cluster::new("dispatch-cluster")
.config(ClusterConfig {
seed_nodes: vec!["node-1:7946", "node-2:7946"],
data_dir: "/var/lib/eneros",
replication_factor: 3,
shard_count: 32,
})
.join("node-1:7946").await?;
// View cluster status
let status = cluster.status().await?;
println!("Node count: {}", status.node_count);
println!("Shard count: {}", status.shard_count);
println!("Healthy nodes: {}", status.healthy_nodes);
Node Roles
| Role | Responsibility | Count | Description |
|---|---|---|---|
| Coordinator | Transaction coordination | 3-5 | Elected |
| DataNode | Shard storage | All | Carries data |
| ComputeNode | Compute node | All | Executes computation |
| Gateway | Entry gateway | 2+ | Load balancing |
2. Node Discovery
Introduces the eneros-distributed-discovery Crate, providing automatic node discovery and membership management. Based on the SWIM protocol (Gossip improvement), it achieves efficient membership maintenance.
Node Joining
use eneros_distributed_discovery::{Discovery, NodeInfo};
let discovery = Discovery::new(&cluster)
.gossip_interval(Duration::milliseconds(200))
.probe_timeout(Duration::milliseconds(500));
// New node joining
let node = NodeInfo::new("node-5")
.address("10.0.1.5:7946")
.roles(vec![NodeRole::DataNode, NodeRole::ComputeNode])
.capacity(Capacity {
cpu: 32,
memory_gb: 128,
disk_gb: 2000,
});
discovery.join(node).await?;
// Auto-broadcast to entire cluster, all nodes感知 within 2s
Failure Detection
// SWIM protocol failure detection
discovery.on_node_failure(|node| async move {
log::warn!("Node {} lost contact", node.id);
// Auto-trigger shard migration
cluster.rebalance_on_failure(node).await?;
// Notify agents to reschedule
swarm.on_node_failure(node).await?;
});
Discovery Protocol Comparison
| Protocol | Detection Latency | Network Overhead | Applicable Scale |
|---|---|---|---|
| Heartbeat | 3-15s | O(n) | < 10 nodes |
| Gossip | 1-5s | O(log n) | < 100 nodes |
| SWIM | 1-3s | O(log n) | < 1000 nodes |
3. Data Sharding
Introduces the eneros-distributed-sharding Crate, providing data sharding capabilities. Sharding by electrical topology ensures most computation completes locally.
Sharding Strategy
use eneros_distributed_sharding::{ShardManager, ShardStrategy};
let sharding = ShardManager::new(&cluster)
.strategy(ShardStrategy::TopologyBased)
.shard_count(32);
// Shard by electrical region
sharding.assign(&network).await?;
// Region A devices → shards 0-7
// Region B devices → shards 8-15
// ...
// Query shard location
let location = sharding.locate(BusId::from(42))?;
println!("Bus 42 is in shard {} (node {})", location.shard, location.node);
Shard Migration
// Auto-migrate shards when node fails
sharding.migrate(
from: "node-3",
to: "node-5",
shards: vec![8, 9, 10],
).await?;
// Online migration, no service interruption
Sharding Strategy Comparison
| Strategy | Data Locality | Migration Frequency | Applicable Scenario |
|---|---|---|---|
| Hash sharding | 50% | Low | General |
| Range sharding | 70% | Medium | Timeseries |
| Topology sharding | 92% | High | Power grid |
| Consistent hashing | 60% | Low | Elastic |
4. Distributed Transaction
Introduces the eneros-distributed-tx Crate, providing cross-node transaction guarantees. Supports both 2PC (Two-Phase Commit) and Saga modes.
2PC Transaction
use eneros_distributed_tx::{Transaction, TxCoordinator};
let coordinator = TxCoordinator::new(&cluster);
// Cross-node transaction: operate on multiple shards simultaneously
let mut tx = Transaction::new();
tx.add(Operation::UpdateBus(42, voltage: 1.02)); // Shard 3
tx.add(Operation::OpenSwitch(15)); // Shard 7
tx.add(Operation::AdjustGen(1, mw: 200.0)); // Shard 2
match coordinator.commit_2pc(tx).await {
Ok(_) => println!("Transaction committed successfully"),
Err(TxError::ParticipantAbort { node, reason }) => {
println!("Node {} rejected: {}", node, reason);
// Auto-rollback
}
}
Saga Mode
// Long transaction: Saga mode (compensating transactions)
let saga = Saga::new("fault-recovery")
.step(Step::new("isolate")
.action(|ctx| isolate_fault(ctx))
.compensation(|ctx| restore_isolated(ctx)))
.step(Step::new("transfer")
.action(|ctx| transfer_load(ctx))
.compensation(|ctx| restore_load(ctx)))
.step(Step::new("restore")
.action(|ctx| restore_power(ctx))
.compensation(|ctx| cut_power(ctx)));
saga.execute().await?;
Transaction Characteristics
| Mode | Consistency | Latency | Availability | Applicable Scenario |
|---|---|---|---|---|
| 2PC | Strong | 15ms | Low | Critical operations |
| Saga | Eventual | 5ms | High | Long workflows |
| TCC | Strong | 8ms | Medium | Resource reservation |
5. Consistency Guarantee
Introduces the eneros-distributed-consistency Crate, providing multi-level consistency guarantees. Different data types use different consistency levels.
Consistency Levels
use eneros_distributed_consistency::{Consistency, ReadOptions};
// Strong consistency read (always read latest value)
let bus = cluster.read(BusId::from(42), ReadOptions {
consistency: Consistency::Strong,
}).await?;
// Causal consistency read (read causally latest value)
let event = cluster.read_event(event_id, ReadOptions {
consistency: Consistency::Causal,
}).await?;
// Eventual consistency read (read any replica)
let metric = cluster.read_metric("load", ReadOptions {
consistency: Consistency::Eventual,
}).await?;
Replication Strategy
// Data replication
let replication = Replication::new()
.factor(3) // 3 replicas
.mode(ReplicationMode::Sync) // Synchronous replication
.placement(PlacementPolicy::rack_aware()); // Cross-rack
cluster.set_replication(replication).await?;
Consistency Matrix
| Data Type | Consistency | Replication | Write Latency | Applicable Scenario |
|---|---|---|---|---|
| Topology data | Strong | Sync 3 replicas | 15ms | Switch state |
| Power flow results | Strong | Sync 3 replicas | 15ms | Computation results |
| Timeseries data | Eventual | Async 3 replicas | 1ms | Telemetry data |
| Audit logs | Strong | Sync 3 replicas | 15ms | Compliance requirements |
| Cache | Eventual | Single replica | 0.1ms | Performance priority |
Improvements
- Network Layer: Switched from TCP to QUIC, multiplexing reduces connection establishment latency by 60%
- Serialization: Switched from JSON to MessagePack, serialization size reduced by 50%
- Compression: Zstandard compression enabled for timeseries data transmission, bandwidth usage reduced by 70%
- Load Balancing: Added adaptive load balancer that dynamically adjusts shards based on node load
Bug Fixes
- Fixed
eneros-distributed-discoverysplit-brain issue during network partition (#2908) - Fixed
eneros-distributed-shardingdata loss risk during shard migration (#2913) - Fixed
eneros-distributed-txtransaction suspension when 2PC coordinator failed (#2918) - Fixed
eneros-distributed-consistencysynchronous replication timeout with slow nodes (#2923)
Breaking Changes
Cluster::new: AddedClusterConfigparameter; shard and replica configuration must be providedread/writeAPI: AddedReadOptions/WriteOptionsparameters to specify consistency level
Upgrade Guide
- Run
cargo update -p eneros-distributed - Provide
ClusterConfigforCluster::new - Add consistency level parameters to read/write operations
- Refer to
docs/migration/v0.29.0.mdfor detailed migration steps