mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-23 22:40:39 +02:00
* ec distribution: parse EC and replication configs into a shard plan NewECConfig/DefaultECConfig and NewReplicationConfig(FromString) turn an EC ratio and a replica placement into ECConfig/ReplicationConfig values, and CalculateDistribution derives the target and maximum shard counts per data center, rack, and node. ECDistribution.Summary and FaultToleranceAnalysis describe, per topology level, whether losing one failure domain leaves enough shards to reconstruct the volume, so the EC durability guarantees of a given setup can be answered directly instead of only documented informally. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * ec distribution: analyze topology and plan shard moves TopologyAnalysis records nodes and shard locations per DC/rack/node, and Rebalancer.PlanRebalance emits the moves that level the layout: data centers first, then racks within each DC, then nodes within each rack, moving parity shards before data shards and honoring per-node free slots. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * ec distribution: cover the plan math and rebalancing with tests Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * ec distribution: keep AddShardLocation and node ShardIDs in sync AddShardLocation updated the count maps but never the node's ShardIDs — yet every rebalancer count reads len(node.ShardIDs), so the documented AddNode-then-AddShardLocation flow produced an empty rebalance plan. It now appends to the node's shard list and skips shards the node already has, making the two registration styles equivalent and idempotent. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * ec distribution: key rack-scoped maps by dc/rack Rack names are only unique within a data center — two DCs can both hold a "rack1" — so ShardsByRack, RackToShards, and RackToNodes keyed by the bare rack name merged distinct domains and corrupted both the DC-level shard counts and rack-level balancing. Rack lookups now use the dc/rack pair; DCToRacks still lists bare rack names. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * ec distribution: never move a shard onto a node already holding it The move picker selected the destination node before the shard, so a node already holding the chosen shard could be targeted. Pick the shard first (parity-first) and choose among destination nodes that lack it. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * ec distribution: tolerate zero-value replication configs A ReplicationConfig{} with zeroed minimums made maxShare divide by zero; clamp each level's unit count to at least one. Covers the new behaviors with tests. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * ec distribution: keep rack keys distinct when names contain "/" rackKey joined data center and rack with "/", so dc "a"/rack "b/c" and dc "a/b"/rack "c" shared one key and were counted as the same failure domain. Separate the parts with a NUL byte, which cannot appear in a name. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * ec distribution: plan rebalances on a copy of the topology recordMove mutated the caller's TopologyAnalysis while planning, so an interrupted or partial execution left the input describing moves that never happened, and replanning on it returned nothing. PlanRebalance now simulates on a cloned analysis; plan.Analysis reports the layout the moves would produce and the caller's input is left untouched. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * ec distribution: balance nodes against the rack's current shard count The node-level target still read the original analysis, so a rack that had just sent or received shards during DC/rack balancing aimed at a stale total and left its nodes unbalanced. * ec distribution: register each node id once Adding the same node twice appended it to RackToNodes twice, so every count that walks rack nodes double-counted its shards. * ec distribution: normalize replication counts in the stored plan A zero-value ReplicationConfig computed targets against one domain per level while Summary still reported zero DCs, racks, and nodes. * ec distribution: cap a survivable level's max at the loss budget * ec distribution: skip shards already inside the destination domain * ec distribution: register nodes implied by shard locations * ec distribution: merge repeat node registrations A shard location now auto-registers an unknown node with no free slots; a later AddNode carrying the real capacity was then dropped entirely. Repeat registration now updates the node's capacity and adopts any new shards, while the first registration keeps the topology placement. * ec distribution: try other overloaded sources before stopping When the most overloaded domain could not shed any shard, balance returned early and skipped every other source that still had movable shards. A source that cannot move now gets set aside for the rest of the pass. * ec distribution: collapse chained shard moves to the final destination Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * ec distribution: schedule collapsed moves behind the departures that free slots Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
EC Distribution Package
This package provides erasure coding (EC) shard distribution algorithms that are:
- Configurable: Works with any EC ratio (e.g., 10+4, 8+4, 6+3)
- Reusable: Used by shell commands, worker tasks, and seaweed-enterprise
- Topology-aware: Distributes shards across data centers, racks, and nodes proportionally
Usage
Basic Usage with Default 10+4 EC
import (
"github.com/seaweedfs/seaweedfs/weed/storage/erasure_coding/distribution"
)
// Parse replication policy
rep, _ := distribution.NewReplicationConfigFromString("110")
// Use default 10+4 EC configuration
ec := distribution.DefaultECConfig()
// Calculate distribution plan
dist := distribution.CalculateDistribution(ec, rep)
fmt.Println(dist.Summary())
// Output:
// EC Configuration: 10+4 (total: 14, can lose: 4)
// Replication: replication=110 (DCs:2, Racks/DC:2, Nodes/Rack:1)
// Distribution Plan:
// Data Centers: 2 (target 7 shards each, max 9)
// Racks per DC: 2 (target 4 shards each, max 4)
// Nodes per Rack: 1 (target 4 shards each, max 4)
Custom EC Ratios (seaweed-enterprise)
// Create custom 8+4 EC configuration
ec, err := distribution.NewECConfig(8, 4)
if err != nil {
log.Fatal(err)
}
rep, _ := distribution.NewReplicationConfigFromString("200")
dist := distribution.CalculateDistribution(ec, rep)
// Check fault tolerance
fmt.Println(dist.FaultToleranceAnalysis())
// Output:
// Fault Tolerance Analysis for 8+4:
// DC Failure: SURVIVABLE ✓
// - Losing one DC loses ~4 shards
// - Remaining: 8 shards (need 8)
Planning Shard Moves
// Build topology analysis
analysis := distribution.NewTopologyAnalysis()
// Add nodes and their shard locations
for _, node := range nodes {
analysis.AddNode(&distribution.TopologyNode{
NodeID: node.ID,
DataCenter: node.DC,
Rack: node.Rack,
FreeSlots: node.FreeSlots,
})
for _, shardID := range node.ShardIDs {
analysis.AddShardLocation(distribution.ShardLocation{
ShardID: shardID,
NodeID: node.ID,
DataCenter: node.DC,
Rack: node.Rack,
})
}
}
analysis.Finalize()
// Create rebalancer and plan moves
rebalancer := distribution.NewRebalancer(ec, rep)
plan, err := rebalancer.PlanRebalance(analysis)
for _, move := range plan.Moves {
fmt.Printf("Move shard %d from %s to %s\n",
move.ShardID, move.SourceNode.NodeID, move.DestNode.NodeID)
}
Algorithm
Proportional Distribution
The replication policy XYZ is interpreted as a ratio:
| Replication | DCs | Racks/DC | Nodes/Rack | 14 Shards Distribution |
|---|---|---|---|---|
000 |
1 | 1 | 1 | All in one place |
001 |
1 | 1 | 2 | 7 per node |
010 |
1 | 2 | 1 | 7 per rack |
100 |
2 | 1 | 1 | 7 per DC |
110 |
2 | 2 | 1 | 7/DC, 4/rack |
200 |
3 | 1 | 1 | 5 per DC |
Rebalancing Process
- DC-level balancing: Move shards to achieve target shards per DC
- Rack-level balancing: Within each DC, balance across racks
- Node-level balancing: Within each rack, balance across nodes
Shard Priority: Data First, Parity Moves First
When rebalancing, the algorithm prioritizes keeping data shards spread out:
- Data shards (0 to DataShards-1): Serve read requests directly
- Parity shards (DataShards to TotalShards-1): Only used for reconstruction
Rebalancing Strategy:
- When moving shards FROM an overloaded node, parity shards are moved first
- This keeps data shards in place on well-distributed nodes
- Result: Data shards remain spread out for optimal read performance
// Check shard type
if ec.IsDataShard(shardID) {
// Shard serves read requests
}
if ec.IsParityShard(shardID) {
// Shard only used for reconstruction
}
// Sort shards for placement (data first for initial distribution)
sorted := ec.SortShardsDataFirst(shards)
// Sort shards for rebalancing (parity first to move them away)
sorted := ec.SortShardsParityFirst(shards)
Fault Tolerance
The package provides fault tolerance analysis:
- DC Failure: Can the data survive complete DC loss?
- Rack Failure: Can the data survive complete rack loss?
- Node Failure: Can the data survive single node loss?
For example, with 10+4 EC (can lose 4 shards):
- Need 4+ DCs for DC-level fault tolerance
- Need 4+ racks for rack-level fault tolerance
- Usually survivable at node level
API Reference
Types
ECConfig: EC configuration (data shards, parity shards)ReplicationConfig: Parsed replication policyECDistribution: Calculated distribution planTopologyAnalysis: Current shard distribution analysisRebalancer: Plans shard movesRebalancePlan: List of planned movesShardMove: Single shard move operation
Key Functions
NewECConfig(data, parity int): Create EC configurationDefaultECConfig(): Returns 10+4 configurationCalculateDistribution(ec, rep): Calculate distribution planNewRebalancer(ec, rep): Create rebalancerPlanRebalance(analysis): Generate rebalancing plan
Integration
Shell Commands
The shell package wraps this distribution package for ec.balance:
import "github.com/seaweedfs/seaweedfs/weed/shell"
rebalancer := shell.NewProportionalECRebalancer(nodes, rp, diskType)
moves, _ := rebalancer.PlanMoves(volumeId, locations)
Worker Tasks
Worker tasks can use the distribution package directly:
import "github.com/seaweedfs/seaweedfs/weed/storage/erasure_coding/distribution"
ec := distribution.ECConfig{DataShards: 8, ParityShards: 4}
rep := distribution.NewReplicationConfig(rp)
dist := distribution.CalculateDistribution(ec, rep)
seaweed-enterprise
Enterprise features can provide custom EC configurations:
// Custom EC ratio from license/config
ec, _ := distribution.NewECConfig(customData, customParity)
rebalancer := distribution.NewRebalancer(ec, rep)