diff --git a/weed/worker/tasks/balance/detection.go b/weed/worker/tasks/balance/detection.go index d71dca4b7..1480c13ca 100644 --- a/weed/worker/tasks/balance/detection.go +++ b/weed/worker/tasks/balance/detection.go @@ -193,7 +193,7 @@ func findServerIDByAddress(diskMetrics []*types.VolumeHealthMetrics, address str // createBalanceTask creates a single balance task for the selected volume. // Returns nil if destination planning fails. func createBalanceTask(diskType string, selectedVolume *types.VolumeHealthMetrics, clusterInfo *types.ClusterInfo) *types.TaskDetectionResult { - taskID := fmt.Sprintf("balance_vol_%d_%d", selectedVolume.VolumeID, time.Now().Unix()) + taskID := fmt.Sprintf("balance_vol_%d_%d", selectedVolume.VolumeID, time.Now().UnixNano()) task := &types.TaskDetectionResult{ TaskID: taskID, @@ -374,7 +374,9 @@ func planBalanceDestination(activeTopology *topology.ActiveTopology, selectedVol }, nil } -// calculateBalanceScore calculates placement score for balance operations +// calculateBalanceScore calculates placement score for balance operations. +// LoadCount reflects pending+assigned tasks on the disk, so we factor it into +// the utilization estimate to avoid stacking multiple moves onto the same target. func calculateBalanceScore(disk *topology.DiskInfo, sourceRack, sourceDC string, volumeSize uint64) float64 { if disk.DiskInfo == nil { return 0.0 @@ -382,9 +384,10 @@ func calculateBalanceScore(disk *topology.DiskInfo, sourceRack, sourceDC string, score := 0.0 - // Prefer disks with lower current volume count (better for balance) + // Prefer disks with lower effective volume count (current + pending moves) if disk.DiskInfo.MaxVolumeCount > 0 { - utilization := float64(disk.DiskInfo.VolumeCount) / float64(disk.DiskInfo.MaxVolumeCount) + effectiveVolumeCount := float64(disk.DiskInfo.VolumeCount) + float64(disk.LoadCount) + utilization := effectiveVolumeCount / float64(disk.DiskInfo.MaxVolumeCount) score += (1.0 - utilization) * 40.0 // Up to 40 points for low utilization }