Search in sources :

Example 6 with FavoredNodeAssignmentHelper

use of org.apache.hadoop.hbase.favored.FavoredNodeAssignmentHelper in project hbase by apache.

the class FavoredStochasticBalancer method randomAssignment.

/**
 * If we have favored nodes for a region, we will return one of the FN as destination. If
 * favored nodes are not present for a region, we will generate and return one of the FN as
 * destination. If we can't generate anything, lets fallback.
 */
@Override
public ServerName randomAssignment(RegionInfo regionInfo, List<ServerName> servers) throws HBaseIOException {
    ServerName destination = null;
    if (!FavoredNodesManager.isFavoredNodeApplicable(regionInfo)) {
        return super.randomAssignment(regionInfo, servers);
    }
    metricsBalancer.incrMiscInvocations();
    Configuration conf = getConf();
    List<ServerName> favoredNodes = fnm.getFavoredNodes(regionInfo);
    if (favoredNodes == null || favoredNodes.isEmpty()) {
        // Generate new favored nodes and return primary
        FavoredNodeAssignmentHelper helper = new FavoredNodeAssignmentHelper(servers, conf);
        helper.initialize();
        try {
            favoredNodes = helper.generateFavoredNodes(regionInfo);
            updateFavoredNodesForRegion(regionInfo, favoredNodes);
        } catch (IOException e) {
            LOG.warn("Encountered exception while doing favored-nodes (random)assignment " + e);
            throw new HBaseIOException(e);
        }
    }
    List<ServerName> onlineServers = getOnlineFavoredNodes(servers, favoredNodes);
    if (onlineServers.size() > 0) {
        destination = onlineServers.get(ThreadLocalRandom.current().nextInt(onlineServers.size()));
    }
    boolean alwaysAssign = conf.getBoolean(FAVORED_ALWAYS_ASSIGN_REGIONS, true);
    if (destination == null && alwaysAssign) {
        LOG.warn("Can't generate FN for region: " + regionInfo + " falling back");
        destination = super.randomAssignment(regionInfo, servers);
    }
    return destination;
}
Also used : Configuration(org.apache.hadoop.conf.Configuration) FavoredNodeAssignmentHelper(org.apache.hadoop.hbase.favored.FavoredNodeAssignmentHelper) HBaseIOException(org.apache.hadoop.hbase.HBaseIOException) ServerName(org.apache.hadoop.hbase.ServerName) IOException(java.io.IOException) HBaseIOException(org.apache.hadoop.hbase.HBaseIOException)

Example 7 with FavoredNodeAssignmentHelper

use of org.apache.hadoop.hbase.favored.FavoredNodeAssignmentHelper in project hbase by apache.

the class RegionPlacementMaintainer method genAssignmentPlan.

/**
 * Generate the assignment plan for the existing table
 *
 * @param tableName
 * @param assignmentSnapshot
 * @param regionLocalityMap
 * @param plan
 * @param munkresForSecondaryAndTertiary if set on true the assignment plan
 * for the tertiary and secondary will be generated with Munkres algorithm,
 * otherwise will be generated using placeSecondaryAndTertiaryRS
 * @throws IOException
 */
