HBASE-5792 HLog Performance Evaluation Tool
git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1326793 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
fcfb13e312
commit
9d15d08d71
|
@ -0,0 +1,302 @@
|
|||
/**
|
||||
* 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.regionserver.wal;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.apache.hadoop.fs.FileStatus;
|
||||
import org.apache.hadoop.fs.Path;
|
||||
import org.apache.hadoop.fs.FileSystem;
|
||||
import org.apache.hadoop.util.Tool;
|
||||
import org.apache.hadoop.util.ToolRunner;
|
||||
import org.apache.hadoop.conf.Configured;
|
||||
import org.apache.hadoop.classification.InterfaceAudience;
|
||||
|
||||
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
||||
import org.apache.hadoop.hbase.HColumnDescriptor;
|
||||
import org.apache.hadoop.hbase.HConstants;
|
||||
import org.apache.hadoop.hbase.HRegionInfo;
|
||||
import org.apache.hadoop.hbase.HTableDescriptor;
|
||||
import org.apache.hadoop.hbase.KeyValue;
|
||||
import org.apache.hadoop.hbase.util.Bytes;
|
||||
import org.apache.hadoop.hbase.client.Put;
|
||||
import org.apache.hadoop.hbase.regionserver.HRegion;
|
||||
import org.apache.hadoop.hbase.regionserver.wal.HLog;
|
||||
import org.apache.hadoop.hbase.regionserver.wal.HLog.Entry;
|
||||
import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
|
||||
|
||||
/**
|
||||
* This class runs performance benchmarks for {@link HLog}.
|
||||
*/
|
||||
@InterfaceAudience.Private
|
||||
public final class HLogPerformanceEvaluation extends Configured implements Tool {
|
||||
static final Log LOG = LogFactory.getLog(HLogPerformanceEvaluation.class.getName());
|
||||
|
||||
private final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
|
||||
|
||||
static final String TABLE_NAME = "HLogPerformanceEvaluation";
|
||||
static final String QUALIFIER_PREFIX = "q";
|
||||
static final String FAMILY_PREFIX = "cf";
|
||||
|
||||
private int numQualifiers = 1;
|
||||
private int valueSize = 512;
|
||||
private int keySize = 16;
|
||||
|
||||
/**
|
||||
* Perform HLog.append() of Put object, for the number of iterations requested.
|
||||
* Keys and Vaues are generated randomly, the number of column familes,
|
||||
* qualifiers and key/value size is tunable by the user.
|
||||
*/
|
||||
class HLogPutBenchmark implements Runnable {
|
||||
private final long numIterations;
|
||||
private final int numFamilies;
|
||||
private final boolean noSync;
|
||||
private final HRegion region;
|
||||
private final HTableDescriptor htd;
|
||||
|
||||
HLogPutBenchmark(final HRegion region, final HTableDescriptor htd,
|
||||
final long numIterations, final boolean noSync) {
|
||||
this.numIterations = numIterations;
|
||||
this.noSync = noSync;
|
||||
this.numFamilies = htd.getColumnFamilies().length;
|
||||
this.region = region;
|
||||
this.htd = htd;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
byte[] key = new byte[keySize];
|
||||
byte[] value = new byte[valueSize];
|
||||
Random rand = new Random(Thread.currentThread().getId());
|
||||
HLog hlog = region.getLog();
|
||||
|
||||
try {
|
||||
long startTime = System.currentTimeMillis();
|
||||
for (int i = 0; i < numIterations; ++i) {
|
||||
Put put = setupPut(rand, key, value, numFamilies);
|
||||
long now = System.currentTimeMillis();
|
||||
WALEdit walEdit = new WALEdit();
|
||||
addFamilyMapToWALEdit(put.getFamilyMap(), walEdit);
|
||||
HRegionInfo hri = region.getRegionInfo();
|
||||
if (this.noSync) {
|
||||
hlog.appendNoSync(hri, hri.getTableName(), walEdit,
|
||||
HConstants.DEFAULT_CLUSTER_ID, now, htd);
|
||||
} else {
|
||||
hlog.append(hri, hri.getTableName(), walEdit, now, htd);
|
||||
}
|
||||
}
|
||||
long totalTime = (System.currentTimeMillis() - startTime);
|
||||
logBenchmarkResult(Thread.currentThread().getName(), numIterations, totalTime);
|
||||
} catch (Exception e) {
|
||||
LOG.error(getClass().getSimpleName() + " Thread failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int run(String[] args) throws Exception {
|
||||
Path rootRegionDir = null;
|
||||
int numThreads = 1;
|
||||
long numIterations = 10000;
|
||||
int numFamilies = 1;
|
||||
boolean noSync = false;
|
||||
boolean verify = false;
|
||||
// Process command line args
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
String cmd = args[i];
|
||||
|
||||
try {
|
||||
if (cmd.equals("-threads")) {
|
||||
numThreads = Integer.parseInt(args[++i]);
|
||||
} else if (cmd.equals("-iterations")) {
|
||||
numIterations = Long.parseLong(args[++i]);
|
||||
} else if (cmd.equals("-path")) {
|
||||
rootRegionDir = new Path(args[++i]);
|
||||
} else if (cmd.equals("-families")) {
|
||||
numFamilies = Integer.parseInt(args[++i]);
|
||||
} else if (cmd.equals("-qualifiers")) {
|
||||
numQualifiers = Integer.parseInt(args[++i]);
|
||||
} else if (cmd.equals("-keySize")) {
|
||||
keySize = Integer.parseInt(args[++i]);
|
||||
} else if (cmd.equals("-valueSize")) {
|
||||
valueSize = Integer.parseInt(args[++i]);
|
||||
} else if (cmd.equals("-nosync")) {
|
||||
noSync = true;
|
||||
} else if (cmd.equals("-verify")) {
|
||||
verify = true;
|
||||
} else {
|
||||
printUsageAndExit();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
printUsageAndExit();
|
||||
}
|
||||
}
|
||||
|
||||
// Run HLog Performance Evaluation
|
||||
FileSystem fs = FileSystem.get(getConf());
|
||||
try {
|
||||
if (rootRegionDir == null) {
|
||||
rootRegionDir = TEST_UTIL.getDataTestDir("HLogPerformanceEvaluation");
|
||||
}
|
||||
rootRegionDir = rootRegionDir.makeQualified(fs);
|
||||
cleanRegionRootDir(fs, rootRegionDir);
|
||||
// Initialize Table Descriptor
|
||||
HTableDescriptor htd = createHTableDescriptor(numFamilies);
|
||||
HLog hlog = new HLog(fs, new Path(rootRegionDir, "wals"),
|
||||
new Path(rootRegionDir, "old.wals"), getConf());
|
||||
HRegion region = null;
|
||||
try {
|
||||
region = openRegion(fs, rootRegionDir, htd, hlog);
|
||||
long putTime = runBenchmark(new HLogPutBenchmark(region, htd, numIterations, noSync), numThreads);
|
||||
logBenchmarkResult("Summary: threads=" + numThreads + ", iterations=" + numIterations,
|
||||
numIterations * numThreads, putTime);
|
||||
if (region != null) {
|
||||
closeRegion(region);
|
||||
region = null;
|
||||
}
|
||||
if (verify) {
|
||||
Path dir = hlog.getDir();
|
||||
for (FileStatus fss: fs.listStatus(dir)) {
|
||||
verifyInSequence(fss.getPath());
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (region != null) closeRegion(region);
|
||||
// Remove the root dir for this test region
|
||||
cleanRegionRootDir(fs, rootRegionDir);
|
||||
}
|
||||
} finally {
|
||||
fs.close();
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
private static HTableDescriptor createHTableDescriptor(final int numFamilies) {
|
||||
HTableDescriptor htd = new HTableDescriptor(TABLE_NAME);
|
||||
for (int i = 0; i < numFamilies; ++i) {
|
||||
HColumnDescriptor colDef = new HColumnDescriptor(FAMILY_PREFIX + i);
|
||||
htd.addFamily(colDef);
|
||||
}
|
||||
return htd;
|
||||
}
|
||||
|
||||
void verifyInSequence(final Path wal) throws IOException {
|
||||
HLog.Reader reader = HLog.getReader(wal.getFileSystem(getConf()), wal, getConf());
|
||||
long previousSeqid = -1;
|
||||
try {
|
||||
while (true) {
|
||||
Entry e = reader.next();
|
||||
if (e == null) break;
|
||||
long seqid = e.getKey().getLogSeqNum();
|
||||
if (previousSeqid >= seqid) {
|
||||
throw new IllegalStateException("wal=" + wal.getName() +
|
||||
", previousSeqid=" + previousSeqid + ", seqid=" + seqid);
|
||||
}
|
||||
previousSeqid = seqid;
|
||||
}
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void logBenchmarkResult(String testName, long numTests, long totalTime) {
|
||||
float tsec = totalTime / 1000.0f;
|
||||
LOG.info(String.format("%s took %.3fs %.3fops/s", testName, tsec, numTests / tsec));
|
||||
}
|
||||
|
||||
private void printUsageAndExit() {
|
||||
System.err.printf("Usage: bin/hbase %s [options]\n", getClass().getName());
|
||||
System.err.println(" where [options] are:");
|
||||
System.err.println(" -h|-help Show this help and exit.");
|
||||
System.err.println(" -threads <N> Number of threads writing on the WAL.");
|
||||
System.err.println(" -iterations <N> Number of iterations per thread.");
|
||||
System.err.println(" -path <PATH> Path where region's root directory is created.");
|
||||
System.err.println(" -families <N> Number of column families to write.");
|
||||
System.err.println(" -qualifiers <N> Number of qualifiers to write.");
|
||||
System.err.println(" -keySize <N> Row key size in byte.");
|
||||
System.err.println(" -valueSize <N> Row/Col value size in byte.");
|
||||
System.err.println(" -nosync Append without syncing");
|
||||
System.err.println(" -verify Verify edits written in sequence");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
private HRegion openRegion(final FileSystem fs, final Path dir, final HTableDescriptor htd, final HLog hlog)
|
||||
throws IOException {
|
||||
// Initialize HRegion
|
||||
HRegionInfo regionInfo = new HRegionInfo(htd.getName());
|
||||
return HRegion.createHRegion(regionInfo, dir, getConf(), htd, hlog);
|
||||
}
|
||||
|
||||
private void closeRegion(final HRegion region) throws IOException {
|
||||
if (region != null) {
|
||||
region.close();
|
||||
HLog wal = region.getLog();
|
||||
if (wal != null) wal.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanRegionRootDir(final FileSystem fs, final Path dir) throws IOException {
|
||||
if (fs.exists(dir)) {
|
||||
fs.delete(dir, true);
|
||||
}
|
||||
}
|
||||
|
||||
private Put setupPut(Random rand, byte[] key, byte[] value, final int numFamilies) {
|
||||
rand.nextBytes(key);
|
||||
Put put = new Put(key);
|
||||
for (int cf = 0; cf < numFamilies; ++cf) {
|
||||
for (int q = 0; q < numQualifiers; ++q) {
|
||||
rand.nextBytes(value);
|
||||
put.add(Bytes.toBytes(FAMILY_PREFIX + cf), Bytes.toBytes(QUALIFIER_PREFIX + q), value);
|
||||
}
|
||||
}
|
||||
return put;
|
||||
}
|
||||
|
||||
private void addFamilyMapToWALEdit(Map<byte[], List<KeyValue>> familyMap, WALEdit walEdit) {
|
||||
for (List<KeyValue> edits : familyMap.values()) {
|
||||
for (KeyValue kv : edits) {
|
||||
walEdit.add(kv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long runBenchmark(Runnable runnable, final int numThreads) throws InterruptedException {
|
||||
Thread[] threads = new Thread[numThreads];
|
||||
long startTime = System.currentTimeMillis();
|
||||
for (int i = 0; i < numThreads; ++i) {
|
||||
threads[i] = new Thread(runnable);
|
||||
threads[i].start();
|
||||
}
|
||||
for (Thread t : threads) t.join();
|
||||
long endTime = System.currentTimeMillis();
|
||||
return(endTime - startTime);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
int exitCode = ToolRunner.run(new HLogPerformanceEvaluation(), args);
|
||||
System.exit(exitCode);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue