summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2016-01-13 17:30:53 +0100
committerantirez <antirez@gmail.com>2016-01-25 15:21:40 +0100
commit8cae6e955be39488a12e5cb73e42eba22331da37 (patch)
tree42abd1d558a7192ea4d5c599f98628b0c4682231
parent791a2956364ceb81e75d833e55e7300f955f6df1 (diff)
downloadredis-8cae6e955be39488a12e5cb73e42eba22331da37.tar.gz
Cluster: fix rebalancing to always empty nodes.
Because of rounding error even with weight=0 sometimes a node was left with an assigned slot. Close #3001.
-rwxr-xr-xsrc/redis-trib.rb27
1 files changed, 24 insertions, 3 deletions
diff --git a/src/redis-trib.rb b/src/redis-trib.rb
index 125e5a4a1..63d2acec1 100755
--- a/src/redis-trib.rb
+++ b/src/redis-trib.rb
@@ -1044,7 +1044,6 @@ class RedisTrib
over_threshold = true
end
end
- puts "#{n} balance is #{n.info[:balance]} slots" if $verbose
threshold_reached = true if over_threshold
end
}
@@ -1053,15 +1052,37 @@ class RedisTrib
return
end
- # Sort nodes by their slots balance.
+ # Only consider nodes we want to change
sn = @nodes.select{|n|
n.has_flag?("master") && n.info[:w]
- }.sort{|a,b|
+ }
+
+ # Because of rounding, it is possible that the balance of all nodes
+ # summed does not give 0. Make sure that nodes that have to provide
+ # slots are always matched by nodes receiving slots.
+ total_balance = sn.map{|x| x.info[:balance]}.reduce{|a,b| a+b}
+ while total_balance > 0
+ sn.each{|n|
+ if n.info[:balance] < 0 && total_balance > 0
+ n.info[:balance] -= 1
+ total_balance -= 1
+ end
+ }
+ end
+
+ # Sort nodes by their slots balance.
+ sn = sn.sort{|a,b|
a.info[:balance] <=> b.info[:balance]
}
xputs ">>> Rebalancing across #{nodes_involved} nodes. Total weight = #{total_weight}"
+ if $verbose
+ sn.each{|n|
+ puts "#{n} balance is #{n.info[:balance]} slots"
+ }
+ end
+
# Now we have at the start of the 'sn' array nodes that should get
# slots, at the end nodes that must give slots.
# We take two indexes, one at the start, and one at the end,