mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-23 22:40:39 +02:00
refactor(ec_balance): make the balance planner per-volume ratio-capable (#9960)
* refactor(ec_balance): make the balance planner per-volume ratio-capable Thread a per-volume EC ratio through the balance planner: Plan resolves each volume's data/parity from a new Options.VolumeRatio (falling back to the collection Ratio, then the build default, when it reports 0), and keys the global phase's ratio maps by volume instead of collection. The shell and worker balance paths build the per-volume lookup from each shard's heartbeat via the new ecbalancer.VolumeShardRatio. In OSS this is behavior-preserving: VolumeShardRatio returns 0 because the per-volume data_shards/parity_shards heartbeat fields are an enterprise feature, so every volume falls back to the collection ratio -- the existing standard-scheme behavior. The refactor keeps the shared planner in sync with the enterprise fork, which overrides VolumeShardRatio to classify and spread a mixed-ratio collection by each volume's own data/parity split. * perf(ec_balance): hoist the collection ratio out of the per-volume loop The collection ratio is constant for every volume in a collection, so resolve it once per collection instead of per volume; a custom Ratio func may do map lookups or locking. Addresses a review comment.
This commit is contained in:
1 parent
138220b961
commit
7e608c877a
7 files changed
+160
-30
No files matched your search
@@ -898,12 +898,16 @@ func shellECRatio(_ string) (int, int) {
|
||||
// balance plans EC shard moves with the shared planner and executes them. When
|
||||
// collections is empty all collections present are balanced.
|
||||
func (ecb *ecBalancer) balance(collections []string) error {
|
||||
topo := toBalancerTopology(ecb.ecNodes, collections, ecb.diskType)
|
||||
topo, volumeRatio := toBalancerTopology(ecb.ecNodes, collections, ecb.diskType)
|
||||
moves := ecbalancer.Plan(topo, ecbalancer.Options{
|
||||
DiskType: string(ecb.diskType),
|
||||
ImbalanceThreshold: 0, // the shell balances to an even distribution
|
||||
ReplicaPlacement: ecb.replicaPlacement,
|
||||
Ratio: shellECRatio,
|
||||
// Prefer each volume's own heartbeat-reported ratio over the collection
|
||||
// default so a mixed-ratio collection is spread per volume; 0 defers to
|
||||
// shellECRatio (and is the always-0 OSS case).
|
||||
VolumeRatio: volumeRatio,
|
||||
// Balance the global phase by fractional fullness so heterogeneous-capacity
|
||||
// nodes fill proportionally (matching the worker). This is identical to raw
|
||||
// shard count when capacities are uniform.
|
||||
@@ -914,12 +918,21 @@ func (ecb *ecBalancer) balance(collections []string) error {
|
||||
|
||||
// toBalancerTopology builds an ecbalancer.Topology from the shell's EcNode model,
|
||||
// including the shards of the requested collections (all collections when empty).
|
||||
func toBalancerTopology(ecNodes []*EcNode, collections []string, diskType types.DiskType) *ecbalancer.Topology {
|
||||
// It also returns a per-volume ratio lookup built from each shard's heartbeat
|
||||
// (0,0 when unreported, e.g. always in OSS), which Plan prefers over the
|
||||
// collection ratio for mixed-ratio clusters.
|
||||
func toBalancerTopology(ecNodes []*EcNode, collections []string, diskType types.DiskType) (*ecbalancer.Topology, func(collection string, vid uint32) (int, int)) {
|
||||
allowed := make(map[string]bool, len(collections))
|
||||
for _, c := range collections {
|
||||
allowed[c] = true
|
||||
}
|
||||
|
||||
type volRatioKey struct {
|
||||
collection string
|
||||
vid uint32
|
||||
}
|
||||
volRatios := make(map[volRatioKey][2]int)
|
||||
|
||||
topo := ecbalancer.NewTopology()
|
||||
for _, en := range ecNodes {
|
||||
rackKey := string(en.dc) + ":" + string(en.rack)
|
||||
@@ -939,9 +952,17 @@ func toBalancerTopology(ecNodes []*EcNode, collections []string, diskType types.
|
||||
continue
|
||||
}
|
||||
node.AddShards(eci.Id, eci.Collection, eci.DiskId, erasure_coding.ShardBits(eci.EcIndexBits))
|
||||
if d, p := ecbalancer.VolumeShardRatio(eci); d > 0 || p > 0 {
|
||||
volRatios[volRatioKey{eci.Collection, eci.Id}] = [2]int{d, p}
|
||||
}
|
||||
}
|
||||
}
|
||||
return topo
|
||||
|
||||
volumeRatio := func(collection string, vid uint32) (int, int) {
|
||||
r := volRatios[volRatioKey{collection, vid}]
|
||||
return r[0], r[1]
|
||||
}
|
||||
return topo, volumeRatio
|
||||
}
|
||||
|
||||
// executeMoves carries out the planned moves. Phases run in order (a within-rack
|
||||
|
||||
Reference in new issue
Block a user