private void genAssignmentPlan(TableName tableName, SnapshotOfRegionAssignmentFromMeta assignmentSnapshot, Map<String, Map<String, Float>> regionLocalityMap, FavoredNodesPlan plan, boolean munkresForSecondaryAndTertiary) throws IOException {
    // Get the all the regions for the current table
    List<RegionInfo> regions = assignmentSnapshot.getTableToRegionMap().get(tableName);
    int numRegions = regions.size();
    // Get the current assignment map
    Map<RegionInfo, ServerName> currentAssignmentMap = assignmentSnapshot.getRegionToRegionServerMap();
    // Get the all the region servers
    List<ServerName> servers = new ArrayList<>();
    servers.addAll(FutureUtils.get(getConnection().getAdmin().getRegionServers()));
    LOG.info("Start to generate assignment plan for " + numRegions + " regions from table " + tableName + " with " + servers.size() + " region servers");
    int slotsPerServer = (int) Math.ceil((float) numRegions / servers.size());
    int regionSlots = slotsPerServer * servers.size();
    // Compute the primary, secondary and tertiary costs for each region/server
    // pair. These costs are based only on node locality and rack locality, and
    // will be modified later.
    float[][] primaryCost = new float[numRegions][regionSlots];
    float[][] secondaryCost = new float[numRegions][regionSlots];
    float[][] tertiaryCost = new float[numRegions][regionSlots];
    if (this.enforceLocality && regionLocalityMap != null) {
        // Transform the locality mapping into a 2D array, assuming that any
        // unspecified locality value is 0.
        float[][] localityPerServer = new float[numRegions][regionSlots];
        for (int i = 0; i < numRegions; i++) {
            Map<String, Float> serverLocalityMap = regionLocalityMap.get(regions.get(i).getEncodedName());
            if (serverLocalityMap == null) {
                continue;
            }
            for (int j = 0; j < servers.size(); j++) {
                String serverName = servers.get(j).getHostname();
                if (serverName == null) {
                    continue;
                }
                Float locality = serverLocalityMap.get(serverName);
                if (locality == null) {
                    continue;
                }
                for (int k = 0; k < slotsPerServer; k++) {
                    // If we can't find the locality of a region to a server, which occurs
                    // because locality is only reported for servers which have some
                    // blocks of a region local, then the locality for that pair is 0.
                    localityPerServer[i][j * slotsPerServer + k] = locality.floatValue();
                }
            }
        }
        // Compute the total rack locality for each region in each rack. The total
        // rack locality is the sum of the localities of a region on all servers in
        // a rack.
        Map<String, Map<RegionInfo, Float>> rackRegionLocality = new HashMap<>();
        for (int i = 0; i < numRegions; i++) {
            RegionInfo region = regions.get(i);
            for (int j = 0; j < regionSlots; j += slotsPerServer) {
                String rack = rackManager.getRack(servers.get(j / slotsPerServer));
                Map<RegionInfo, Float> rackLocality = rackRegionLocality.get(rack);
                if (rackLocality == null) {
                    rackLocality = new HashMap<>();
                    rackRegionLocality.put(rack, rackLocality);
                }
                Float localityObj = rackLocality.get(region);
                float locality = localityObj == null ? 0 : localityObj.floatValue();
                locality += localityPerServer[i][j];
                rackLocality.put(region, locality);
            }
        }
        for (int i = 0; i < numRegions; i++) {
            for (int j = 0; j < regionSlots; j++) {
                String rack = rackManager.getRack(servers.get(j / slotsPerServer));
                Float totalRackLocalityObj = rackRegionLocality.get(rack).get(regions.get(i));
                float totalRackLocality = totalRackLocalityObj == null ? 0 : totalRackLocalityObj.floatValue();
                // Primary cost aims to favor servers with high node locality and low
                // rack locality, so that secondaries and tertiaries can be chosen for
                // nodes with high rack locality. This might give primaries with
                // slightly less locality at first compared to a cost which only
                // considers the node locality, but should be better in the long run.
                primaryCost[i][j] = 1 - (2 * localityPerServer[i][j] - totalRackLocality);
                // Secondary cost aims to favor servers with high node locality and high
                // rack locality since the tertiary will be chosen from the same rack as
                // the secondary. This could be negative, but that is okay.
                secondaryCost[i][j] = 2 - (localityPerServer[i][j] + totalRackLocality);
                // Tertiary cost is only concerned with the node locality. It will later
                // be restricted to only hosts on the same rack as the secondary.
                tertiaryCost[i][j] = 1 - localityPerServer[i][j];
            }
        }
    }
    if (this.enforceMinAssignmentMove && currentAssignmentMap != null) {
        // a host that is not currently serving the region.
        for (int i = 0; i < numRegions; i++) {
            for (int j = 0; j < servers.size(); j++) {
                ServerName currentAddress = currentAssignmentMap.get(regions.get(i));
                if (currentAddress != null && !currentAddress.equals(servers.get(j))) {
                    for (int k = 0; k < slotsPerServer; k++) {
                        primaryCost[i][j * slotsPerServer + k] += NOT_CURRENT_HOST_PENALTY;
                    }
                }
            }
        }
    }
    // regions and many servers with the max number of regions.
    for (int i = 0; i < numRegions; i++) {
        for (int j = 0; j < regionSlots; j += slotsPerServer) {
            primaryCost[i][j] += LAST_SLOT_COST_PENALTY;
            secondaryCost[i][j] += LAST_SLOT_COST_PENALTY;
            tertiaryCost[i][j] += LAST_SLOT_COST_PENALTY;
        }
    }
    RandomizedMatrix randomizedMatrix = new RandomizedMatrix(numRegions, regionSlots);
    primaryCost = randomizedMatrix.transform(primaryCost);
    int[] primaryAssignment = new MunkresAssignment(primaryCost).solve();
    primaryAssignment = randomizedMatrix.invertIndices(primaryAssignment);
    // and either one of secondary or tertiary.
    for (int i = 0; i < numRegions; i++) {
        int slot = primaryAssignment[i];
        String rack = rackManager.getRack(servers.get(slot / slotsPerServer));
        for (int k = 0; k < servers.size(); k++) {
            if (!rackManager.getRack(servers.get(k)).equals(rack)) {
                continue;
            }
            if (k == slot / slotsPerServer) {
                // Same node, do not place secondary or tertiary here ever.
                for (int m = 0; m < slotsPerServer; m++) {
                    secondaryCost[i][k * slotsPerServer + m] = MAX_COST;
                    tertiaryCost[i][k * slotsPerServer + m] = MAX_COST;
                }
            } else {
                // Same rack, do not place secondary or tertiary here if possible.
                for (int m = 0; m < slotsPerServer; m++) {
                    secondaryCost[i][k * slotsPerServer + m] = AVOID_COST;
                    tertiaryCost[i][k * slotsPerServer + m] = AVOID_COST;
                }
            }
        }
    }
    if (munkresForSecondaryAndTertiary) {
        randomizedMatrix = new RandomizedMatrix(numRegions, regionSlots);
        secondaryCost = randomizedMatrix.transform(secondaryCost);
        int[] secondaryAssignment = new MunkresAssignment(secondaryCost).solve();
        secondaryAssignment = randomizedMatrix.invertIndices(secondaryAssignment);
        // server, but not the same server in that rack.
        for (int i = 0; i < numRegions; i++) {
            int slot = secondaryAssignment[i];
            String rack = rackManager.getRack(servers.get(slot / slotsPerServer));
            for (int k = 0; k < servers.size(); k++) {
                if (k == slot / slotsPerServer) {
                    // Same node, do not place tertiary here ever.
                    for (int m = 0; m < slotsPerServer; m++) {
                        tertiaryCost[i][k * slotsPerServer + m] = MAX_COST;
                    }
                } else {
                    if (rackManager.getRack(servers.get(k)).equals(rack)) {
                        continue;
                    }
                    // Different rack, do not place tertiary here if possible.
                    for (int m = 0; m < slotsPerServer; m++) {
                        tertiaryCost[i][k * slotsPerServer + m] = AVOID_COST;
                    }
                }
            }
        }
        randomizedMatrix = new RandomizedMatrix(numRegions, regionSlots);
        tertiaryCost = randomizedMatrix.transform(tertiaryCost);
        int[] tertiaryAssignment = new MunkresAssignment(tertiaryCost).solve();
        tertiaryAssignment = randomizedMatrix.invertIndices(tertiaryAssignment);
        for (int i = 0; i < numRegions; i++) {
            List<ServerName> favoredServers = new ArrayList<>(FavoredNodeAssignmentHelper.FAVORED_NODES_NUM);
            ServerName s = servers.get(primaryAssignment[i] / slotsPerServer);
            favoredServers.add(ServerName.valueOf(s.getHostname(), s.getPort(), ServerName.NON_STARTCODE));
            s = servers.get(secondaryAssignment[i] / slotsPerServer);
            favoredServers.add(ServerName.valueOf(s.getHostname(), s.getPort(), ServerName.NON_STARTCODE));
            s = servers.get(tertiaryAssignment[i] / slotsPerServer);
            favoredServers.add(ServerName.valueOf(s.getHostname(), s.getPort(), ServerName.NON_STARTCODE));
            // Update the assignment plan
            plan.updateFavoredNodesMap(regions.get(i), favoredServers);
        }
        LOG.info("Generated the assignment plan for " + numRegions + " regions from table " + tableName + " with " + servers.size() + " region servers");
        LOG.info("Assignment plan for secondary and tertiary generated " + "using MunkresAssignment");
    } else {
        Map<RegionInfo, ServerName> primaryRSMap = new HashMap<>();
        for (int i = 0; i < numRegions; i++) {
            primaryRSMap.put(regions.get(i), servers.get(primaryAssignment[i] / slotsPerServer));
        }
        FavoredNodeAssignmentHelper favoredNodeHelper = new FavoredNodeAssignmentHelper(servers, conf);
        favoredNodeHelper.initialize();
        Map<RegionInfo, ServerName[]> secondaryAndTertiaryMap = favoredNodeHelper.placeSecondaryAndTertiaryWithRestrictions(primaryRSMap);
        for (int i = 0; i < numRegions; i++) {
            List<ServerName> favoredServers = new ArrayList<>(FavoredNodeAssignmentHelper.FAVORED_NODES_NUM);
            RegionInfo currentRegion = regions.get(i);
            ServerName s = primaryRSMap.get(currentRegion);
            favoredServers.add(ServerName.valueOf(s.getHostname(), s.getPort(), ServerName.NON_STARTCODE));
            ServerName[] secondaryAndTertiary = secondaryAndTertiaryMap.get(currentRegion);
            s = secondaryAndTertiary[0];
            favoredServers.add(ServerName.valueOf(s.getHostname(), s.getPort(), ServerName.NON_STARTCODE));
            s = secondaryAndTertiary[1];
            favoredServers.add(ServerName.valueOf(s.getHostname(), s.getPort(), ServerName.NON_STARTCODE));
            // Update the assignment plan
            plan.updateFavoredNodesMap(regions.get(i), favoredServers);
        }
        LOG.info("Generated the assignment plan for " + numRegions + " regions from table " + tableName + " with " + servers.size() + " region servers");
        LOG.info("Assignment plan for secondary and tertiary generated " + "using placeSecondaryAndTertiaryWithRestrictions method");
    }
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) RegionInfo(org.apache.hadoop.hbase.client.RegionInfo) MunkresAssignment(org.apache.hadoop.hbase.util.MunkresAssignment) FavoredNodeAssignmentHelper(org.apache.hadoop.hbase.favored.FavoredNodeAssignmentHelper) ServerName(org.apache.hadoop.hbase.ServerName) HashMap(java.util.HashMap) Map(java.util.Map) TreeMap(java.util.TreeMap)

