View Javadoc

1   /*
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  package org.apache.hadoop.hbase.replication.regionserver;
21  
22  import java.io.IOException;
23  import java.util.concurrent.atomic.AtomicLong;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.hbase.HBaseConfiguration;
29  import org.apache.hadoop.hbase.HBaseTestingUtility;
30  import org.apache.hadoop.hbase.HColumnDescriptor;
31  import org.apache.hadoop.hbase.HConstants;
32  import org.apache.hadoop.hbase.HTableDescriptor;
33  import org.apache.hadoop.hbase.HTestConst;
34  import org.apache.hadoop.hbase.TableName;
35  import org.apache.hadoop.hbase.client.Put;
36  import org.apache.hadoop.hbase.client.Result;
37  import org.apache.hadoop.hbase.client.ResultScanner;
38  import org.apache.hadoop.hbase.client.Scan;
39  import org.apache.hadoop.hbase.client.Table;
40  import org.apache.hadoop.hbase.client.replication.ReplicationAdmin;
41  import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
42  import org.apache.hadoop.hbase.testclassification.LargeTests;
43  import org.apache.hadoop.hbase.testclassification.ReplicationTests;
44  import org.apache.hadoop.hbase.util.Bytes;
45  import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
46  import org.apache.hadoop.hbase.util.Threads;
47  import org.apache.hadoop.hbase.zookeeper.MiniZooKeeperCluster;
48  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
49  import org.junit.AfterClass;
50  import org.junit.Assert;
51  import org.junit.BeforeClass;
52  import org.junit.Test;
53  import org.junit.experimental.categories.Category;
54  
55  @Category({ ReplicationTests.class, LargeTests.class })
56  public class TestGlobalReplicationThrottler {
57    private static final Log LOG = LogFactory.getLog(TestGlobalReplicationThrottler.class);
58    private static final int REPLICATION_SOURCE_QUOTA = 200;
59    private static int numOfPeer = 0;
60    private static Configuration conf1;
61    private static Configuration conf2;
62  
63    private static HBaseTestingUtility utility1;
64    private static HBaseTestingUtility utility2;
65  
66    private static final byte[] famName = Bytes.toBytes("f");
67    private static final byte[] VALUE = Bytes.toBytes("v");
68    private static final byte[] ROW = Bytes.toBytes("r");
69    private static final byte[][] ROWS = HTestConst.makeNAscii(ROW, 100);
70  
71    @BeforeClass
72    public static void setUpBeforeClass() throws Exception {
73      conf1 = HBaseConfiguration.create();
74      conf1.set(HConstants.ZOOKEEPER_ZNODE_PARENT, "/1");
75      conf1.setLong("replication.source.sleepforretries", 100);
76      // Each WAL is about 120 bytes
77      conf1.setInt(HConstants.REPLICATION_SOURCE_TOTAL_BUFFER_KEY, 200);
78      conf1.setLong("replication.source.per.peer.node.bandwidth", 100L);
79  
80      utility1 = new HBaseTestingUtility(conf1);
81      utility1.startMiniZKCluster();
82      MiniZooKeeperCluster miniZK = utility1.getZkCluster();
83      new ZooKeeperWatcher(conf1, "cluster1", null, true);
84  
85      conf2 = new Configuration(conf1);
86      conf2.set(HConstants.ZOOKEEPER_ZNODE_PARENT, "/2");
87  
88      utility2 = new HBaseTestingUtility(conf2);
89      utility2.setZkCluster(miniZK);
90      new ZooKeeperWatcher(conf2, "cluster2", null, true);
91  
92      ReplicationAdmin admin1 = new ReplicationAdmin(conf1);
93      ReplicationPeerConfig rpc = new ReplicationPeerConfig();
94      rpc.setClusterKey(utility2.getClusterKey());
95      admin1.addPeer("peer1", rpc, null);
96      admin1.addPeer("peer2", rpc, null);
97      admin1.addPeer("peer3", rpc, null);
98      numOfPeer = admin1.getPeersCount();
99  
100     utility1.startMiniCluster(1, 1);
101     utility2.startMiniCluster(1, 1);
102   }
103 
104   @AfterClass
105   public static void tearDownAfterClass() throws Exception {
106     utility2.shutdownMiniCluster();
107     utility1.shutdownMiniCluster();
108   }
109 
110   volatile private boolean testQuotaPass = false;
111 
112   @Test
113   public void testQuota() throws IOException {
114     TableName tableName = TableName.valueOf("testQuota");
115     HTableDescriptor table = new HTableDescriptor(tableName);
116     HColumnDescriptor fam = new HColumnDescriptor(famName);
117     fam.setScope(HConstants.REPLICATION_SCOPE_LOCAL);
118     table.addFamily(fam);
119     utility1.getHBaseAdmin().createTable(table);
120     utility2.getHBaseAdmin().createTable(table);
121 
122     Thread watcher = new Thread(new Runnable() {
123       @Override
124       public void run() {
125         Replication replication = (Replication) utility1.getMiniHBaseCluster()
126             .getRegionServer(0).getReplicationSourceService();
127         AtomicLong bufferUsed = replication.getReplicationManager().getTotalBufferUsed();
128         testQuotaPass = true;
129         while (!Thread.interrupted()) {
130           long size = bufferUsed.get();
131           //the reason here doing "numOfPeer + 1" is because by using method addEntryToBatch(), even the
132           // batch size (after added last entry) exceeds quota, it still keeps the last one in the batch
133           // so total used buffer size can be one "replication.total.buffer.quota" larger than expected
134           if (size > REPLICATION_SOURCE_QUOTA * (numOfPeer + 1)) {
135             // We read logs first then check throttler, so if the buffer quota limiter doesn't
136             // take effect, it will push many logs and exceed the quota.
137             testQuotaPass = false;
138           }
139           Threads.sleep(50);
140         }
141       }
142     });
143 
144     watcher.start();
145 
146     try(Table t1 = utility1.getConnection().getTable(tableName);
147         Table t2 = utility2.getConnection().getTable(tableName)) {
148       for (int i = 0; i < 50; i++) {
149         Put put = new Put(ROWS[i]);
150         put.addColumn(famName, VALUE, VALUE);
151         t1.put(put);
152       }
153       long start = EnvironmentEdgeManager.currentTime();
154       while (EnvironmentEdgeManager.currentTime() - start < 180000) {
155         Scan scan = new Scan();
156         scan.setCaching(50);
157         int count = 0;
158         try (ResultScanner results = t2.getScanner(scan)) {
159           for (Result result : results) {
160             count++;
161           }
162         }
163         if (count < 50) {
164           LOG.info("Waiting all logs pushed to slave. Expected 50 , actual " + count);
165           Threads.sleep(200);
166           continue;
167         }
168         break;
169       }
170     }
171 
172     watcher.interrupt();
173     Assert.assertTrue(testQuotaPass);
174   }
175 }