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