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 */ 018package org.apache.hadoop.hbase.quotas; 019 020import static org.apache.hadoop.hbase.quotas.ThrottleQuotaTestUtil.doGets; 021import static org.apache.hadoop.hbase.quotas.ThrottleQuotaTestUtil.doPuts; 022import static org.apache.hadoop.hbase.quotas.ThrottleQuotaTestUtil.triggerNamespaceCacheRefresh; 023import static org.apache.hadoop.hbase.quotas.ThrottleQuotaTestUtil.triggerTableCacheRefresh; 024import static org.apache.hadoop.hbase.quotas.ThrottleQuotaTestUtil.triggerUserCacheRefresh; 025import static org.junit.Assert.assertEquals; 026import static org.junit.Assert.assertTrue; 027 028import java.util.concurrent.TimeUnit; 029import org.apache.hadoop.hbase.HBaseClassTestRule; 030import org.apache.hadoop.hbase.HBaseTestingUtility; 031import org.apache.hadoop.hbase.HConstants; 032import org.apache.hadoop.hbase.NamespaceDescriptor; 033import org.apache.hadoop.hbase.TableName; 034import org.apache.hadoop.hbase.client.Admin; 035import org.apache.hadoop.hbase.client.Table; 036import org.apache.hadoop.hbase.security.User; 037import org.apache.hadoop.hbase.testclassification.LargeTests; 038import org.apache.hadoop.hbase.testclassification.RegionServerTests; 039import org.apache.hadoop.hbase.util.Bytes; 040import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 041import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread; 042import org.junit.After; 043import org.junit.AfterClass; 044import org.junit.BeforeClass; 045import org.junit.ClassRule; 046import org.junit.Test; 047import org.junit.experimental.categories.Category; 048 049@Category({ RegionServerTests.class, LargeTests.class }) 050public class TestClusterScopeQuotaThrottle { 051 052 @ClassRule 053 public static final HBaseClassTestRule CLASS_RULE = 054 HBaseClassTestRule.forClass(TestClusterScopeQuotaThrottle.class); 055 056 private final static int REFRESH_TIME = 30 * 60000; 057 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); 058 059 private final static TableName[] TABLE_NAMES = 060 new TableName[] { TableName.valueOf("TestQuotaAdmin0"), TableName.valueOf("TestQuotaAdmin1"), 061 TableName.valueOf("TestQuotaAdmin2") }; 062 private final static byte[] FAMILY = Bytes.toBytes("cf"); 063 private final static byte[] QUALIFIER = Bytes.toBytes("q"); 064 private final static byte[][] SPLITS = new byte[][] { Bytes.toBytes("1") }; 065 private static Table[] tables; 066 067 private final static String NAMESPACE = "TestNs"; 068 private final static TableName TABLE_NAME = TableName.valueOf(NAMESPACE, "TestTable"); 069 private static Table table; 070 071 @BeforeClass 072 public static void setUpBeforeClass() throws Exception { 073 TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, true); 074 TEST_UTIL.getConfiguration().setInt(QuotaCache.REFRESH_CONF_KEY, REFRESH_TIME); 075 TEST_UTIL.getConfiguration().setInt("hbase.hstore.compactionThreshold", 10); 076 TEST_UTIL.getConfiguration().setInt("hbase.regionserver.msginterval", 100); 077 TEST_UTIL.getConfiguration().setInt("hbase.client.pause", 250); 078 TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 6); 079 TEST_UTIL.getConfiguration().setBoolean("hbase.master.enabletable.roundrobin", true); 080 TEST_UTIL.startMiniCluster(2); 081 TEST_UTIL.waitTableAvailable(QuotaTableUtil.QUOTA_TABLE_NAME); 082 QuotaCache.TEST_FORCE_REFRESH = true; 083 084 tables = new Table[TABLE_NAMES.length]; 085 for (int i = 0; i < TABLE_NAMES.length; ++i) { 086 tables[i] = TEST_UTIL.createTable(TABLE_NAMES[i], FAMILY); 087 TEST_UTIL.waitTableAvailable(TABLE_NAMES[i]); 088 } 089 TEST_UTIL.getAdmin().createNamespace(NamespaceDescriptor.create(NAMESPACE).build()); 090 table = TEST_UTIL.createTable(TABLE_NAME, FAMILY, SPLITS); 091 TEST_UTIL.waitTableAvailable(TABLE_NAME); 092 } 093 094 @AfterClass 095 public static void tearDownAfterClass() throws Exception { 096 EnvironmentEdgeManager.reset(); 097 for (int i = 0; i < tables.length; ++i) { 098 if (tables[i] != null) { 099 tables[i].close(); 100 TEST_UTIL.deleteTable(TABLE_NAMES[i]); 101 } 102 } 103 TEST_UTIL.deleteTable(TABLE_NAME); 104 TEST_UTIL.getAdmin().deleteNamespace(NAMESPACE); 105 TEST_UTIL.shutdownMiniCluster(); 106 } 107 108 @After 109 public void tearDown() throws Exception { 110 ThrottleQuotaTestUtil.clearQuotaCache(TEST_UTIL); 111 } 112 113 @Test 114 public void testNamespaceClusterScopeQuota() throws Exception { 115 final Admin admin = TEST_UTIL.getAdmin(); 116 final String NAMESPACE = "default"; 117 118 // Add 10req/min limit for write request in cluster scope 119 admin.setQuota(QuotaSettingsFactory.throttleNamespace(NAMESPACE, ThrottleType.WRITE_NUMBER, 10, 120 TimeUnit.MINUTES, QuotaScope.CLUSTER)); 121 // Add 6req/min limit for read request in machine scope 122 admin.setQuota(QuotaSettingsFactory.throttleNamespace(NAMESPACE, ThrottleType.READ_NUMBER, 6, 123 TimeUnit.MINUTES, QuotaScope.MACHINE)); 124 triggerNamespaceCacheRefresh(TEST_UTIL, false, TABLE_NAMES[0]); 125 // should execute at max 5 write requests and at max 3 read requests 126 assertEquals(5, doPuts(10, FAMILY, QUALIFIER, tables[0])); 127 assertEquals(6, doGets(10, tables[0])); 128 // Remove all the limits 129 admin.setQuota(QuotaSettingsFactory.unthrottleNamespace(NAMESPACE)); 130 triggerNamespaceCacheRefresh(TEST_UTIL, true, TABLE_NAMES[0]); 131 } 132 133 @Test 134 public void testTableClusterScopeQuota() throws Exception { 135 final Admin admin = TEST_UTIL.getAdmin(); 136 admin.setQuota(QuotaSettingsFactory.throttleTable(TABLE_NAME, ThrottleType.READ_NUMBER, 20, 137 TimeUnit.HOURS, QuotaScope.CLUSTER)); 138 triggerTableCacheRefresh(TEST_UTIL, false, TABLE_NAME); 139 for (RegionServerThread rst : TEST_UTIL.getMiniHBaseCluster().getRegionServerThreads()) { 140 for (TableName tableName : rst.getRegionServer().getOnlineTables()) { 141 if (tableName.getNameAsString().equals(TABLE_NAME.getNameAsString())) { 142 int rsRegionNum = rst.getRegionServer().getRegions(tableName).size(); 143 if (rsRegionNum == 0) { 144 // If rs has 0 region, the machine limiter is 0 (20 * 0 / 2) 145 break; 146 } else if (rsRegionNum == 1) { 147 // If rs has 1 region, the machine limiter is 10 (20 * 1 / 2) 148 // Read rows from 1 region, so can read 10 first time and 0 second time 149 long count = doGets(20, table); 150 assertTrue(count == 0 || count == 10); 151 } else if (rsRegionNum == 2) { 152 // If rs has 2 regions, the machine limiter is 20 (20 * 2 / 2) 153 assertEquals(20, doGets(20, table)); 154 } 155 break; 156 } 157 } 158 } 159 admin.setQuota(QuotaSettingsFactory.unthrottleTable(TABLE_NAME)); 160 triggerTableCacheRefresh(TEST_UTIL, true, TABLE_NAME); 161 } 162 163 @Test 164 public void testUserClusterScopeQuota() throws Exception { 165 final Admin admin = TEST_UTIL.getAdmin(); 166 final String userName = User.getCurrent().getShortName(); 167 168 // Add 6req/min limit for read request in cluster scope 169 admin.setQuota(QuotaSettingsFactory.throttleUser(userName, ThrottleType.READ_NUMBER, 6, 170 TimeUnit.MINUTES, QuotaScope.CLUSTER)); 171 // Add 6req/min limit for write request in machine scope 172 admin.setQuota( 173 QuotaSettingsFactory.throttleUser(userName, ThrottleType.WRITE_NUMBER, 6, TimeUnit.MINUTES)); 174 triggerUserCacheRefresh(TEST_UTIL, false, TABLE_NAMES); 175 // should execute at max 6 read requests and at max 3 write write requests 176 assertEquals(6, doPuts(10, FAMILY, QUALIFIER, tables[0])); 177 assertEquals(3, doGets(10, tables[0])); 178 // Remove all the limits 179 admin.setQuota(QuotaSettingsFactory.unthrottleUser(userName)); 180 triggerUserCacheRefresh(TEST_UTIL, true, TABLE_NAMES); 181 } 182 183 @org.junit.Ignore 184 @Test // Spews the log w/ triggering of scheduler? HBASE-24035 185 public void testUserNamespaceClusterScopeQuota() throws Exception { 186 final Admin admin = TEST_UTIL.getAdmin(); 187 final String userName = User.getCurrent().getShortName(); 188 final String namespace = TABLE_NAMES[0].getNamespaceAsString(); 189 190 // Add 10req/min limit for read request in cluster scope 191 admin.setQuota(QuotaSettingsFactory.throttleUser(userName, namespace, ThrottleType.READ_NUMBER, 192 10, TimeUnit.MINUTES, QuotaScope.CLUSTER)); 193 // Add 6req/min limit for write request in machine scope 194 admin.setQuota(QuotaSettingsFactory.throttleUser(userName, namespace, ThrottleType.WRITE_NUMBER, 195 6, TimeUnit.MINUTES)); 196 triggerUserCacheRefresh(TEST_UTIL, false, TABLE_NAMES[0]); 197 // should execute at max 5 read requests and at max 6 write requests 198 assertEquals(5, doGets(10, tables[0])); 199 assertEquals(6, doPuts(10, FAMILY, QUALIFIER, tables[0])); 200 201 // Remove all the limits 202 admin.setQuota(QuotaSettingsFactory.unthrottleUser(userName, namespace)); 203 triggerUserCacheRefresh(TEST_UTIL, true, TABLE_NAMES[0]); 204 } 205 206 @Test 207 public void testUserTableClusterScopeQuota() throws Exception { 208 final Admin admin = TEST_UTIL.getAdmin(); 209 final String userName = User.getCurrent().getShortName(); 210 admin.setQuota(QuotaSettingsFactory.throttleUser(userName, TABLE_NAME, ThrottleType.READ_NUMBER, 211 20, TimeUnit.HOURS, QuotaScope.CLUSTER)); 212 triggerUserCacheRefresh(TEST_UTIL, false, TABLE_NAME); 213 for (RegionServerThread rst : TEST_UTIL.getMiniHBaseCluster().getRegionServerThreads()) { 214 for (TableName tableName : rst.getRegionServer().getOnlineTables()) { 215 if (tableName.getNameAsString().equals(TABLE_NAME.getNameAsString())) { 216 int rsRegionNum = rst.getRegionServer().getRegions(tableName).size(); 217 if (rsRegionNum == 0) { 218 // If rs has 0 region, the machine limiter is 0 (20 * 0 / 2) 219 break; 220 } else if (rsRegionNum == 1) { 221 // If rs has 1 region, the machine limiter is 10 (20 * 1 / 2) 222 // Read rows from 1 region, so can read 10 first time and 0 second time 223 long count = doGets(20, table); 224 assertTrue(count == 0 || count == 10); 225 } else if (rsRegionNum == 2) { 226 // If rs has 2 regions, the machine limiter is 20 (20 * 2 / 2) 227 assertEquals(20, doGets(20, table)); 228 } 229 break; 230 } 231 } 232 } 233 admin.setQuota(QuotaSettingsFactory.unthrottleUser(userName)); 234 triggerUserCacheRefresh(TEST_UTIL, true, TABLE_NAME); 235 } 236}