You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by li...@apache.org on 2013/04/24 20:18:14 UTC
svn commit: r1471579 - in
/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master:
AssignmentPlan.java RegionPlacement.java
Author: liyin
Date: Wed Apr 24 18:18:13 2013
New Revision: 1471579
URL: http://svn.apache.org/r1471579
Log:
[Master] Rack expansion (expanding existing regions to one new rack)
Author: adela
Summary: We are moving only a number of tertiaries from the old racks to a new rack
Test Plan: run the tool and check
Reviewers: liyintang
Reviewed By: liyintang
CC: hbase-eng@
Differential Revision: https://phabricator.fb.com/D626932
Task ID: 735404
Modified:
hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/AssignmentPlan.java
hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacement.java
Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/AssignmentPlan.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/AssignmentPlan.java?rev=1471579&r1=1471578&r2=1471579&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/AssignmentPlan.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/AssignmentPlan.java Wed Apr 24 18:18:13 2013
@@ -209,8 +209,8 @@ public class AssignmentPlan implements W
int version = in.readInt();
if (version != VERSION) {
throw new IOException("The version mismatch for the assignment plan. " +
- "The expected versioin is " + VERSION +
- " but the verion from the assigment plan is " + version);
+ "The expected versioin is " + VERSION +
+ " but the verion from the assigment plan is " + version);
}
// read the favoredAssignmentMap size
int assignmentMapSize = in.readInt();
@@ -265,17 +265,45 @@ public class AssignmentPlan implements W
return true;
}
- public static AssignmentPlan.POSITION getFavoredServerPosition(
- List<HServerAddress> favoredNodes, HServerAddress server) {
- if (favoredNodes == null || server == null ||
- favoredNodes.size() != HConstants.FAVORED_NODES_NUM) {
- return null;
- }
- for (AssignmentPlan.POSITION p : AssignmentPlan.POSITION.values()) {
- if (favoredNodes.get(p.ordinal()).equals(server)) {
- return p;
- }
- }
- return null;
- }
+ /**
+ * Returns the position of the passed server in the list of favored nodes (the
+ * position can be primary, secondary or tertiary)
+ *
+ * @param favoredNodes
+ * @param server
+ * @return
+ */
+ public static AssignmentPlan.POSITION getFavoredServerPosition(
+ List<HServerAddress> favoredNodes, HServerAddress server) {
+ if (favoredNodes == null || server == null ||
+ favoredNodes.size() != HConstants.FAVORED_NODES_NUM) {
+ return null;
+ }
+ for (AssignmentPlan.POSITION p : AssignmentPlan.POSITION.values()) {
+ if (favoredNodes.get(p.ordinal()).equals(server)) {
+ return p;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Replaces a server on the specified position (primary, secondary or
+ * tertiary) in the list of favored nodes with a new one.
+ *
+ * @param favoredNodes
+ * @param posOfReplacement
+ * @param newServer
+ * @return
+ */
+ public static boolean replaceFavoredNodesServerWithNew(
+ List<HServerAddress> favoredNodes, POSITION posOfReplacement,
+ HServerAddress newServer) {
+ if (favoredNodes == null || newServer == null
+ || favoredNodes.size() != HConstants.FAVORED_NODES_NUM) {
+ return false;
+ }
+ favoredNodes.set(posOfReplacement.ordinal(), newServer);
+ return true;
+ }
}
Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacement.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacement.java?rev=1471579&r1=1471578&r2=1471579&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacement.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/master/RegionPlacement.java Wed Apr 24 18:18:13 2013
@@ -33,6 +33,7 @@ import org.apache.hadoop.hbase.client.HC
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.ipc.HRegionInterface;
+import org.apache.hadoop.hbase.master.AssignmentPlan.POSITION;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.FSUtils;
import org.apache.hadoop.hbase.util.MunkresAssignment;
@@ -486,6 +487,190 @@ public class RegionPlacement implements
}
/**
+ * Makes expansion on the new rack by migrating a number of regions from each
+ * of the existing racks to a new rack. Assumption: the assignment domain will
+ * contain information that the newly added rack is there (but no regions are
+ * assigned to it).
+ *
+ */
+ public void expandRegionsToNewRack(String newRack,
+ RegionAssignmentSnapshot assignmentSnapshot) throws IOException {
+ AssignmentPlan plan = assignmentSnapshot.getExistingAssignmentPlan();
+ AssignmentDomain domain = assignmentSnapshot.getGlobalAssignmentDomain();
+ Map<HServerAddress, List<HRegionInfo>> mapServerToRegions = assignmentSnapshot
+ .getRegionServerToRegionMap();
+ Map<String, List<HServerAddress>> mapRackToRegionServers = domain
+ .getRackToRegionServerMap();
+
+ int avgRegionsPerRs = calculateAvgRegionsPerRS(mapServerToRegions);
+ if (avgRegionsPerRs == 0) {
+ System.out
+ .println("ERROR: average number of regions per regionserver is ZERO, ABORTING!");
+ return;
+ }
+
+ // because the domain knows about the newly added rack we subtract 1.
+ int totalNumRacks = domain.getTotalRackNum() - 1;
+ int numServersNewRack = domain.getRackToRegionServerMap().get(newRack)
+ .size();
+ int moveRegionsPerRack = (int) Math.floor(avgRegionsPerRs
+ * numServersNewRack / totalNumRacks);
+ List<HRegionInfo> regionsToMove = new ArrayList<HRegionInfo>();
+ for (String rack : mapRackToRegionServers.keySet()) {
+ if (!rack.equals(newRack)) {
+ List<HRegionInfo> regionsToMoveFromRack = pickRegionsFromRack(plan,
+ mapRackToRegionServers.get(rack), mapServerToRegions, rack,
+ moveRegionsPerRack, newRack);
+ if (regionsToMoveFromRack.size() == 0) {
+ System.out
+ .println("WARNING: number of regions to be moved from rack "
+ + rack + " is zero!");
+ }
+ regionsToMove.addAll(regionsToMoveFromRack);
+ }
+ }
+ moveRegionsToNewRack(plan, domain, regionsToMove, newRack);
+ }
+
+ /**
+ * This method will pick regions from a given rack, such that these regions
+ * are going to be moved to the new rack later. The logic behind is: we move
+ * the regions' tertiaries into a new rack
+ *
+ * @param plan - the current assignment plan
+ * @param regionServersFromOneRack - region servers that belong to the given
+ * rack
+ * @param mapServerToRegions map contains the mapping from a region server to
+ * it's regions
+ * @param currentRack
+ * @param moveRegionsPerRack - how many regions we want to move per rack
+ * @param newRack - the new rack where we will move the tertiaries
+ * @return a complete list of regions that are going to be moved in the new
+ * rack
+ */
+ private List<HRegionInfo> pickRegionsFromRack(AssignmentPlan plan,
+ List<HServerAddress> regionServersFromOneRack,
+ Map<HServerAddress, List<HRegionInfo>> mapServerToRegions,
+ String currentRack, int moveRegionsPerRack, String newRack) {
+ // we want to move equal number of tertiaries per server
+ List<HRegionInfo> regionsToMove = new ArrayList<HRegionInfo>();
+ System.out.println("------------------------------------------");
+ System.out.println("Printing how many regions are planned to be moved per regionserver in rack " + currentRack);
+ // use Math.ceil to ensure that we move at least one region from some of the RS
+ // if we should move a number of regions smaller than the total number of
+ // servers in the rack
+ int movePerServer = (int) Math.ceil(moveRegionsPerRack
+ / regionServersFromOneRack.size());
+ int totalMovedPerRack = 0;
+ int serverIndex = 0;
+ for (serverIndex = 0; serverIndex < regionServersFromOneRack.size(); serverIndex++) {
+ HServerAddress server = regionServersFromOneRack.get(serverIndex);
+ int totalMovedPerRs = 0;
+ // get all the regions on this server
+ List<HRegionInfo> regions = mapServerToRegions.get(server);
+ for (HRegionInfo region : regions) {
+ List<HServerAddress> favoredNodes = plan.getAssignment(region);
+ if (favoredNodes.size() != HConstants.FAVORED_NODES_NUM) {
+ System.out.println("WARNING!!! Number of favored nodes for region "
+ + region.getEncodedName() + " is not "
+ + HConstants.FAVORED_NODES_NUM);
+ }
+ regionsToMove.add(region);
+ totalMovedPerRs++;
+ totalMovedPerRack++;
+ if (totalMovedPerRs == movePerServer
+ || totalMovedPerRack == moveRegionsPerRack)
+ break;
+ }
+ System.out.println(totalMovedPerRs + " tertiary regions from RS "
+ + regionServersFromOneRack.get(serverIndex).getHostname()
+ + " will be moved to a new rack");
+ if (totalMovedPerRack == moveRegionsPerRack)
+ break;
+ }
+ while (serverIndex < regionServersFromOneRack.size()) {
+ System.out.println("0 tertiary regions from RS "
+ + regionServersFromOneRack.get(serverIndex).getHostname()
+ + " will be moved to a new rack");
+ serverIndex++;
+ }
+ System.out.println("Total number of regions: " + totalMovedPerRack
+ + " in rack " + currentRack + " will move its tertiary to a new rack: "
+ + newRack);
+ System.out.println("------------------------------------------");
+ return regionsToMove;
+ }
+
+ /**
+ * Returns the average number of regions per regionserver
+ *
+ * @param mapServerToRegions
+ * @return
+ */
+ private int calculateAvgRegionsPerRS(
+ Map<HServerAddress, List<HRegionInfo>> mapServerToRegions) {
+ int totalRegions = 0;
+ int totalRS = 0;
+ for (Entry<HServerAddress, List<HRegionInfo>> entry : mapServerToRegions
+ .entrySet()) {
+ if (entry.getKey() != null && entry.getKey() != null) {
+ totalRegions += entry.getValue().size();
+ totalRS++;
+ }
+ }
+ return (int) Math.floor(totalRegions / totalRS);
+ }
+
+ /**
+ *
+ * Move the regions to the new rack, such that each server will get equal
+ * number of regions
+ *
+ * @param plan - the current assignment plan
+ * @param domain - the assignment domain
+ * @param regionsToMove - the regions that would be moved to the new rack
+ * regionserver per rack are picked to be moved in the new rack
+ * @param newRack - the new rack
+ * @throws IOException
+ */
+ private void moveRegionsToNewRack(AssignmentPlan plan,
+ AssignmentDomain domain, List<HRegionInfo> regionsToMove, String newRack)
+ throws IOException {
+ System.out.println("------------------------------------------");
+ System.out
+ .println("Printing how many regions are planned to be assigned per region server in the new rack (" + newRack + ")");
+ List<HServerAddress> serversFromNewRack = domain
+ .getServersFromRack(newRack);
+ int totalNumRSNewRack = serversFromNewRack.size();
+ for (int j = 0; j < totalNumRSNewRack; j++) {
+ int regionsPerRs = 0;
+ for (int i = j; i < regionsToMove.size(); i += totalNumRSNewRack) {
+ HRegionInfo region = regionsToMove.get(i);
+ List<HServerAddress> favoredNodes = plan.getAssignment(region);
+ if (AssignmentPlan.replaceFavoredNodesServerWithNew(favoredNodes,
+ POSITION.TERTIARY, serversFromNewRack.get(j))) {
+ plan.updateAssignmentPlan(region, favoredNodes);
+
+ }
+ regionsPerRs++;
+ }
+ System.out.println("RS: " + serversFromNewRack.get(j).getHostname()
+ + " got " + regionsPerRs + "tertiary regions");
+ }
+ System.out
+ .println("Do you want to update the assignment plan with this changes (y/n): ");
+ Scanner s = new Scanner(System.in);
+ String input = s.nextLine().trim();
+ s.close();
+ if (input.toLowerCase().equals("y")) {
+ System.out.println("Updating assignment plan...");
+ updateAssignmentPlanToMeta(plan);
+ updateAssignmentPlanToRegionServers(plan);
+ } else {
+ System.out.println("exiting without updating the assignment plan");
+ }
+ }
+ /**
* Generate the assignment plan for the existing table
*
* @param tableName
@@ -1071,7 +1256,7 @@ public class RegionPlacement implements
// Set all the options
Options opt = new Options();
opt.addOption("w", "write", false, "write the assignments to META only");
- opt.addOption("u", "update", false,
+ opt.addOption("u", "update", false,
"update the assignments to META and RegionServers together");
opt.addOption("n", "dry-run", false, "do not write assignments to META");
opt.addOption("v", "verify", false, "verify current assignments against META");
@@ -1079,14 +1264,14 @@ public class RegionPlacement implements
opt.addOption("h", "help", false, "print usage");
opt.addOption("d", "verification-details", false,
"print the details of verification report");
-
+
opt.addOption("zk", true, "to set the zookeeper quorum");
opt.addOption("fs", true, "to set HDFS");
opt.addOption("hbase_root", true, "to set hbase_root directory");
-
+
opt.addOption("overwrite", false,
- "overwrite the favored nodes for a single region," +
- "for example: -update -r regionName -f server1:port,server2:port,server3:port");
+ "overwrite the favored nodes for a single region," +
+ "for example: -update -r regionName -f server1:port,server2:port,server3:port");
opt.addOption("r", true, "The region name that needs to be updated");
opt.addOption("f", true, "The new favored nodes");
@@ -1099,19 +1284,20 @@ public class RegionPlacement implements
opt.addOption("munkres", false,
"use munkres to place secondaries and tertiaries");
opt.addOption("ld", "locality-dispersion", false, "print locality and dispersion information for current plan");
+ opt.addOption("exprack", "expand-with-rack", false, "expand the regions to a new rack");
try {
// Set the log4j
Logger.getLogger("org.apache.zookeeper").setLevel(Level.ERROR);
Logger.getLogger("org.apache.hadoop.hbase").setLevel(Level.ERROR);
- Logger.getLogger("org.apache.hadoop.hbase.master.RegionPlacement").
- setLevel(Level.INFO);
+ Logger.getLogger("org.apache.hadoop.hbase.master.RegionPlacement")
+ .setLevel(Level.INFO);
CommandLine cmd = new GnuParser().parse(opt, args);
Configuration conf = HBaseConfiguration.create();
boolean enforceMinAssignmentMove = true;
boolean enforceLocality = true;
- boolean verificationDetails =false;
+ boolean verificationDetails = false;
// Read all the options
if ((cmd.hasOption("l") &&
@@ -1132,17 +1318,17 @@ public class RegionPlacement implements
conf.set(HConstants.ZOOKEEPER_QUORUM, cmd.getOptionValue("zk"));
LOG.info("Setting the zk quorum: " + conf.get(HConstants.ZOOKEEPER_QUORUM));
}
-
+
if (cmd.hasOption("fs")) {
conf.set(FileSystem.FS_DEFAULT_NAME_KEY, cmd.getOptionValue("fs"));
LOG.info("Setting the HDFS: " + conf.get(FileSystem.FS_DEFAULT_NAME_KEY));
}
-
+
if (cmd.hasOption("hbase_root")) {
conf.set(HConstants.HBASE_DIR, cmd.getOptionValue("hbase_root"));
LOG.info("Setting the hbase root directory: " + conf.get(HConstants.HBASE_DIR));
}
-
+
// Create the region placement obj
RegionPlacement rp = new RegionPlacement(conf, enforceLocality,
enforceMinAssignmentMove);
@@ -1176,7 +1362,7 @@ public class RegionPlacement implements
RegionPlacement.printAssignmentPlan(plan);
// Write the new assignment plan to META
rp.updateAssignmentPlanToMeta(plan);
- } else if (cmd.hasOption("u") || cmd.hasOption("update")) {
+ } else if (cmd.hasOption("u") || cmd.hasOption("update")) {
// Generate the new assignment plan
AssignmentPlan plan = rp.getNewAssignmentPlan();
// Print the new assignment plan
@@ -1216,7 +1402,7 @@ public class RegionPlacement implements
favoredNodesStr);
List<HServerAddress> favoredNodes = null;
HRegionInfo regionInfo =
- rp.getRegionAssignmentSnapshot().getRegionNameToRegionInfoMap().get(regionName);
+ rp.getRegionAssignmentSnapshot().getRegionNameToRegionInfoMap().get(regionName);
if (regionInfo == null) {
LOG.error("Cannot find the region " + regionName + " from the META");
} else {
@@ -1229,6 +1415,24 @@ public class RegionPlacement implements
newPlan.updateAssignmentPlan(regionInfo, favoredNodes);
rp.updateAssignmentPlan(newPlan);
}
+ } else if (cmd.hasOption("exprack")) {
+ RegionAssignmentSnapshot snapshot = rp.getRegionAssignmentSnapshot();
+ AssignmentDomain domain = snapshot.getGlobalAssignmentDomain();
+ System.out.println("List of current racks: ");
+ Set<String> allRacks = domain.getRackToRegionServerMap().keySet();
+ for (String rack : allRacks) {
+ System.out.println("\t"
+ + rack
+ + "\t number of Region Servers: "
+ + snapshot.getGlobalAssignmentDomain().getServersFromRack(rack)
+ .size());
+ }
+ System.out
+ .println("Insert the name of the new rack (to which the migration should be done): ");
+ Scanner s = new Scanner(System.in);
+ String newRack = s.nextLine().trim();
+ s.close();
+ rp.expandRegionsToNewRack(newRack, snapshot);
} else {
printHelp(opt);
}