From 9cacb67b6997a0345d9ad121b40661a3ceb96c32 Mon Sep 17 00:00:00 2001 From: Michael Stack Date: Tue, 5 Jan 2010 06:02:52 +0000 Subject: [PATCH] HBASE-2021 Add compaction details to master UI git-svn-id: https://svn.apache.org/repos/asf/hadoop/hbase/trunk@895912 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/hadoop/hbase/master/HMaster.java | 16 +++- .../regionserver/CompactSplitThread.java | 10 ++ .../hbase/regionserver/HRegionServer.java | 2 + .../metrics/RegionServerMetrics.java | 10 +- .../org/apache/hadoop/hbase/util/FSUtils.java | 95 +++++++++++++++++++ src/webapps/master/master.jsp | 22 ++++- src/webapps/master/table.jsp | 2 + 7 files changed, 150 insertions(+), 7 deletions(-) diff --git a/src/java/org/apache/hadoop/hbase/master/HMaster.java b/src/java/org/apache/hadoop/hbase/master/HMaster.java index f0caeebb2ea..0ca14feb378 100644 --- a/src/java/org/apache/hadoop/hbase/master/HMaster.java +++ b/src/java/org/apache/hadoop/hbase/master/HMaster.java @@ -151,6 +151,9 @@ public class HMaster extends Thread implements HConstants, HMasterInterface, private final ServerManager serverManager; private final RegionManager regionManager; + private long lastFragmentationQuery = -1L; + private Map fragmentation = null; + /** * Constructor * @param conf configuration @@ -1233,6 +1236,17 @@ public class HMaster extends Thread implements HConstants, HMasterInterface, } } + public Map getTableFragmentation() throws IOException { + long now = System.currentTimeMillis(); + // only check every two minutes by default + int check = this.conf.getInt("hbase.master.fragmentation.check.frequency", 2 * 60 * 1000); + if (lastFragmentationQuery == -1 || now - lastFragmentationQuery > check) { + fragmentation = FSUtils.getTableFragmentation(this); + lastFragmentationQuery = now; + } + return fragmentation; + } + /** * Main program * @param args @@ -1240,4 +1254,4 @@ public class HMaster extends Thread implements HConstants, HMasterInterface, public static void main(String [] args) { doMain(args, HMaster.class); } -} \ No newline at end of file +} diff --git a/src/java/org/apache/hadoop/hbase/regionserver/CompactSplitThread.java b/src/java/org/apache/hadoop/hbase/regionserver/CompactSplitThread.java index 7c67aea64cb..d2834e5083e 100644 --- a/src/java/org/apache/hadoop/hbase/regionserver/CompactSplitThread.java +++ b/src/java/org/apache/hadoop/hbase/regionserver/CompactSplitThread.java @@ -217,4 +217,14 @@ class CompactSplitThread extends Thread implements HConstants { this.interrupt(); } } + + /** + * Returns the current size of the queue containing regions that are + * processed. + * + * @return The current size of the regions queue. + */ + public int getCompactionQueueSize() { + return compactionQueue.size(); + } } \ No newline at end of file diff --git a/src/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java b/src/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java index fd0f43f3fb9..cd31af0a60e 100644 --- a/src/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java +++ b/src/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java @@ -1010,6 +1010,8 @@ public class HRegionServer implements HConstants, HRegionInterface, this.metrics.storefiles.set(storefiles); this.metrics.memstoreSizeMB.set((int)(memstoreSize/(1024*1024))); this.metrics.storefileIndexSizeMB.set((int)(storefileIndexSize/(1024*1024))); + this.metrics.compactionQueueSize.set(compactSplitThread. + getCompactionQueueSize()); LruBlockCache lruBlockCache = (LruBlockCache)StoreFile.getBlockCache(conf); if (lruBlockCache != null) { diff --git a/src/java/org/apache/hadoop/hbase/regionserver/metrics/RegionServerMetrics.java b/src/java/org/apache/hadoop/hbase/regionserver/metrics/RegionServerMetrics.java index 61fc698f09f..875024cb7a4 100644 --- a/src/java/org/apache/hadoop/hbase/regionserver/metrics/RegionServerMetrics.java +++ b/src/java/org/apache/hadoop/hbase/regionserver/metrics/RegionServerMetrics.java @@ -107,6 +107,12 @@ public class RegionServerMetrics implements Updater { public final MetricsIntValue memstoreSizeMB = new MetricsIntValue("memstoreSizeMB", registry); + /** + * Size of the compaction queue. + */ + public final MetricsIntValue compactionQueueSize = + new MetricsIntValue("compactionQueueSize", registry); + /** * filesystem read latency */ @@ -158,7 +164,7 @@ public class RegionServerMetrics implements Updater { this.memstoreSizeMB.pushMetric(this.metricsRecord); this.regions.pushMetric(this.metricsRecord); this.requests.pushMetric(this.metricsRecord); - + this.compactionQueueSize.pushMetric(this.metricsRecord); this.blockCacheSize.pushMetric(this.metricsRecord); this.blockCacheFree.pushMetric(this.metricsRecord); this.blockCacheCount.pushMetric(this.metricsRecord); @@ -218,6 +224,8 @@ public class RegionServerMetrics implements Updater { Integer.valueOf(this.storefileIndexSizeMB.get())); sb = Strings.appendKeyValue(sb, "memstoreSize", Integer.valueOf(this.memstoreSizeMB.get())); + sb = Strings.appendKeyValue(sb, "compactionQueueSize", + Integer.valueOf(this.compactionQueueSize.get())); // Duplicate from jvmmetrics because metrics are private there so // inaccessible. MemoryUsage memory = diff --git a/src/java/org/apache/hadoop/hbase/util/FSUtils.java b/src/java/org/apache/hadoop/hbase/util/FSUtils.java index 696d78693e9..0d549c8e2b3 100644 --- a/src/java/org/apache/hadoop/hbase/util/FSUtils.java +++ b/src/java/org/apache/hadoop/hbase/util/FSUtils.java @@ -23,6 +23,8 @@ import java.io.DataInputStream; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -36,6 +38,7 @@ import org.apache.hadoop.fs.PathFilter; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.RemoteExceptionHandler; +import org.apache.hadoop.hbase.master.HMaster; import org.apache.hadoop.hbase.regionserver.HRegion; import org.apache.hadoop.hdfs.DistributedFileSystem; import org.apache.hadoop.hdfs.protocol.FSConstants; @@ -360,6 +363,98 @@ public class FSUtils { return true; } + /** + * Returns the total overall fragmentation percentage. Includes .META. and + * -ROOT- as well. + * + * @param master The master defining the HBase root and file system. + * @return A map for each table and its percentage. + * @throws IOException When scanning the directory fails. + */ + public static int getTotalTableFragmentation(final HMaster master) + throws IOException { + Map map = getTableFragmentation(master); + return map != null && map.size() > 0 ? map.get("-TOTAL-").intValue() : -1; + } + + /** + * Runs through the HBase rootdir and checks how many stores for each table + * have more than one file in them. Checks -ROOT- and .META. too. The total + * percentage across all tables is stored under the special key "-TOTAL-". + * + * @param master The master defining the HBase root and file system. + * @return A map for each table and its percentage. + * @throws IOException When scanning the directory fails. + */ + public static Map getTableFragmentation( + final HMaster master) + throws IOException { + Path path = master.getRootDir(); + // since HMaster.getFileSystem() is package private + FileSystem fs = path.getFileSystem(master.getConfiguration()); + return getTableFragmentation(fs, path); + } + + /** + * Runs through the HBase rootdir and checks how many stores for each table + * have more than one file in them. Checks -ROOT- and .META. too. The total + * percentage across all tables is stored under the special key "-TOTAL-". + * + * @param fs The file system to use. + * @param hbaseRootDir The root directory to scan. + * @return A map for each table and its percentage. + * @throws IOException When scanning the directory fails. + */ + public static Map getTableFragmentation( + final FileSystem fs, final Path hbaseRootDir) + throws IOException { + Map frags = new HashMap(); + int cfCountTotal = 0; + int cfFragTotal = 0; + DirFilter df = new DirFilter(fs); + // presumes any directory under hbase.rootdir is a table + FileStatus [] tableDirs = fs.listStatus(hbaseRootDir, df); + for (int i = 0; i < tableDirs.length; i++) { + // Skip the .log directory. All others should be tables. Inside a table, + // there are compaction.dir directories to skip. Otherwise, all else + // should be regions. Then in each region, should only be family + // directories. Under each of these, should be one file only. + Path d = tableDirs[i].getPath(); + if (d.getName().equals(HConstants.HREGION_LOGDIR_NAME)) { + continue; + } + int cfCount = 0; + int cfFrag = 0; + FileStatus [] regionDirs = fs.listStatus(d, df); + for (int j = 0; j < regionDirs.length; j++) { + Path dd = regionDirs[j].getPath(); + if (dd.getName().equals(HConstants.HREGION_COMPACTIONDIR_NAME)) { + continue; + } + // else its a region name, now look in region for families + FileStatus [] familyDirs = fs.listStatus(dd, df); + for (int k = 0; k < familyDirs.length; k++) { + cfCount++; + cfCountTotal++; + Path family = familyDirs[k].getPath(); + // now in family make sure only one file + FileStatus [] familyStatus = fs.listStatus(family); + if (familyStatus.length > 1) { + cfFrag++; + cfFragTotal++; + } + } + } + // compute percentage per table and store in result list + frags.put(d.getName(), new Integer( + Math.round((float) cfFrag / cfCount * 100))); + } + // set overall percentage for all tables + frags.put("-TOTAL-", new Integer( + Math.round((float) cfFragTotal / cfCountTotal * 100))); + return frags; + } + /** * Expects to find -ROOT- directory. * @param fs diff --git a/src/webapps/master/master.jsp b/src/webapps/master/master.jsp index 066301958c5..902a53e319a 100644 --- a/src/webapps/master/master.jsp +++ b/src/webapps/master/master.jsp @@ -4,6 +4,7 @@ import="org.apache.hadoop.conf.Configuration" import="org.apache.hadoop.io.Text" import="org.apache.hadoop.hbase.util.Bytes" + import="org.apache.hadoop.hbase.util.FSUtils" import="org.apache.hadoop.hbase.master.HMaster" import="org.apache.hadoop.hbase.HConstants" import="org.apache.hadoop.hbase.master.MetaRegion" @@ -24,6 +25,7 @@ if (interval == 0) { interval = 1; } + Map frags = master.getTableFragmentation(); %> @@ -49,6 +51,7 @@ HBase Root Directory<%= master.getRootDir().toString() %>Location of HBase home directory Load average<%= master.getServerManager().getAverageLoad() %>Average number of regions per regionserver. Naive computation. Regions On FS<%= master.getRegionManager().countRegionsOnFS() %>Number of regions on FileSystem. Rough count. +Fragmentation<%= frags.get("-TOTAL-") != null ? frags.get("-TOTAL-").intValue() + "%" : "n/a" %>Overall fragmentation of all tables, including .META. and -ROOT-. Zookeeper Quorum<%= master.getZooKeeperWrapper().getQuorumServers() %>Addresses of all registered ZK servers. For more, see zk dump. @@ -56,11 +59,17 @@ <% if (rootLocation != null) { %> - - + + + + + <% if (onlineRegions != null && onlineRegions.size() > 0) { %> - + + + + <% } %>
TableDescription
<%= Bytes.toString(HConstants.ROOT_TABLE_NAME) %>The -ROOT- table holds references to all .META. regions.
TableFrag.Description
<%= Bytes.toString(HConstants.ROOT_TABLE_NAME) %><%= frags.get("-ROOT-") != null ? frags.get("-ROOT-").intValue() + "%" : "n/a" %>The -ROOT- table holds references to all .META. regions.
<%= Bytes.toString(HConstants.META_TABLE_NAME) %>The .META. table holds references to all User Table regions
<%= Bytes.toString(HConstants.META_TABLE_NAME) %><%= frags.get(".META.") != null ? frags.get(".META.").intValue() + "%" : "n/a" %>The .META. table holds references to all User Table regions
@@ -70,9 +79,12 @@ <% HTableDescriptor[] tables = new HBaseAdmin(conf).listTables(); if(tables != null && tables.length > 0) { %> - + <% for(HTableDescriptor htDesc : tables ) { %> - + + + + <% } %>

<%= tables.length %> table(s) in set.

diff --git a/src/webapps/master/table.jsp b/src/webapps/master/table.jsp index 07573e1a92b..57037d09ba6 100644 --- a/src/webapps/master/table.jsp +++ b/src/webapps/master/table.jsp @@ -28,6 +28,7 @@ master.getServerManager().getServerAddressToServerInfo(); String tableHeader = "

Table Regions

TableDescription
TableFrag.Description
><%= htDesc.getNameAsString() %> <%= htDesc.toString() %>
><%= htDesc.getNameAsString() %> <%= frags.get(htDesc.getNameAsString()) != null ? frags.get(htDesc.getNameAsString()).intValue() + "%" : "n/a" %><%= htDesc.toString() %>
"; HServerAddress rootLocation = master.getRegionManager().getRootRegionLocation(); + Map frags = master.getTableFragmentation(); %> @@ -121,6 +122,7 @@
NameRegion ServerEncoded NameStart KeyEnd Key
+
Attribute NameValueDescription
Enabled<%= hbadmin.isTableEnabled(table.getTableName()) %>Is the table enabled
Fragmentation<%= frags.get(tableName) != null ? frags.get(tableName).intValue() + "%" : "n/a" %>How fragmented is the table. After a major compaction it is 0%.
<% Map regions = table.getRegionsInfo();