mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-15 11:00:51 +02:00
* balance: extract the bytes-aware density metric to weed/topology/balancer The shell's volume.balance ranks servers by a bytes-aware density (used volume equivalents over free capacity). Move that math into the shared balancer package (VolumeDensity / DensityRatio / DensityNextRatio) so the maintenance worker can adopt the same metric next. Shell behavior is unchanged. * balance: rank a server with no free capacity as the fullest DensityRatio/DensityNextRatio divided by capacity, so a server past its slot limit (negative capacity) returned a negative ratio and sorted as the emptiest under ascending consumers — the opposite of reality. Treat any non-positive capacity (full, or overfull mid-run after receiving volumes) as the fullest (+Inf) so it is a move source, never a target. Covered by negative-capacity and ordering tests.
53 lines
2.2 KiB
Go
53 lines
2.2 KiB
Go
package balancer
|
|
|
|
import "math"
|
|
|
|
// zeroVolumeDensityWeight is the ratio given to a server holding no data, so it
|
|
// still ranks below any loaded server (which has ratio >= 1) but is distinguished
|
|
// from a server with unknown capacity.
|
|
const zeroVolumeDensityWeight = 0.5
|
|
|
|
// UsedVolumeEquivalents converts the bytes a server holds into whole-volume
|
|
// equivalents (volumeBytes / volumeSizeLimit). Returns 0 when the limit is unset.
|
|
func UsedVolumeEquivalents(volumeBytes, volumeSizeLimitBytes uint64) uint64 {
|
|
if volumeSizeLimitBytes == 0 {
|
|
return 0
|
|
}
|
|
return volumeBytes / volumeSizeLimitBytes
|
|
}
|
|
|
|
// VolumeDensity is the bytes-aware capacity view balancing ranks servers by:
|
|
// used = volumeBytes / volumeSizeLimit, capacity = maxVolumeCount - used. Using
|
|
// real data (not just volume count) means an over-configured maxVolumeCount can't
|
|
// make a byte-full server look empty. capacity may be <= 0 for a server already
|
|
// past its configured slots.
|
|
func VolumeDensity(maxVolumeCount int64, volumeBytes, volumeSizeLimitBytes uint64) (capacity float64, usedVolumes uint64) {
|
|
usedVolumes = UsedVolumeEquivalents(volumeBytes, volumeSizeLimitBytes)
|
|
return float64(maxVolumeCount - int64(usedVolumes)), usedVolumes
|
|
}
|
|
|
|
// DensityRatio is a server's load: usedVolumes / capacity, higher = fuller. An
|
|
// empty server gets a small positive ratio so it sorts below loaded servers.
|
|
// A server with no free capacity (capacity <= 0: full, or over its configured
|
|
// slots so capacity is negative) ranks as the fullest (+Inf), so ascending
|
|
// consumers treat it as a move source and never as the emptiest target.
|
|
func DensityRatio(capacity float64, usedVolumes uint64) float64 {
|
|
if capacity <= 0 {
|
|
return math.Inf(1)
|
|
}
|
|
if usedVolumes == 0 {
|
|
return zeroVolumeDensityWeight / capacity
|
|
}
|
|
return float64(usedVolumes) / capacity
|
|
}
|
|
|
|
// DensityNextRatio is a server's load after one more volume lands on it:
|
|
// (usedVolumes+1) / capacity. Used to test whether a move would overshoot. A
|
|
// server with no free capacity (capacity <= 0) ranks as the fullest (+Inf).
|
|
func DensityNextRatio(capacity float64, usedVolumes uint64) float64 {
|
|
if capacity <= 0 {
|
|
return math.Inf(1)
|
|
}
|
|
return float64(usedVolumes+1) / capacity
|
|
}
|