-
Notifications
You must be signed in to change notification settings - Fork 3.4k
HBASE-24140 : Move CandidateGenerator and their implementors out of StochasticLoadBalancer #1458
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
fd60fa8
HBASE-24140 : Move CandidateGenerator and their implementors out of S…
virajjasani 5b0556f
adding InterfaceAudience.Private based on review comment
virajjasani 90d19ea
Merge branch 'master' of github.com:apache/hbase into HBASE-24140-master
virajjasani 50fd8be
Merge branch 'master' of github.com:apache/hbase into HBASE-24140-master
virajjasani bdf82fb
Merge branch 'master' of github.com:apache/hbase into HBASE-24140-master
virajjasani File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
151 changes: 151 additions & 0 deletions
151
hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/CandidateGenerator.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,151 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package org.apache.hadoop.hbase.master.balancer; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| import org.apache.hadoop.hbase.client.RegionInfo; | ||
|
|
||
| import org.apache.yetus.audience.InterfaceAudience; | ||
|
|
||
| /** | ||
| * Generates a candidate action to be applied to the cluster for cost function search | ||
| */ | ||
| @InterfaceAudience.Private | ||
| abstract class CandidateGenerator { | ||
|
|
||
| abstract BaseLoadBalancer.Cluster.Action generate(BaseLoadBalancer.Cluster cluster); | ||
|
|
||
| /** | ||
| * From a list of regions pick a random one. Null can be returned which | ||
| * {@link StochasticLoadBalancer#balanceCluster(Map)} recognize as signal to try a region move | ||
| * rather than swap. | ||
| * | ||
| * @param cluster The state of the cluster | ||
| * @param server index of the server | ||
| * @param chanceOfNoSwap Chance that this will decide to try a move rather | ||
| * than a swap. | ||
| * @return a random {@link RegionInfo} or null if an asymmetrical move is | ||
| * suggested. | ||
| */ | ||
| int pickRandomRegion(BaseLoadBalancer.Cluster cluster, int server, | ||
| double chanceOfNoSwap) { | ||
| // Check to see if this is just a move. | ||
| if (cluster.regionsPerServer[server].length == 0 | ||
| || StochasticLoadBalancer.RANDOM.nextFloat() < chanceOfNoSwap) { | ||
| // signal a move only. | ||
| return -1; | ||
| } | ||
| int rand = StochasticLoadBalancer.RANDOM.nextInt(cluster.regionsPerServer[server].length); | ||
| return cluster.regionsPerServer[server][rand]; | ||
| } | ||
|
|
||
| int pickRandomServer(BaseLoadBalancer.Cluster cluster) { | ||
| if (cluster.numServers < 1) { | ||
| return -1; | ||
| } | ||
|
|
||
| return StochasticLoadBalancer.RANDOM.nextInt(cluster.numServers); | ||
| } | ||
|
|
||
| int pickRandomRack(BaseLoadBalancer.Cluster cluster) { | ||
| if (cluster.numRacks < 1) { | ||
| return -1; | ||
| } | ||
|
|
||
| return StochasticLoadBalancer.RANDOM.nextInt(cluster.numRacks); | ||
| } | ||
|
|
||
| int pickOtherRandomServer(BaseLoadBalancer.Cluster cluster, int serverIndex) { | ||
| if (cluster.numServers < 2) { | ||
| return -1; | ||
| } | ||
| while (true) { | ||
| int otherServerIndex = pickRandomServer(cluster); | ||
| if (otherServerIndex != serverIndex) { | ||
| return otherServerIndex; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| int pickOtherRandomRack(BaseLoadBalancer.Cluster cluster, int rackIndex) { | ||
| if (cluster.numRacks < 2) { | ||
| return -1; | ||
| } | ||
| while (true) { | ||
| int otherRackIndex = pickRandomRack(cluster); | ||
| if (otherRackIndex != rackIndex) { | ||
| return otherRackIndex; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| BaseLoadBalancer.Cluster.Action pickRandomRegions(BaseLoadBalancer.Cluster cluster, | ||
| int thisServer, int otherServer) { | ||
| if (thisServer < 0 || otherServer < 0) { | ||
| return BaseLoadBalancer.Cluster.NullAction; | ||
| } | ||
|
|
||
| // Decide who is most likely to need another region | ||
| int thisRegionCount = cluster.getNumRegions(thisServer); | ||
| int otherRegionCount = cluster.getNumRegions(otherServer); | ||
|
|
||
| // Assign the chance based upon the above | ||
| double thisChance = (thisRegionCount > otherRegionCount) ? 0 : 0.5; | ||
| double otherChance = (thisRegionCount <= otherRegionCount) ? 0 : 0.5; | ||
|
|
||
| int thisRegion = pickRandomRegion(cluster, thisServer, thisChance); | ||
| int otherRegion = pickRandomRegion(cluster, otherServer, otherChance); | ||
|
|
||
| return getAction(thisServer, thisRegion, otherServer, otherRegion); | ||
| } | ||
|
|
||
| protected BaseLoadBalancer.Cluster.Action getAction(int fromServer, int fromRegion, | ||
| int toServer, int toRegion) { | ||
| if (fromServer < 0 || toServer < 0) { | ||
| return BaseLoadBalancer.Cluster.NullAction; | ||
| } | ||
| if (fromRegion > 0 && toRegion > 0) { | ||
| return new BaseLoadBalancer.Cluster.SwapRegionsAction(fromServer, fromRegion, | ||
| toServer, toRegion); | ||
| } else if (fromRegion > 0) { | ||
| return new BaseLoadBalancer.Cluster.MoveRegionAction(fromRegion, fromServer, toServer); | ||
| } else if (toRegion > 0) { | ||
| return new BaseLoadBalancer.Cluster.MoveRegionAction(toRegion, toServer, fromServer); | ||
| } else { | ||
| return BaseLoadBalancer.Cluster.NullAction; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Returns a random iteration order of indexes of an array with size length | ||
| */ | ||
| List<Integer> getRandomIterationOrder(int length) { | ||
| ArrayList<Integer> order = new ArrayList<>(length); | ||
| for (int i = 0; i < length; i++) { | ||
| order.add(i); | ||
| } | ||
| Collections.shuffle(order); | ||
| return order; | ||
| } | ||
|
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
60 changes: 60 additions & 0 deletions
60
...-server/src/main/java/org/apache/hadoop/hbase/master/balancer/LoadCandidateGenerator.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package org.apache.hadoop.hbase.master.balancer; | ||
|
|
||
| import org.apache.yetus.audience.InterfaceAudience; | ||
|
|
||
| @InterfaceAudience.Private | ||
| class LoadCandidateGenerator extends CandidateGenerator { | ||
virajjasani marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| @Override | ||
| BaseLoadBalancer.Cluster.Action generate(BaseLoadBalancer.Cluster cluster) { | ||
| cluster.sortServersByRegionCount(); | ||
| int thisServer = pickMostLoadedServer(cluster, -1); | ||
| int otherServer = pickLeastLoadedServer(cluster, thisServer); | ||
| return pickRandomRegions(cluster, thisServer, otherServer); | ||
| } | ||
|
|
||
| private int pickLeastLoadedServer(final BaseLoadBalancer.Cluster cluster, int thisServer) { | ||
| Integer[] servers = cluster.serverIndicesSortedByRegionCount; | ||
|
|
||
| int index = 0; | ||
| while (servers[index] == null || servers[index] == thisServer) { | ||
| index++; | ||
| if (index == servers.length) { | ||
| return -1; | ||
| } | ||
| } | ||
| return servers[index]; | ||
| } | ||
|
|
||
| private int pickMostLoadedServer(final BaseLoadBalancer.Cluster cluster, int thisServer) { | ||
| Integer[] servers = cluster.serverIndicesSortedByRegionCount; | ||
|
|
||
| int index = servers.length - 1; | ||
| while (servers[index] == null || servers[index] == thisServer) { | ||
| index--; | ||
| if (index < 0) { | ||
| return -1; | ||
| } | ||
| } | ||
| return servers[index]; | ||
| } | ||
|
|
||
| } | ||
93 changes: 93 additions & 0 deletions
93
...rc/main/java/org/apache/hadoop/hbase/master/balancer/LocalityBasedCandidateGenerator.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package org.apache.hadoop.hbase.master.balancer; | ||
|
|
||
| import org.apache.hadoop.hbase.master.MasterServices; | ||
|
|
||
| import org.apache.hbase.thirdparty.com.google.common.base.Optional; | ||
|
|
||
| import org.apache.yetus.audience.InterfaceAudience; | ||
|
|
||
| @InterfaceAudience.Private | ||
| class LocalityBasedCandidateGenerator extends CandidateGenerator { | ||
virajjasani marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| private MasterServices masterServices; | ||
|
|
||
| LocalityBasedCandidateGenerator(MasterServices masterServices) { | ||
| this.masterServices = masterServices; | ||
| } | ||
|
|
||
| @Override | ||
| BaseLoadBalancer.Cluster.Action generate(BaseLoadBalancer.Cluster cluster) { | ||
| if (this.masterServices == null) { | ||
| int thisServer = pickRandomServer(cluster); | ||
| // Pick the other server | ||
| int otherServer = pickOtherRandomServer(cluster, thisServer); | ||
| return pickRandomRegions(cluster, thisServer, otherServer); | ||
| } | ||
|
|
||
| // Randomly iterate through regions until you find one that is not on ideal host | ||
| for (int region : getRandomIterationOrder(cluster.numRegions)) { | ||
| int currentServer = cluster.regionIndexToServerIndex[region]; | ||
| if (currentServer != cluster.getOrComputeRegionsToMostLocalEntities( | ||
| BaseLoadBalancer.Cluster.LocalityType.SERVER)[region]) { | ||
| Optional<BaseLoadBalancer.Cluster.Action> potential = tryMoveOrSwap(cluster, | ||
| currentServer, region, | ||
| cluster.getOrComputeRegionsToMostLocalEntities( | ||
| BaseLoadBalancer.Cluster.LocalityType.SERVER)[region] | ||
| ); | ||
| if (potential.isPresent()) { | ||
| return potential.get(); | ||
| } | ||
| } | ||
| } | ||
| return BaseLoadBalancer.Cluster.NullAction; | ||
| } | ||
|
|
||
| private Optional<BaseLoadBalancer.Cluster.Action> tryMoveOrSwap(BaseLoadBalancer.Cluster cluster, | ||
| int fromServer, int fromRegion, int toServer) { | ||
| // Try move first. We know apriori fromRegion has the highest locality on toServer | ||
| if (cluster.serverHasTooFewRegions(toServer)) { | ||
| return Optional.of(getAction(fromServer, fromRegion, toServer, -1)); | ||
| } | ||
| // Compare locality gain/loss from swapping fromRegion with regions on toServer | ||
| double fromRegionLocalityDelta = getWeightedLocality(cluster, fromRegion, toServer) | ||
| - getWeightedLocality(cluster, fromRegion, fromServer); | ||
| for (int toRegionIndex : getRandomIterationOrder(cluster.regionsPerServer[toServer].length)) { | ||
| int toRegion = cluster.regionsPerServer[toServer][toRegionIndex]; | ||
| double toRegionLocalityDelta = getWeightedLocality(cluster, toRegion, fromServer) | ||
| - getWeightedLocality(cluster, toRegion, toServer); | ||
| // If locality would remain neutral or improve, attempt the swap | ||
| if (fromRegionLocalityDelta + toRegionLocalityDelta >= 0) { | ||
| return Optional.of(getAction(fromServer, fromRegion, toServer, toRegion)); | ||
| } | ||
| } | ||
| return Optional.absent(); | ||
| } | ||
|
|
||
| private double getWeightedLocality(BaseLoadBalancer.Cluster cluster, int region, int server) { | ||
| return cluster.getOrComputeWeightedLocality(region, server, | ||
| BaseLoadBalancer.Cluster.LocalityType.SERVER); | ||
| } | ||
|
|
||
| void setServices(MasterServices services) { | ||
| this.masterServices = services; | ||
| } | ||
|
|
||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.