Example 8 with FavoredNodeAssignmentHelper

use of org.apache.hadoop.hbase.favored.FavoredNodeAssignmentHelper in project hbase by apache.

the class TestFavoredStochasticLoadBalancer method testAllFavoredNodesDead.

@Ignore
@Test
public void testAllFavoredNodesDead() throws Exception {
    TableName tableName = TableName.valueOf("testAllFavoredNodesDead");
    TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(tableName).setColumnFamily(ColumnFamilyDescriptorBuilder.of(HConstants.CATALOG_FAMILY)).build();
    admin.createTable(tableDescriptor, Bytes.toBytes("aaa"), Bytes.toBytes("zzz"), REGION_NUM);
    TEST_UTIL.waitTableAvailable(tableName);
    final RegionInfo region = admin.getRegions(tableName).get(0);
    LOG.info("Region that's supposed to be in transition: " + region);
    FavoredNodesManager fnm = master.getFavoredNodesManager();
    List<ServerName> currentFN = fnm.getFavoredNodes(region);
    assertNotNull(currentFN);
    // Lets kill all the RS that are favored nodes for this region.
    stopServersAndWaitUntilProcessed(currentFN);
    final RegionStates regionStates = master.getAssignmentManager().getRegionStates();
    TEST_UTIL.waitFor(10000, new Waiter.Predicate<Exception>() {

        @Override
        public boolean evaluate() throws Exception {
            return regionStates.getRegionState(region).isFailedOpen();
        }
    });
    assertTrue("Region: " + region + " should be RIT", regionStates.getRegionState(region).isFailedOpen());
    // Regenerate FN and assign, everything else should be fine
    List<ServerName> serversForNewFN = Lists.newArrayList();
    for (ServerName sn : admin.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS)).getLiveServerMetrics().keySet()) {
        serversForNewFN.add(ServerName.valueOf(sn.getHostname(), sn.getPort(), NON_STARTCODE));
    }
    FavoredNodeAssignmentHelper helper = new FavoredNodeAssignmentHelper(serversForNewFN, conf);
    helper.initialize();
    for (RegionStateNode regionState : regionStates.getRegionsInTransition()) {
        RegionInfo regionInfo = regionState.getRegionInfo();
        List<ServerName> newFavoredNodes = helper.generateFavoredNodes(regionInfo);
        assertNotNull(newFavoredNodes);
        assertEquals(FavoredNodeAssignmentHelper.FAVORED_NODES_NUM, newFavoredNodes.size());
        LOG.info("Region: " + regionInfo.getEncodedName() + " FN: " + newFavoredNodes);
        Map<RegionInfo, List<ServerName>> regionFNMap = Maps.newHashMap();
        regionFNMap.put(regionInfo, newFavoredNodes);
        fnm.updateFavoredNodes(regionFNMap);
        LOG.info("Assigning region: " + regionInfo.getEncodedName());
        admin.assign(regionInfo.getEncodedNameAsBytes());
    }
    TEST_UTIL.waitUntilNoRegionsInTransition(60000);
    assertEquals("Not all regions are online", REGION_NUM, admin.getRegions(tableName).size());
    admin.balancerSwitch(true, true);
    assertTrue("Balancer did not run", admin.balance());
    TEST_UTIL.waitUntilNoRegionsInTransition(60000);
    checkFavoredNodeAssignments(tableName, fnm, regionStates);
}
Also used : FavoredNodesManager(org.apache.hadoop.hbase.favored.FavoredNodesManager) RegionInfo(org.apache.hadoop.hbase.client.RegionInfo) TableDescriptor(org.apache.hadoop.hbase.client.TableDescriptor) IOException(java.io.IOException) RegionStateNode(org.apache.hadoop.hbase.master.assignment.RegionStateNode) TableName(org.apache.hadoop.hbase.TableName) RegionStates(org.apache.hadoop.hbase.master.assignment.RegionStates) FavoredNodeAssignmentHelper(org.apache.hadoop.hbase.favored.FavoredNodeAssignmentHelper) ServerName(org.apache.hadoop.hbase.ServerName) List(java.util.List) Waiter(org.apache.hadoop.hbase.Waiter) Ignore(org.junit.Ignore) Test(org.junit.Test)

