1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.master.balancer;
19
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Random;
24 import java.util.Set;
25 import java.util.TreeMap;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.hadoop.conf.Configuration;
30 import org.apache.hadoop.hbase.ClusterStatus;
31 import org.apache.hadoop.hbase.HRegionInfo;
32 import org.apache.hadoop.hbase.ServerName;
33 import org.apache.hadoop.hbase.master.AssignmentManager;
34 import org.apache.hadoop.hbase.master.LoadBalancer;
35 import org.apache.hadoop.hbase.master.MasterServices;
36
37 import com.google.common.base.Joiner;
38 import com.google.common.collect.ArrayListMultimap;
39 import com.google.common.collect.Sets;
40
41
42
43
44
45
46
47 public abstract class BaseLoadBalancer implements LoadBalancer {
48
49
50 private float slop;
51 private Configuration config;
52 private static final Random RANDOM = new Random(System.currentTimeMillis());
53 private static final Log LOG = LogFactory.getLog(BaseLoadBalancer.class);
54
55 protected MasterServices services;
56
57 @Override
58 public void setConf(Configuration conf) {
59 this.slop = conf.getFloat("hbase.regions.slop", (float) 0.2);
60 if (slop < 0) slop = 0;
61 else if (slop > 1) slop = 1;
62 this.config = conf;
63 }
64
65 @Override
66 public Configuration getConf() {
67 return this.config;
68 }
69
70 public void setClusterStatus(ClusterStatus st) {
71
72 }
73
74 public void setMasterServices(MasterServices masterServices) {
75 this.services = masterServices;
76 }
77
78 protected boolean needsBalance(ClusterLoadState cs) {
79
80 float average = cs.getLoadAverage();
81
82 int floor = (int) Math.floor(average * (1 - slop));
83 int ceiling = (int) Math.ceil(average * (1 + slop));
84
85 return cs.getMinLoad() > ceiling || cs.getMaxLoad() < floor;
86 }
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 public Map<ServerName, List<HRegionInfo>> roundRobinAssignment(List<HRegionInfo> regions,
106 List<ServerName> servers) {
107 if (regions.isEmpty() || servers.isEmpty()) {
108 return null;
109 }
110 Map<ServerName, List<HRegionInfo>> assignments = new TreeMap<ServerName, List<HRegionInfo>>();
111 int numRegions = regions.size();
112 int numServers = servers.size();
113 int max = (int) Math.ceil((float) numRegions / numServers);
114 int serverIdx = 0;
115 if (numServers > 1) {
116 serverIdx = RANDOM.nextInt(numServers);
117 }
118 int regionIdx = 0;
119 for (int j = 0; j < numServers; j++) {
120 ServerName server = servers.get((j + serverIdx) % numServers);
121 List<HRegionInfo> serverRegions = new ArrayList<HRegionInfo>(max);
122 for (int i = regionIdx; i < numRegions; i += numServers) {
123 serverRegions.add(regions.get(i % numRegions));
124 }
125 assignments.put(server, serverRegions);
126 regionIdx++;
127 }
128 return assignments;
129 }
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148 public Map<HRegionInfo, ServerName> immediateAssignment(List<HRegionInfo> regions,
149 List<ServerName> servers) {
150 Map<HRegionInfo, ServerName> assignments = new TreeMap<HRegionInfo, ServerName>();
151 for (HRegionInfo region : regions) {
152 assignments.put(region, randomAssignment(region, servers));
153 }
154 return assignments;
155 }
156
157
158
159
160 public ServerName randomAssignment(HRegionInfo regionInfo, List<ServerName> servers) {
161 if (servers == null || servers.isEmpty()) {
162 LOG.warn("Wanted to do random assignment but no servers to assign to");
163 return null;
164 }
165 return servers.get(RANDOM.nextInt(servers.size()));
166 }
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185 public Map<ServerName, List<HRegionInfo>> retainAssignment(Map<HRegionInfo, ServerName> regions,
186 List<ServerName> servers) {
187
188
189
190
191
192
193 ArrayListMultimap<String, ServerName> serversByHostname = ArrayListMultimap.create();
194 for (ServerName server : servers) {
195 serversByHostname.put(server.getHostname(), server);
196 }
197
198
199 Map<ServerName, List<HRegionInfo>> assignments = new TreeMap<ServerName, List<HRegionInfo>>();
200
201 for (ServerName server : servers) {
202 assignments.put(server, new ArrayList<HRegionInfo>());
203 }
204
205
206
207
208 Set<String> oldHostsNoLongerPresent = Sets.newTreeSet();
209
210 int numRandomAssignments = 0;
211 int numRetainedAssigments = 0;
212 for (Map.Entry<HRegionInfo, ServerName> entry : regions.entrySet()) {
213 HRegionInfo region = entry.getKey();
214 ServerName oldServerName = entry.getValue();
215 List<ServerName> localServers = new ArrayList<ServerName>();
216 if (oldServerName != null) {
217 localServers = serversByHostname.get(oldServerName.getHostname());
218 }
219 if (localServers.isEmpty()) {
220
221
222 ServerName randomServer = servers.get(RANDOM.nextInt(servers.size()));
223 assignments.get(randomServer).add(region);
224 numRandomAssignments++;
225 if (oldServerName != null) oldHostsNoLongerPresent.add(oldServerName.getHostname());
226 } else if (localServers.size() == 1) {
227
228 assignments.get(localServers.get(0)).add(region);
229 numRetainedAssigments++;
230 } else {
231
232 int size = localServers.size();
233 ServerName target = localServers.get(RANDOM.nextInt(size));
234 assignments.get(target).add(region);
235 numRetainedAssigments++;
236 }
237 }
238
239 String randomAssignMsg = "";
240 if (numRandomAssignments > 0) {
241 randomAssignMsg =
242 numRandomAssignments + " regions were assigned "
243 + "to random hosts, since the old hosts for these regions are no "
244 + "longer present in the cluster. These hosts were:\n "
245 + Joiner.on("\n ").join(oldHostsNoLongerPresent);
246 }
247
248 LOG.info("Reassigned " + regions.size() + " regions. " + numRetainedAssigments
249 + " retained the pre-restart assignment. " + randomAssignMsg);
250 return assignments;
251 }
252
253 }