001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019package org.apache.hadoop.hbase.master.balancer; 020 021import java.io.IOException; 022import java.util.ArrayList; 023import java.util.Collections; 024import java.util.HashMap; 025import java.util.List; 026import java.util.Map; 027import java.util.concurrent.TimeUnit; 028 029import org.apache.hadoop.hbase.HBaseCommonTestingUtility; 030import org.apache.hadoop.hbase.HBaseInterfaceAudience; 031import org.apache.hadoop.hbase.HConstants; 032import org.apache.hadoop.hbase.ServerName; 033import org.apache.hadoop.hbase.TableName; 034import org.apache.hadoop.hbase.client.RegionInfo; 035import org.apache.hadoop.hbase.client.RegionInfoBuilder; 036import org.apache.hadoop.hbase.master.LoadBalancer; 037import org.apache.hadoop.hbase.util.AbstractHBaseTool; 038import org.apache.hadoop.hbase.util.Bytes; 039import org.apache.yetus.audience.InterfaceAudience; 040import org.slf4j.Logger; 041import org.slf4j.LoggerFactory; 042import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 043import org.apache.hbase.thirdparty.com.google.common.base.Stopwatch; 044import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLine; 045import org.apache.hbase.thirdparty.org.apache.commons.cli.Option; 046 047/** 048 * Tool to test performance of different {@link org.apache.hadoop.hbase.master.LoadBalancer} 049 * implementations. 050 * Example command: 051 * $ bin/hbase org.apache.hadoop.hbase.master.balancer.LoadBalancerPerformanceEvaluation 052 * -regions 1000 -servers 100 053 * -load_balancer org.apache.hadoop.hbase.master.balancer.SimpleLoadBalancer 054 */ 055@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS) 056public class LoadBalancerPerformanceEvaluation extends AbstractHBaseTool { 057 private static final Logger LOG = 058 LoggerFactory.getLogger(LoadBalancerPerformanceEvaluation.class.getName()); 059 060 protected static final HBaseCommonTestingUtility UTIL = new HBaseCommonTestingUtility(); 061 062 private static final int DEFAULT_NUM_REGIONS = 1000000; 063 private static Option NUM_REGIONS_OPT = new Option("regions", true, 064 "Number of regions to consider by load balancer. Default: " + DEFAULT_NUM_REGIONS); 065 066 private static final int DEFAULT_NUM_SERVERS = 1000; 067 private static Option NUM_SERVERS_OPT = new Option("servers", true, 068 "Number of servers to consider by load balancer. Default: " + DEFAULT_NUM_SERVERS); 069 070 private static final String DEFAULT_LOAD_BALANCER = 071 "org.apache.hadoop.hbase.master.balancer.StochasticLoadBalancer"; 072 private static Option LOAD_BALANCER_OPT = new Option("load_balancer", true, 073 "Type of Load Balancer to use. Default: " + DEFAULT_LOAD_BALANCER); 074 075 private int numRegions; 076 private int numServers; 077 private String loadBalancerType; 078 private Class<?> loadBalancerClazz; 079 080 private LoadBalancer loadBalancer; 081 082 // data 083 private List<ServerName> servers; 084 private List<RegionInfo> regions; 085 private Map<RegionInfo, ServerName> regionServerMap; 086 private Map<ServerName, List<RegionInfo>> serverRegionMap; 087 088 // Non-default configurations. 089 private void setupConf() { 090 conf.setClass(HConstants.HBASE_MASTER_LOADBALANCER_CLASS, loadBalancerClazz, LoadBalancer.class); 091 loadBalancer = LoadBalancerFactory.getLoadBalancer(conf); 092 } 093 094 private void generateRegionsAndServers() { 095 // regions 096 regions = new ArrayList<>(numRegions); 097 regionServerMap = new HashMap<>(numRegions); 098 for (int i = 0; i < numRegions; ++i) { 099 byte[] start = new byte[16]; 100 byte[] end = new byte[16]; 101 102 Bytes.putInt(start, 0, i); 103 Bytes.putInt(end, 0, i + 1); 104 TableName tableName = TableName.valueOf("LoadBalancerPerfTable"); 105 RegionInfo hri = RegionInfoBuilder.newBuilder(tableName) 106 .setStartKey(start) 107 .setEndKey(end) 108 .setSplit(false) 109 .setRegionId(i) 110 .build(); 111 regions.add(hri); 112 regionServerMap.put(hri, null); 113 } 114 115 // servers 116 servers = new ArrayList<>(numServers); 117 serverRegionMap = new HashMap<>(numServers); 118 for (int i = 0; i < numServers; ++i) { 119 ServerName sn = ServerName.valueOf("srv" + i, HConstants.DEFAULT_REGIONSERVER_PORT, i); 120 servers.add(sn); 121 serverRegionMap.put(sn, i == 0 ? regions : Collections.emptyList()); 122 } 123 } 124 125 @Override 126 protected void addOptions() { 127 addOption(NUM_REGIONS_OPT); 128 addOption(NUM_SERVERS_OPT); 129 addOption(LOAD_BALANCER_OPT); 130 } 131 132 @Override 133 protected void processOptions(CommandLine cmd) { 134 numRegions = getOptionAsInt(cmd, NUM_REGIONS_OPT.getOpt(), DEFAULT_NUM_REGIONS); 135 Preconditions.checkArgument(numRegions > 0, "Invalid number of regions!"); 136 137 numServers = getOptionAsInt(cmd, NUM_SERVERS_OPT.getOpt(), DEFAULT_NUM_SERVERS); 138 Preconditions.checkArgument(numServers > 0, "Invalid number of servers!"); 139 140 loadBalancerType = cmd.getOptionValue(LOAD_BALANCER_OPT.getOpt(), DEFAULT_LOAD_BALANCER); 141 Preconditions.checkArgument(!loadBalancerType.isEmpty(), "Invalid load balancer type!"); 142 143 try { 144 loadBalancerClazz = Class.forName(loadBalancerType); 145 } catch (ClassNotFoundException e) { 146 System.err.println("Class '" + loadBalancerType + "' not found!"); 147 System.exit(1); 148 } 149 150 setupConf(); 151 } 152 153 private String formatResults(final String methodName, final long timeMillis) { 154 return String.format("Time for %-25s: %dms%n", methodName, timeMillis); 155 } 156 157 @Override 158 protected int doWork() throws Exception { 159 generateRegionsAndServers(); 160 161 String methodName = "roundRobinAssignment"; 162 LOG.info("Calling " + methodName); 163 Stopwatch watch = Stopwatch.createStarted(); 164 loadBalancer.roundRobinAssignment(regions, servers); 165 System.out.print(formatResults(methodName, watch.elapsed(TimeUnit.MILLISECONDS))); 166 167 methodName = "retainAssignment"; 168 LOG.info("Calling " + methodName); 169 watch.reset().start(); 170 loadBalancer.retainAssignment(regionServerMap, servers); 171 System.out.print(formatResults(methodName, watch.elapsed(TimeUnit.MILLISECONDS))); 172 173 methodName = "balanceCluster"; 174 LOG.info("Calling " + methodName); 175 watch.reset().start(); 176 177 loadBalancer.balanceTable(HConstants.ENSEMBLE_TABLE_NAME, serverRegionMap); 178 System.out.print(formatResults(methodName, watch.elapsed(TimeUnit.MILLISECONDS))); 179 180 return EXIT_SUCCESS; 181 } 182 183 public static void main(String[] args) throws IOException { 184 LoadBalancerPerformanceEvaluation tool = new LoadBalancerPerformanceEvaluation(); 185 tool.setConf(UTIL.getConfiguration()); 186 tool.run(args); 187 } 188}