1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.regionserver.throttle;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertTrue;
22
23 import java.io.IOException;
24 import java.util.List;
25 import java.util.Random;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.hadoop.conf.Configuration;
30 import org.apache.hadoop.hbase.HBaseTestingUtility;
31 import org.apache.hadoop.hbase.HColumnDescriptor;
32 import org.apache.hadoop.hbase.HTableDescriptor;
33 import org.apache.hadoop.hbase.MiniHBaseCluster;
34 import org.apache.hadoop.hbase.TableName;
35 import org.apache.hadoop.hbase.client.Admin;
36 import org.apache.hadoop.hbase.client.Connection;
37 import org.apache.hadoop.hbase.client.ConnectionFactory;
38 import org.apache.hadoop.hbase.client.Put;
39 import org.apache.hadoop.hbase.client.Table;
40 import org.apache.hadoop.hbase.regionserver.DefaultStoreEngine;
41 import org.apache.hadoop.hbase.regionserver.HRegionServer;
42 import org.apache.hadoop.hbase.regionserver.HStore;
43 import org.apache.hadoop.hbase.regionserver.Region;
44 import org.apache.hadoop.hbase.regionserver.Store;
45 import org.apache.hadoop.hbase.regionserver.StoreEngine;
46 import org.apache.hadoop.hbase.regionserver.StripeStoreConfig;
47 import org.apache.hadoop.hbase.regionserver.StripeStoreEngine;
48 import org.apache.hadoop.hbase.regionserver.compactions.CompactionConfiguration;
49 import org.apache.hadoop.hbase.regionserver.throttle.CompactionThroughputControllerFactory;
50 import org.apache.hadoop.hbase.regionserver.throttle.NoLimitThroughputController;
51 import org.apache.hadoop.hbase.regionserver.throttle.PressureAwareCompactionThroughputController;
52 import org.apache.hadoop.hbase.testclassification.MediumTests;
53 import org.apache.hadoop.hbase.testclassification.RegionServerTests;
54 import org.apache.hadoop.hbase.util.Bytes;
55 import org.apache.hadoop.hbase.util.JVMClusterUtil;
56 import org.junit.Test;
57 import org.junit.experimental.categories.Category;
58
59 @Category({ RegionServerTests.class, MediumTests.class })
60 public class TestCompactionWithThroughputController {
61
62 private static final Log LOG = LogFactory.getLog(TestCompactionWithThroughputController.class);
63
64 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
65
66 private static final double EPSILON = 1E-6;
67
68 private final TableName tableName = TableName.valueOf(getClass().getSimpleName());
69
70 private final byte[] family = Bytes.toBytes("f");
71
72 private final byte[] qualifier = Bytes.toBytes("q");
73
74 private Store getStoreWithName(TableName tableName) {
75 MiniHBaseCluster cluster = TEST_UTIL.getMiniHBaseCluster();
76 List<JVMClusterUtil.RegionServerThread> rsts = cluster.getRegionServerThreads();
77 for (int i = 0; i < cluster.getRegionServerThreads().size(); i++) {
78 HRegionServer hrs = rsts.get(i).getRegionServer();
79 for (Region region : hrs.getOnlineRegions(tableName)) {
80 return region.getStores().iterator().next();
81 }
82 }
83 return null;
84 }
85
86 private Store prepareData() throws IOException {
87 Admin admin = TEST_UTIL.getHBaseAdmin();
88 if (admin.tableExists(tableName)) {
89 admin.disableTable(tableName);
90 admin.deleteTable(tableName);
91 }
92 Table table = TEST_UTIL.createTable(tableName, family);
93 Random rand = new Random();
94 for (int i = 0; i < 10; i++) {
95 for (int j = 0; j < 10; j++) {
96 byte[] value = new byte[128 * 1024];
97 rand.nextBytes(value);
98 table.put(new Put(Bytes.toBytes(i * 10 + j)).addColumn(family, qualifier, value));
99 }
100 admin.flush(tableName);
101 }
102 return getStoreWithName(tableName);
103 }
104
105 private long testCompactionWithThroughputLimit() throws Exception {
106 long throughputLimit = 1024L * 1024;
107 Configuration conf = TEST_UTIL.getConfiguration();
108 conf.set(StoreEngine.STORE_ENGINE_CLASS_KEY, DefaultStoreEngine.class.getName());
109 conf.setInt(CompactionConfiguration.HBASE_HSTORE_COMPACTION_MIN_KEY, 100);
110 conf.setInt(CompactionConfiguration.HBASE_HSTORE_COMPACTION_MAX_KEY, 200);
111 conf.setInt(HStore.BLOCKING_STOREFILES_KEY, 10000);
112 conf.setLong(
113 PressureAwareCompactionThroughputController
114 .HBASE_HSTORE_COMPACTION_MAX_THROUGHPUT_HIGHER_BOUND,
115 throughputLimit);
116 conf.setLong(
117 PressureAwareCompactionThroughputController
118 .HBASE_HSTORE_COMPACTION_MAX_THROUGHPUT_LOWER_BOUND,
119 throughputLimit);
120 conf.set(CompactionThroughputControllerFactory.HBASE_THROUGHPUT_CONTROLLER_KEY,
121 PressureAwareCompactionThroughputController.class.getName());
122 TEST_UTIL.startMiniCluster(1);
123 try {
124 Store store = prepareData();
125 assertEquals(10, store.getStorefilesCount());
126 long startTime = System.currentTimeMillis();
127 TEST_UTIL.getHBaseAdmin().majorCompact(tableName);
128 while (store.getStorefilesCount() != 1) {
129 Thread.sleep(20);
130 }
131 long duration = System.currentTimeMillis() - startTime;
132 double throughput = (double) store.getStorefilesSize() / duration * 1000;
133
134
135 assertTrue(throughput < throughputLimit * 1.2);
136 assertTrue(throughput > throughputLimit * 0.8);
137 return System.currentTimeMillis() - startTime;
138 } finally {
139 TEST_UTIL.shutdownMiniCluster();
140 }
141 }
142
143 private long testCompactionWithoutThroughputLimit() throws Exception {
144 Configuration conf = TEST_UTIL.getConfiguration();
145 conf.set(StoreEngine.STORE_ENGINE_CLASS_KEY, DefaultStoreEngine.class.getName());
146 conf.setInt(CompactionConfiguration.HBASE_HSTORE_COMPACTION_MIN_KEY, 100);
147 conf.setInt(CompactionConfiguration.HBASE_HSTORE_COMPACTION_MAX_KEY, 200);
148 conf.setInt(HStore.BLOCKING_STOREFILES_KEY, 10000);
149 conf.set(CompactionThroughputControllerFactory.HBASE_THROUGHPUT_CONTROLLER_KEY,
150 NoLimitThroughputController.class.getName());
151 TEST_UTIL.startMiniCluster(1);
152 try {
153 Store store = prepareData();
154 assertEquals(10, store.getStorefilesCount());
155 long startTime = System.currentTimeMillis();
156 TEST_UTIL.getHBaseAdmin().majorCompact(tableName);
157 while (store.getStorefilesCount() != 1) {
158 Thread.sleep(20);
159 }
160 return System.currentTimeMillis() - startTime;
161 } finally {
162 TEST_UTIL.shutdownMiniCluster();
163 }
164 }
165
166 @Test
167 public void testCompaction() throws Exception {
168 long limitTime = testCompactionWithThroughputLimit();
169 long noLimitTime = testCompactionWithoutThroughputLimit();
170 LOG.info("With 1M/s limit, compaction use " + limitTime + "ms; without limit, compaction use "
171 + noLimitTime + "ms");
172
173
174 assertTrue(limitTime > noLimitTime * 2);
175 }
176
177
178
179
180 @Test
181 public void testThroughputTuning() throws Exception {
182 Configuration conf = TEST_UTIL.getConfiguration();
183 conf.set(StoreEngine.STORE_ENGINE_CLASS_KEY, DefaultStoreEngine.class.getName());
184 conf.setLong(
185 PressureAwareCompactionThroughputController
186 .HBASE_HSTORE_COMPACTION_MAX_THROUGHPUT_HIGHER_BOUND,
187 20L * 1024 * 1024);
188 conf.setLong(
189 PressureAwareCompactionThroughputController
190 .HBASE_HSTORE_COMPACTION_MAX_THROUGHPUT_LOWER_BOUND,
191 10L * 1024 * 1024);
192 conf.setInt(CompactionConfiguration.HBASE_HSTORE_COMPACTION_MIN_KEY, 4);
193 conf.setInt(HStore.BLOCKING_STOREFILES_KEY, 6);
194 conf.set(CompactionThroughputControllerFactory.HBASE_THROUGHPUT_CONTROLLER_KEY,
195 PressureAwareCompactionThroughputController.class.getName());
196 conf.setInt(
197 PressureAwareCompactionThroughputController.HBASE_HSTORE_COMPACTION_THROUGHPUT_TUNE_PERIOD,
198 1000);
199 TEST_UTIL.startMiniCluster(1);
200 Connection conn = ConnectionFactory.createConnection(conf);
201 try {
202 HTableDescriptor htd = new HTableDescriptor(tableName);
203 htd.addFamily(new HColumnDescriptor(family));
204 htd.setCompactionEnabled(false);
205 TEST_UTIL.getHBaseAdmin().createTable(htd);
206 TEST_UTIL.waitTableAvailable(tableName);
207 HRegionServer regionServer = TEST_UTIL.getRSForFirstRegionInTable(tableName);
208 PressureAwareCompactionThroughputController throughputController =
209 (PressureAwareCompactionThroughputController) regionServer.compactSplitThread
210 .getCompactionThroughputController();
211 assertEquals(10L * 1024 * 1024, throughputController.getMaxThroughput(), EPSILON);
212 Table table = conn.getTable(tableName);
213 for (int i = 0; i < 5; i++) {
214 byte[] value = new byte[0];
215 table.put(new Put(Bytes.toBytes(i)).addColumn(family, qualifier, value));
216 TEST_UTIL.flush(tableName);
217 }
218 Thread.sleep(2000);
219 assertEquals(15L * 1024 * 1024, throughputController.getMaxThroughput(), EPSILON);
220
221 byte[] value1 = new byte[0];
222 table.put(new Put(Bytes.toBytes(5)).addColumn(family, qualifier, value1));
223 TEST_UTIL.flush(tableName);
224 Thread.sleep(2000);
225 assertEquals(20L * 1024 * 1024, throughputController.getMaxThroughput(), EPSILON);
226
227 byte[] value = new byte[0];
228 table.put(new Put(Bytes.toBytes(6)).addColumn(family, qualifier, value));
229 TEST_UTIL.flush(tableName);
230 Thread.sleep(2000);
231 assertEquals(Double.MAX_VALUE, throughputController.getMaxThroughput(), EPSILON);
232
233 conf.set(CompactionThroughputControllerFactory.HBASE_THROUGHPUT_CONTROLLER_KEY,
234 NoLimitThroughputController.class.getName());
235 regionServer.compactSplitThread.onConfigurationChange(conf);
236 assertTrue(throughputController.isStopped());
237 assertTrue(regionServer.compactSplitThread.getCompactionThroughputController()
238 instanceof NoLimitThroughputController);
239 } finally {
240 conn.close();
241 TEST_UTIL.shutdownMiniCluster();
242 }
243 }
244
245
246
247
248 @Test
249 public void testGetCompactionPressureForStripedStore() throws Exception {
250 Configuration conf = TEST_UTIL.getConfiguration();
251 conf.set(StoreEngine.STORE_ENGINE_CLASS_KEY, StripeStoreEngine.class.getName());
252 conf.setBoolean(StripeStoreConfig.FLUSH_TO_L0_KEY, false);
253 conf.setInt(StripeStoreConfig.INITIAL_STRIPE_COUNT_KEY, 2);
254 conf.setInt(StripeStoreConfig.MIN_FILES_KEY, 4);
255 conf.setInt(HStore.BLOCKING_STOREFILES_KEY, 12);
256 TEST_UTIL.startMiniCluster(1);
257 Connection conn = ConnectionFactory.createConnection(conf);
258 try {
259 HTableDescriptor htd = new HTableDescriptor(tableName);
260 htd.addFamily(new HColumnDescriptor(family));
261 htd.setCompactionEnabled(false);
262 TEST_UTIL.getHBaseAdmin().createTable(htd);
263 TEST_UTIL.waitTableAvailable(tableName);
264 HStore store = (HStore) getStoreWithName(tableName);
265 assertEquals(0, store.getStorefilesCount());
266 assertEquals(0.0, store.getCompactionPressure(), EPSILON);
267 Table table = conn.getTable(tableName);
268 for (int i = 0; i < 4; i++) {
269 byte[] value1 = new byte[0];
270 table.put(new Put(Bytes.toBytes(i)).addColumn(family, qualifier, value1));
271 byte[] value = new byte[0];
272 table.put(new Put(Bytes.toBytes(100 + i)).addColumn(family, qualifier, value));
273 TEST_UTIL.flush(tableName);
274 }
275 assertEquals(8, store.getStorefilesCount());
276 assertEquals(0.0, store.getCompactionPressure(), EPSILON);
277
278 byte[] value5 = new byte[0];
279 table.put(new Put(Bytes.toBytes(4)).addColumn(family, qualifier, value5));
280 byte[] value4 = new byte[0];
281 table.put(new Put(Bytes.toBytes(104)).addColumn(family, qualifier, value4));
282 TEST_UTIL.flush(tableName);
283 assertEquals(10, store.getStorefilesCount());
284 assertEquals(0.5, store.getCompactionPressure(), EPSILON);
285
286 byte[] value3 = new byte[0];
287 table.put(new Put(Bytes.toBytes(5)).addColumn(family, qualifier, value3));
288 byte[] value2 = new byte[0];
289 table.put(new Put(Bytes.toBytes(105)).addColumn(family, qualifier, value2));
290 TEST_UTIL.flush(tableName);
291 assertEquals(12, store.getStorefilesCount());
292 assertEquals(1.0, store.getCompactionPressure(), EPSILON);
293
294 byte[] value1 = new byte[0];
295 table.put(new Put(Bytes.toBytes(6)).addColumn(family, qualifier, value1));
296 byte[] value = new byte[0];
297 table.put(new Put(Bytes.toBytes(106)).addColumn(family, qualifier, value));
298 TEST_UTIL.flush(tableName);
299 assertEquals(14, store.getStorefilesCount());
300 assertEquals(2.0, store.getCompactionPressure(), EPSILON);
301 } finally {
302 conn.close();
303 TEST_UTIL.shutdownMiniCluster();
304 }
305 }
306 }