Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 5DF68200CB4 for ; Tue, 27 Jun 2017 17:01:23 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 5C5DF160C02; Tue, 27 Jun 2017 15:01:23 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id F306A160BE9 for ; Tue, 27 Jun 2017 17:01:20 +0200 (CEST) Received: (qmail 24543 invoked by uid 500); 27 Jun 2017 15:01:20 -0000 Mailing-List: contact commits-help@hbase.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@hbase.apache.org Delivered-To: mailing list commits@hbase.apache.org Received: (qmail 24253 invoked by uid 99); 27 Jun 2017 15:01:19 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 27 Jun 2017 15:01:19 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id E8CEFF16B5; Tue, 27 Jun 2017 15:01:16 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: git-site-role@apache.org To: commits@hbase.apache.org Date: Tue, 27 Jun 2017 15:01:18 -0000 Message-Id: In-Reply-To: <226601fc29d5464ba43fac0105ae50b9@git.apache.org> References: <226601fc29d5464ba43fac0105ae50b9@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [04/51] [partial] hbase-site git commit: Published site at 82d554e3783372cc6b05489452c815b57c06f6cd. archived-at: Tue, 27 Jun 2017 15:01:23 -0000 http://git-wip-us.apache.org/repos/asf/hbase-site/blob/8e3b63ca/devapidocs/src-html/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.RegionReplicaCandidateGenerator.html ---------------------------------------------------------------------- diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.RegionReplicaCandidateGenerator.html b/devapidocs/src-html/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.RegionReplicaCandidateGenerator.html index c895448..545d4da 100644 --- a/devapidocs/src-html/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.RegionReplicaCandidateGenerator.html +++ b/devapidocs/src-html/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.RegionReplicaCandidateGenerator.html @@ -1294,425 +1294,426 @@ 1286 } 1287 1288 // We normalize locality to be a score between 0 and 1.0 representing how good it -1289 // is compared to how good it could be -1290 locality /= bestLocality; -1291 } -1292 -1293 @Override -1294 protected void regionMoved(int region, int oldServer, int newServer) { -1295 int oldEntity = type == LocalityType.SERVER ? oldServer : cluster.serverIndexToRackIndex[oldServer]; -1296 int newEntity = type == LocalityType.SERVER ? newServer : cluster.serverIndexToRackIndex[newServer]; -1297 if (this.services == null) { -1298 return; -1299 } -1300 double localityDelta = getWeightedLocality(region, newEntity) - getWeightedLocality(region, oldEntity); -1301 double normalizedDelta = localityDelta / bestLocality; -1302 locality += normalizedDelta; -1303 } -1304 -1305 @Override -1306 double cost() { -1307 return 1 - locality; -1308 } -1309 -1310 private int getMostLocalEntityForRegion(int region) { -1311 return cluster.getOrComputeRegionsToMostLocalEntities(type)[region]; -1312 } -1313 -1314 private double getWeightedLocality(int region, int entity) { -1315 return cluster.getOrComputeWeightedLocality(region, entity, type); -1316 } -1317 -1318 } -1319 -1320 static class ServerLocalityCostFunction extends LocalityBasedCostFunction { -1321 -1322 private static final String LOCALITY_COST_KEY = "hbase.master.balancer.stochastic.localityCost"; -1323 private static final float DEFAULT_LOCALITY_COST = 25; -1324 -1325 ServerLocalityCostFunction(Configuration conf, MasterServices srv) { -1326 super( -1327 conf, -1328 srv, -1329 LocalityType.SERVER, -1330 LOCALITY_COST_KEY, -1331 DEFAULT_LOCALITY_COST -1332 ); -1333 } -1334 -1335 @Override -1336 int regionIndexToEntityIndex(int region) { -1337 return cluster.regionIndexToServerIndex[region]; -1338 } -1339 } -1340 -1341 static class RackLocalityCostFunction extends LocalityBasedCostFunction { -1342 -1343 private static final String RACK_LOCALITY_COST_KEY = "hbase.master.balancer.stochastic.rackLocalityCost"; -1344 private static final float DEFAULT_RACK_LOCALITY_COST = 15; -1345 -1346 public RackLocalityCostFunction(Configuration conf, MasterServices services) { -1347 super( -1348 conf, -1349 services, -1350 LocalityType.RACK, -1351 RACK_LOCALITY_COST_KEY, -1352 DEFAULT_RACK_LOCALITY_COST -1353 ); -1354 } -1355 -1356 @Override -1357 int regionIndexToEntityIndex(int region) { -1358 return cluster.getRackForRegion(region); -1359 } -1360 } -1361 -1362 /** -1363 * Base class the allows writing costs functions from rolling average of some -1364 * number from RegionLoad. -1365 */ -1366 abstract static class CostFromRegionLoadFunction extends CostFunction { -1367 -1368 private ClusterStatus clusterStatus = null; -1369 private Map<String, Deque<BalancerRegionLoad>> loads = null; -1370 private double[] stats = null; -1371 CostFromRegionLoadFunction(Configuration conf) { -1372 super(conf); -1373 } -1374 -1375 void setClusterStatus(ClusterStatus status) { -1376 this.clusterStatus = status; -1377 } -1378 -1379 void setLoads(Map<String, Deque<BalancerRegionLoad>> l) { -1380 this.loads = l; -1381 } -1382 -1383 @Override -1384 double cost() { -1385 if (clusterStatus == null || loads == null) { -1386 return 0; -1387 } -1388 -1389 if (stats == null || stats.length != cluster.numServers) { -1390 stats = new double[cluster.numServers]; -1391 } -1392 -1393 for (int i =0; i < stats.length; i++) { -1394 //Cost this server has from RegionLoad -1395 long cost = 0; -1396 -1397 // for every region on this server get the rl -1398 for(int regionIndex:cluster.regionsPerServer[i]) { -1399 Collection<BalancerRegionLoad> regionLoadList = cluster.regionLoads[regionIndex]; -1400 -1401 // Now if we found a region load get the type of cost that was requested. -1402 if (regionLoadList != null) { -1403 cost += getRegionLoadCost(regionLoadList); -1404 } -1405 } -1406 -1407 // Add the total cost to the stats. -1408 stats[i] = cost; -1409 } -1410 -1411 // Now return the scaled cost from data held in the stats object. -1412 return costFromArray(stats); -1413 } -1414 -1415 protected double getRegionLoadCost(Collection<BalancerRegionLoad> regionLoadList) { -1416 double cost = 0; -1417 for (BalancerRegionLoad rl : regionLoadList) { -1418 cost += getCostFromRl(rl); -1419 } -1420 return cost / regionLoadList.size(); -1421 } -1422 -1423 protected abstract double getCostFromRl(BalancerRegionLoad rl); -1424 } -1425 -1426 /** -1427 * Class to be used for the subset of RegionLoad costs that should be treated as rates. -1428 * We do not compare about the actual rate in requests per second but rather the rate relative -1429 * to the rest of the regions. -1430 */ -1431 abstract static class CostFromRegionLoadAsRateFunction extends CostFromRegionLoadFunction { -1432 -1433 CostFromRegionLoadAsRateFunction(Configuration conf) { -1434 super(conf); -1435 } -1436 -1437 @Override -1438 protected double getRegionLoadCost(Collection<BalancerRegionLoad> regionLoadList) { -1439 double cost = 0; -1440 double previous = 0; -1441 boolean isFirst = true; -1442 for (BalancerRegionLoad rl : regionLoadList) { -1443 double current = getCostFromRl(rl); -1444 if (isFirst) { -1445 isFirst = false; -1446 } else { -1447 cost += current - previous; -1448 } -1449 previous = current; -1450 } -1451 return Math.max(0, cost / (regionLoadList.size() - 1)); -1452 } -1453 } -1454 -1455 /** -1456 * Compute the cost of total number of read requests The more unbalanced the higher the -1457 * computed cost will be. This uses a rolling average of regionload. -1458 */ -1459 -1460 static class ReadRequestCostFunction extends CostFromRegionLoadAsRateFunction { -1461 -1462 private static final String READ_REQUEST_COST_KEY = -1463 "hbase.master.balancer.stochastic.readRequestCost"; -1464 private static final float DEFAULT_READ_REQUEST_COST = 5; -1465 -1466 ReadRequestCostFunction(Configuration conf) { -1467 super(conf); -1468 this.setMultiplier(conf.getFloat(READ_REQUEST_COST_KEY, DEFAULT_READ_REQUEST_COST)); -1469 } -1470 -1471 @Override -1472 protected double getCostFromRl(BalancerRegionLoad rl) { -1473 return rl.getReadRequestsCount(); -1474 } -1475 } -1476 -1477 /** -1478 * Compute the cost of total number of write requests. The more unbalanced the higher the -1479 * computed cost will be. This uses a rolling average of regionload. -1480 */ -1481 static class WriteRequestCostFunction extends CostFromRegionLoadAsRateFunction { -1482 -1483 private static final String WRITE_REQUEST_COST_KEY = -1484 "hbase.master.balancer.stochastic.writeRequestCost"; -1485 private static final float DEFAULT_WRITE_REQUEST_COST = 5; -1486 -1487 WriteRequestCostFunction(Configuration conf) { -1488 super(conf); -1489 this.setMultiplier(conf.getFloat(WRITE_REQUEST_COST_KEY, DEFAULT_WRITE_REQUEST_COST)); -1490 } -1491 -1492 @Override -1493 protected double getCostFromRl(BalancerRegionLoad rl) { -1494 return rl.getWriteRequestsCount(); -1495 } -1496 } -1497 -1498 /** -1499 * A cost function for region replicas. We give a very high cost to hosting -1500 * replicas of the same region in the same host. We do not prevent the case -1501 * though, since if numReplicas > numRegionServers, we still want to keep the -1502 * replica open. -1503 */ -1504 static class RegionReplicaHostCostFunction extends CostFunction { -1505 private static final String REGION_REPLICA_HOST_COST_KEY = -1506 "hbase.master.balancer.stochastic.regionReplicaHostCostKey"; -1507 private static final float DEFAULT_REGION_REPLICA_HOST_COST_KEY = 100000; -1508 -1509 long maxCost = 0; -1510 long[] costsPerGroup; // group is either server, host or rack -1511 int[][] primariesOfRegionsPerGroup; -1512 -1513 public RegionReplicaHostCostFunction(Configuration conf) { -1514 super(conf); -1515 this.setMultiplier(conf.getFloat(REGION_REPLICA_HOST_COST_KEY, -1516 DEFAULT_REGION_REPLICA_HOST_COST_KEY)); -1517 } -1518 -1519 @Override -1520 void init(Cluster cluster) { -1521 super.init(cluster); -1522 // max cost is the case where every region replica is hosted together regardless of host -1523 maxCost = cluster.numHosts > 1 ? getMaxCost(cluster) : 0; -1524 costsPerGroup = new long[cluster.numHosts]; -1525 primariesOfRegionsPerGroup = cluster.multiServersPerHost // either server based or host based -1526 ? cluster.primariesOfRegionsPerHost -1527 : cluster.primariesOfRegionsPerServer; -1528 for (int i = 0 ; i < primariesOfRegionsPerGroup.length; i++) { -1529 costsPerGroup[i] = costPerGroup(primariesOfRegionsPerGroup[i]); -1530 } -1531 } -1532 -1533 long getMaxCost(Cluster cluster) { -1534 if (!cluster.hasRegionReplicas) { -1535 return 0; // short circuit -1536 } -1537 // max cost is the case where every region replica is hosted together regardless of host -1538 int[] primariesOfRegions = new int[cluster.numRegions]; -1539 System.arraycopy(cluster.regionIndexToPrimaryIndex, 0, primariesOfRegions, 0, -1540 cluster.regions.length); -1541 -1542 Arrays.sort(primariesOfRegions); -1543 -1544 // compute numReplicas from the sorted array -1545 return costPerGroup(primariesOfRegions); -1546 } -1547 -1548 @Override -1549 boolean isNeeded() { -1550 return cluster.hasRegionReplicas; -1551 } -1552 -1553 @Override -1554 double cost() { -1555 if (maxCost <= 0) { -1556 return 0; -1557 } -1558 -1559 long totalCost = 0; -1560 for (int i = 0 ; i < costsPerGroup.length; i++) { -1561 totalCost += costsPerGroup[i]; -1562 } -1563 return scale(0, maxCost, totalCost); -1564 } -1565 -1566 /** -1567 * For each primary region, it computes the total number of replicas in the array (numReplicas) -1568 * and returns a sum of numReplicas-1 squared. For example, if the server hosts -1569 * regions a, b, c, d, e, f where a and b are same replicas, and c,d,e are same replicas, it -1570 * returns (2-1) * (2-1) + (3-1) * (3-1) + (1-1) * (1-1). -1571 * @param primariesOfRegions a sorted array of primary regions ids for the regions hosted -1572 * @return a sum of numReplicas-1 squared for each primary region in the group. -1573 */ -1574 protected long costPerGroup(int[] primariesOfRegions) { -1575 long cost = 0; -1576 int currentPrimary = -1; -1577 int currentPrimaryIndex = -1; -1578 // primariesOfRegions is a sorted array of primary ids of regions. Replicas of regions -1579 // sharing the same primary will have consecutive numbers in the array. -1580 for (int j = 0 ; j <= primariesOfRegions.length; j++) { -1581 int primary = j < primariesOfRegions.length ? primariesOfRegions[j] : -1; -1582 if (primary != currentPrimary) { // we see a new primary -1583 int numReplicas = j - currentPrimaryIndex; -1584 // square the cost -1585 if (numReplicas > 1) { // means consecutive primaries, indicating co-location -1586 cost += (numReplicas - 1) * (numReplicas - 1); -1587 } -1588 currentPrimary = primary; -1589 currentPrimaryIndex = j; -1590 } -1591 } -1592 -1593 return cost; -1594 } -1595 -1596 @Override -1597 protected void regionMoved(int region, int oldServer, int newServer) { -1598 if (maxCost <= 0) { -1599 return; // no need to compute -1600 } -1601 if (cluster.multiServersPerHost) { -1602 int oldHost = cluster.serverIndexToHostIndex[oldServer]; -1603 int newHost = cluster.serverIndexToHostIndex[newServer]; -1604 if (newHost != oldHost) { -1605 costsPerGroup[oldHost] = costPerGroup(cluster.primariesOfRegionsPerHost[oldHost]); -1606 costsPerGroup[newHost] = costPerGroup(cluster.primariesOfRegionsPerHost[newHost]); -1607 } -1608 } else { -1609 costsPerGroup[oldServer] = costPerGroup(cluster.primariesOfRegionsPerServer[oldServer]); -1610 costsPerGroup[newServer] = costPerGroup(cluster.primariesOfRegionsPerServer[newServer]); -1611 } -1612 } -1613 } -1614 -1615 /** -1616 * A cost function for region replicas for the rack distribution. We give a relatively high -1617 * cost to hosting replicas of the same region in the same rack. We do not prevent the case -1618 * though. -1619 */ -1620 static class RegionReplicaRackCostFunction extends RegionReplicaHostCostFunction { -1621 private static final String REGION_REPLICA_RACK_COST_KEY = -1622 "hbase.master.balancer.stochastic.regionReplicaRackCostKey"; -1623 private static final float DEFAULT_REGION_REPLICA_RACK_COST_KEY = 10000; -1624 -1625 public RegionReplicaRackCostFunction(Configuration conf) { -1626 super(conf); -1627 this.setMultiplier(conf.getFloat(REGION_REPLICA_RACK_COST_KEY, -1628 DEFAULT_REGION_REPLICA_RACK_COST_KEY)); -1629 } -1630 -1631 @Override -1632 void init(Cluster cluster) { -1633 this.cluster = cluster; -1634 if (cluster.numRacks <= 1) { -1635 maxCost = 0; -1636 return; // disabled for 1 rack -1637 } -1638 // max cost is the case where every region replica is hosted together regardless of rack -1639 maxCost = getMaxCost(cluster); -1640 costsPerGroup = new long[cluster.numRacks]; -1641 for (int i = 0 ; i < cluster.primariesOfRegionsPerRack.length; i++) { -1642 costsPerGroup[i] = costPerGroup(cluster.primariesOfRegionsPerRack[i]); -1643 } -1644 } -1645 -1646 @Override -1647 protected void regionMoved(int region, int oldServer, int newServer) { -1648 if (maxCost <= 0) { -1649 return; // no need to compute -1650 } -1651 int oldRack = cluster.serverIndexToRackIndex[oldServer]; -1652 int newRack = cluster.serverIndexToRackIndex[newServer]; -1653 if (newRack != oldRack) { -1654 costsPerGroup[oldRack] = costPerGroup(cluster.primariesOfRegionsPerRack[oldRack]); -1655 costsPerGroup[newRack] = costPerGroup(cluster.primariesOfRegionsPerRack[newRack]); -1656 } -1657 } -1658 } -1659 -1660 /** -1661 * Compute the cost of total memstore size. The more unbalanced the higher the -1662 * computed cost will be. This uses a rolling average of regionload. -1663 */ -1664 static class MemstoreSizeCostFunction extends CostFromRegionLoadAsRateFunction { -1665 -1666 private static final String MEMSTORE_SIZE_COST_KEY = -1667 "hbase.master.balancer.stochastic.memstoreSizeCost"; -1668 private static final float DEFAULT_MEMSTORE_SIZE_COST = 5; -1669 -1670 MemstoreSizeCostFunction(Configuration conf) { -1671 super(conf); -1672 this.setMultiplier(conf.getFloat(MEMSTORE_SIZE_COST_KEY, DEFAULT_MEMSTORE_SIZE_COST)); -1673 } -1674 -1675 @Override -1676 protected double getCostFromRl(BalancerRegionLoad rl) { -1677 return rl.getMemStoreSizeMB(); -1678 } -1679 } -1680 /** -1681 * Compute the cost of total open storefiles size. The more unbalanced the higher the -1682 * computed cost will be. This uses a rolling average of regionload. -1683 */ -1684 static class StoreFileCostFunction extends CostFromRegionLoadFunction { -1685 -1686 private static final String STOREFILE_SIZE_COST_KEY = -1687 "hbase.master.balancer.stochastic.storefileSizeCost"; -1688 private static final float DEFAULT_STOREFILE_SIZE_COST = 5; -1689 -1690 StoreFileCostFunction(Configuration conf) { -1691 super(conf); -1692 this.setMultiplier(conf.getFloat(STOREFILE_SIZE_COST_KEY, DEFAULT_STOREFILE_SIZE_COST)); -1693 } -1694 -1695 @Override -1696 protected double getCostFromRl(BalancerRegionLoad rl) { -1697 return rl.getStorefileSizeMB(); -1698 } -1699 } -1700 -1701 /** -1702 * A helper function to compose the attribute name from tablename and costfunction name -1703 */ -1704 public static String composeAttributeName(String tableName, String costFunctionName) { -1705 return tableName + TABLE_FUNCTION_SEP + costFunctionName; -1706 } -1707} +1289 // is compared to how good it could be. If bestLocality is 0, assume locality is 100 +1290 // (and the cost is 0) +1291 locality = bestLocality == 0 ? 1 : locality / bestLocality; +1292 } +1293 +1294 @Override +1295 protected void regionMoved(int region, int oldServer, int newServer) { +1296 int oldEntity = type == LocalityType.SERVER ? oldServer : cluster.serverIndexToRackIndex[oldServer]; +1297 int newEntity = type == LocalityType.SERVER ? newServer : cluster.serverIndexToRackIndex[newServer]; +1298 if (this.services == null) { +1299 return; +1300 } +1301 double localityDelta = getWeightedLocality(region, newEntity) - getWeightedLocality(region, oldEntity); +1302 double normalizedDelta = bestLocality == 0 ? 0.0 : localityDelta / bestLocality; +1303 locality += normalizedDelta; +1304 } +1305 +1306 @Override +1307 double cost() { +1308 return 1 - locality; +1309 } +1310 +1311 private int getMostLocalEntityForRegion(int region) { +1312 return cluster.getOrComputeRegionsToMostLocalEntities(type)[region]; +1313 } +1314 +1315 private double getWeightedLocality(int region, int entity) { +1316 return cluster.getOrComputeWeightedLocality(region, entity, type); +1317 } +1318 +1319 } +1320 +1321 static class ServerLocalityCostFunction extends LocalityBasedCostFunction { +1322 +1323 private static final String LOCALITY_COST_KEY = "hbase.master.balancer.stochastic.localityCost"; +1324 private static final float DEFAULT_LOCALITY_COST = 25; +1325 +1326 ServerLocalityCostFunction(Configuration conf, MasterServices srv) { +1327 super( +1328 conf, +1329 srv, +1330 LocalityType.SERVER, +1331 LOCALITY_COST_KEY, +1332 DEFAULT_LOCALITY_COST +1333 ); +1334 } +1335 +1336 @Override +1337 int regionIndexToEntityIndex(int region) { +1338 return cluster.regionIndexToServerIndex[region]; +1339 } +1340 } +1341 +1342 static class RackLocalityCostFunction extends LocalityBasedCostFunction { +1343 +1344 private static final String RACK_LOCALITY_COST_KEY = "hbase.master.balancer.stochastic.rackLocalityCost"; +1345 private static final float DEFAULT_RACK_LOCALITY_COST = 15; +1346 +1347 public RackLocalityCostFunction(Configuration conf, MasterServices services) { +1348 super( +1349 conf, +1350 services, +1351 LocalityType.RACK, +1352 RACK_LOCALITY_COST_KEY, +1353 DEFAULT_RACK_LOCALITY_COST +1354 ); +1355 } +1356 +1357 @Override +1358 int regionIndexToEntityIndex(int region) { +1359 return cluster.getRackForRegion(region); +1360 } +1361 } +1362 +1363 /** +1364 * Base class the allows writing costs functions from rolling average of some +1365 * number from RegionLoad. +1366 */ +1367 abstract static class CostFromRegionLoadFunction extends CostFunction { +1368 +1369 private ClusterStatus clusterStatus = null; +1370 private Map<String, Deque<BalancerRegionLoad>> loads = null; +1371 private double[] stats = null; +1372 CostFromRegionLoadFunction(Configuration conf) { +1373 super(conf); +1374 } +1375 +1376 void setClusterStatus(ClusterStatus status) { +1377 this.clusterStatus = status; +1378 } +1379 +1380 void setLoads(Map<String, Deque<BalancerRegionLoad>> l) { +1381 this.loads = l; +1382 } +1383 +1384 @Override +1385 double cost() { +1386 if (clusterStatus == null || loads == null) { +1387 return 0; +1388 } +1389 +1390 if (stats == null || stats.length != cluster.numServers) { +1391 stats = new double[cluster.numServers]; +1392 } +1393 +1394 for (int i =0; i < stats.length; i++) { +1395 //Cost this server has from RegionLoad +1396 long cost = 0; +1397 +1398 // for every region on this server get the rl +1399 for(int regionIndex:cluster.regionsPerServer[i]) { +1400 Collection<BalancerRegionLoad> regionLoadList = cluster.regionLoads[regionIndex]; +1401 +1402 // Now if we found a region load get the type of cost that was requested. +1403 if (regionLoadList != null) { +1404 cost += getRegionLoadCost(regionLoadList); +1405 } +1406 } +1407 +1408 // Add the total cost to the stats. +1409 stats[i] = cost; +1410 } +1411 +1412 // Now return the scaled cost from data held in the stats object. +1413 return costFromArray(stats); +1414 } +1415 +1416 protected double getRegionLoadCost(Collection<BalancerRegionLoad> regionLoadList) { +1417 double cost = 0; +1418 for (BalancerRegionLoad rl : regionLoadList) { +1419 cost += getCostFromRl(rl); +1420 } +1421 return cost / regionLoadList.size(); +1422 } +1423 +1424 protected abstract double getCostFromRl(BalancerRegionLoad rl); +1425 } +1426 +1427 /** +1428 * Class to be used for the subset of RegionLoad costs that should be treated as rates. +1429 * We do not compare about the actual rate in requests per second but rather the rate relative +1430 * to the rest of the regions. +1431 */ +1432 abstract static class CostFromRegionLoadAsRateFunction extends CostFromRegionLoadFunction { +1433 +1434 CostFromRegionLoadAsRateFunction(Configuration conf) { +1435 super(conf); +1436 } +1437 +1438 @Override +1439 protected double getRegionLoadCost(Collection<BalancerRegionLoad> regionLoadList) { +1440 double cost = 0; +1441 double previous = 0; +1442 boolean isFirst = true; +1443 for (BalancerRegionLoad rl : regionLoadList) { +1444 double current = getCostFromRl(rl); +1445 if (isFirst) { +1446 isFirst = false; +1447 } else { +1448 cost += current - previous; +1449 } +1450 previous = current; +1451 } +1452 return Math.max(0, cost / (regionLoadList.size() - 1)); +1453 } +1454 } +1455 +1456 /** +1457 * Compute the cost of total number of read requests The more unbalanced the higher the +1458 * computed cost will be. This uses a rolling average of regionload. +1459 */ +1460 +1461 static class ReadRequestCostFunction extends CostFromRegionLoadAsRateFunction { +1462 +1463 private static final String READ_REQUEST_COST_KEY = +1464 "hbase.master.balancer.stochastic.readRequestCost"; +1465 private static final float DEFAULT_READ_REQUEST_COST = 5; +1466 +1467 ReadRequestCostFunction(Configuration conf) { +1468 super(conf); +1469 this.setMultiplier(conf.getFloat(READ_REQUEST_COST_KEY, DEFAULT_READ_REQUEST_COST)); +1470 } +1471 +1472 @Override +1473 protected double getCostFromRl(BalancerRegionLoad rl) { +1474 return rl.getReadRequestsCount(); +1475 } +1476 } +1477 +1478 /** +1479 * Compute the cost of total number of write requests. The more unbalanced the higher the +1480 * computed cost will be. This uses a rolling average of regionload. +1481 */ +1482 static class WriteRequestCostFunction extends CostFromRegionLoadAsRateFunction { +1483 +1484 private static final String WRITE_REQUEST_COST_KEY = +1485 "hbase.master.balancer.stochastic.writeRequestCost"; +1486 private static final float DEFAULT_WRITE_REQUEST_COST = 5; +1487 +1488 WriteRequestCostFunction(Configuration conf) { +1489 super(conf); +1490 this.setMultiplier(conf.getFloat(WRITE_REQUEST_COST_KEY, DEFAULT_WRITE_REQUEST_COST)); +1491 } +1492 +1493 @Override +1494 protected double getCostFromRl(BalancerRegionLoad rl) { +1495 return rl.getWriteRequestsCount(); +1496 } +1497 } +1498 +1499 /** +1500 * A cost function for region replicas. We give a very high cost to hosting +1501 * replicas of the same region in the same host. We do not prevent the case +1502 * though, since if numReplicas > numRegionServers, we still want to keep the +1503 * replica open. +1504 */ +1505 static class RegionReplicaHostCostFunction extends CostFunction { +1506 private static final String REGION_REPLICA_HOST_COST_KEY = +1507 "hbase.master.balancer.stochastic.regionReplicaHostCostKey"; +1508 private static final float DEFAULT_REGION_REPLICA_HOST_COST_KEY = 100000; +1509 +1510 long maxCost = 0; +1511 long[] costsPerGroup; // group is either server, host or rack +1512 int[][] primariesOfRegionsPerGroup; +1513 +1514 public RegionReplicaHostCostFunction(Configuration conf) { +1515 super(conf); +1516 this.setMultiplier(conf.getFloat(REGION_REPLICA_HOST_COST_KEY, +1517 DEFAULT_REGION_REPLICA_HOST_COST_KEY)); +1518 } +1519 +1520 @Override +1521 void init(Cluster cluster) { +1522 super.init(cluster); +1523 // max cost is the case where every region replica is hosted together regardless of host +1524 maxCost = cluster.numHosts > 1 ? getMaxCost(cluster) : 0; +1525 costsPerGroup = new long[cluster.numHosts]; +1526 primariesOfRegionsPerGroup = cluster.multiServersPerHost // either server based or host based +1527 ? cluster.primariesOfRegionsPerHost +1528 : cluster.primariesOfRegionsPerServer; +1529 for (int i = 0 ; i < primariesOfRegionsPerGroup.length; i++) { +1530 costsPerGroup[i] = costPerGroup(primariesOfRegionsPerGroup[i]); +1531 } +1532 } +1533 +1534 long getMaxCost(Cluster cluster) { +1535 if (!cluster.hasRegionReplicas) { +1536 return 0; // short circuit +1537 } +1538 // max cost is the case where every region replica is hosted together regardless of host +1539 int[] primariesOfRegions = new int[cluster.numRegions]; +1540 System.arraycopy(cluster.regionIndexToPrimaryIndex, 0, primariesOfRegions, 0, +1541 cluster.regions.length); +1542 +1543 Arrays.sort(primariesOfRegions); +1544 +1545 // compute numReplicas from the sorted array +1546 return costPerGroup(primariesOfRegions); +1547 } +1548 +1549 @Override +1550 boolean isNeeded() { +1551 return cluster.hasRegionReplicas; +1552 } +1553 +1554 @Override +1555 double cost() { +1556 if (maxCost <= 0) { +1557 return 0; +1558 } +1559 +1560 long totalCost = 0; +1561 for (int i = 0 ; i < costsPerGroup.length; i++) { +1562 totalCost += costsPerGroup[i]; +1563 } +1564 return scale(0, maxCost, totalCost); +1565 } +1566 +1567 /** +1568 * For each primary region, it computes the total number of replicas in the array (numReplicas) +1569 * and returns a sum of numReplicas-1 squared. For example, if the server hosts +1570 * regions a, b, c, d, e, f where a and b are same replicas, and c,d,e are same replicas, it +1571 * returns (2-1) * (2-1) + (3-1) * (3-1) + (1-1) * (1-1). +1572 * @param primariesOfRegions a sorted array of primary regions ids for the regions hosted +1573 * @return a sum of numReplicas-1 squared for each primary region in the group. +1574 */ +1575 protected long costPerGroup(int[] primariesOfRegions) { +1576 long cost = 0; +1577 int currentPrimary = -1; +1578 int currentPrimaryIndex = -1; +1579 // primariesOfRegions is a sorted array of primary ids of regions. Replicas of regions +1580 // sharing the same primary will have consecutive numbers in the array. +1581 for (int j = 0 ; j <= primariesOfRegions.length; j++) { +1582 int primary = j < primariesOfRegions.length ? primariesOfRegions[j] : -1; +1583 if (primary != currentPrimary) { // we see a new primary +1584 int numReplicas = j - currentPrimaryIndex; +1585 // square the cost +1586 if (numReplicas > 1) { // means consecutive primaries, indicating co-location +1587 cost += (numReplicas - 1) * (numReplicas - 1); +1588 } +1589 currentPrimary = primary; +1590 currentPrimaryIndex = j; +1591 } +1592 } +1593 +1594 return cost; +1595 } +1596 +1597 @Override +1598 protected void regionMoved(int region, int oldServer, int newServer) { +1599 if (maxCost <= 0) { +1600 return; // no need to compute +1601 } +1602 if (cluster.multiServersPerHost) { +1603 int oldHost = cluster.serverIndexToHostIndex[oldServer]; +1604 int newHost = cluster.serverIndexToHostIndex[newServer]; +1605 if (newHost != oldHost) { +1606 costsPerGroup[oldHost] = costPerGroup(cluster.primariesOfRegionsPerHost[oldHost]); +1607 costsPerGroup[newHost] = costPerGroup(cluster.primariesOfRegionsPerHost[newHost]); +1608 } +1609 } else { +1610 costsPerGroup[oldServer] = costPerGroup(cluster.primariesOfRegionsPerServer[oldServer]); +1611 costsPerGroup[newServer] = costPerGroup(cluster.primariesOfRegionsPerServer[newServer]); +1612 } +1613 } +1614 } +1615 +1616 /** +1617 * A cost function for region replicas for the rack distribution. We give a relatively high +1618 * cost to hosting replicas of the same region in the same rack. We do not prevent the case +1619 * though. +1620 */ +1621 static class RegionReplicaRackCostFunction extends RegionReplicaHostCostFunction { +1622 private static final String REGION_REPLICA_RACK_COST_KEY = +1623 "hbase.master.balancer.stochastic.regionReplicaRackCostKey"; +1624 private static final float DEFAULT_REGION_REPLICA_RACK_COST_KEY = 10000; +1625 +1626 public RegionReplicaRackCostFunction(Configuration conf) { +1627 super(conf); +1628 this.setMultiplier(conf.getFloat(REGION_REPLICA_RACK_COST_KEY, +1629 DEFAULT_REGION_REPLICA_RACK_COST_KEY)); +1630 } +1631 +1632 @Override +1633 void init(Cluster cluster) { +1634 this.cluster = cluster; +1635 if (cluster.numRacks <= 1) { +1636 maxCost = 0; +1637 return; // disabled for 1 rack +1638 } +1639 // max cost is the case where every region replica is hosted together regardless of rack +1640 maxCost = getMaxCost(cluster); +1641 costsPerGroup = new long[cluster.numRacks]; +1642 for (int i = 0 ; i < cluster.primariesOfRegionsPerRack.length; i++) { +1643 costsPerGroup[i] = costPerGroup(cluster.primariesOfRegionsPerRack[i]); +1644 } +1645 } +1646 +1647 @Override +1648 protected void regionMoved(int region, int oldServer, int newServer) { +1649 if (maxCost <= 0) { +1650 return; // no need to compute +1651 } +1652 int oldRack = cluster.serverIndexToRackIndex[oldServer]; +1653 int newRack = cluster.serverIndexToRackIndex[newServer]; +1654 if (newRack != oldRack) { +1655 costsPerGroup[oldRack] = costPerGroup(cluster.primariesOfRegionsPerRack[oldRack]); +1656 costsPerGroup[newRack] = costPerGroup(cluster.primariesOfRegionsPerRack[newRack]); +1657 } +1658 } +1659 } +1660 +1661 /** +1662 * Compute the cost of total memstore size. The more unbalanced the higher the +1663 * computed cost will be. This uses a rolling average of regionload. +1664 */ +1665 static class MemstoreSizeCostFunction extends CostFromRegionLoadAsRateFunction { +1666 +1667 private static final String MEMSTORE_SIZE_COST_KEY = +1668 "hbase.master.balancer.stochastic.memstoreSizeCost"; +1669 private static final float DEFAULT_MEMSTORE_SIZE_COST = 5; +1670 +1671 MemstoreSizeCostFunction(Configuration conf) { +1672 super(conf); +1673 this.setMultiplier(conf.getFloat(MEMSTORE_SIZE_COST_KEY, DEFAULT_MEMSTORE_SIZE_COST)); +1674 } +1675 +1676 @Override +1677 protected double getCostFromRl(BalancerRegionLoad rl) { +1678 return rl.getMemStoreSizeMB(); +1679 } +1680 } +1681 /** +1682 * Compute the cost of total open storefiles size. The more unbalanced the higher the +1683 * computed cost will be. This uses a rolling average of regionload. +1684 */ +1685 static class StoreFileCostFunction extends CostFromRegionLoadFunction { +1686 +1687 private static final String STOREFILE_SIZE_COST_KEY = +1688 "hbase.master.balancer.stochastic.storefileSizeCost"; +1689 private static final float DEFAULT_STOREFILE_SIZE_COST = 5; +1690 +1691 StoreFileCostFunction(Configuration conf) { +1692 super(conf); +1693 this.setMultiplier(conf.getFloat(STOREFILE_SIZE_COST_KEY, DEFAULT_STOREFILE_SIZE_COST)); +1694 } +1695 +1696 @Override +1697 protected double getCostFromRl(BalancerRegionLoad rl) { +1698 return rl.getStorefileSizeMB(); +1699 } +1700 } +1701 +1702 /** +1703 * A helper function to compose the attribute name from tablename and costfunction name +1704 */ +1705 public static String composeAttributeName(String tableName, String costFunctionName) { +1706 return tableName + TABLE_FUNCTION_SEP + costFunctionName; +1707 } +1708}