Aggregations

ServerName (org.apache.hadoop.hbase.ServerName)8 FavoredNodeAssignmentHelper (org.apache.hadoop.hbase.favored.FavoredNodeAssignmentHelper)8 RegionInfo (org.apache.hadoop.hbase.client.RegionInfo)7 IOException (java.io.IOException)6 List (java.util.List)6 ArrayList (java.util.ArrayList)4 HashMap (java.util.HashMap)4 Map (java.util.Map)3 HBaseIOException (org.apache.hadoop.hbase.HBaseIOException)3 TableName (org.apache.hadoop.hbase.TableName)3 Waiter (org.apache.hadoop.hbase.Waiter)3 TableDescriptor (org.apache.hadoop.hbase.client.TableDescriptor)3 FavoredNodesManager (org.apache.hadoop.hbase.favored.FavoredNodesManager)3 RegionStates (org.apache.hadoop.hbase.master.assignment.RegionStates)3 Ignore (org.junit.Ignore)3 Test (org.junit.Test)3 NonNull (edu.umd.cs.findbugs.annotations.NonNull)2 Configuration (org.apache.hadoop.conf.Configuration)2 RegionStateNode (org.apache.hadoop.hbase.master.assignment.RegionStateNode)2 HashSet (java.util.HashSet)1