View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase.chaos.actions;
20  
21  import java.io.IOException;
22  import java.util.Collection;
23  import java.util.LinkedList;
24  import java.util.List;
25  
26  import org.apache.commons.lang.math.RandomUtils;
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.hadoop.hbase.ClusterStatus;
30  import org.apache.hadoop.hbase.HBaseCluster;
31  import org.apache.hadoop.hbase.HRegionInfo;
32  import org.apache.hadoop.hbase.IntegrationTestingUtility;
33  import org.apache.hadoop.hbase.ServerLoad;
34  import org.apache.hadoop.hbase.ServerName;
35  import org.apache.hadoop.hbase.chaos.monkies.PolicyBasedChaosMonkey;
36  import org.apache.hadoop.hbase.client.HBaseAdmin;
37  import org.apache.hadoop.hbase.util.Bytes;
38  
39  /**
40   * A (possibly mischievous) action that the ChaosMonkey can perform.
41   */
42  public class Action {
43  
44    protected static Log LOG = LogFactory.getLog(Action.class);
45  
46    protected ActionContext context;
47    protected HBaseCluster cluster;
48    protected ClusterStatus initialStatus;
49    protected ServerName[] initialServers;
50  
51    public void init(ActionContext context) throws IOException {
52      this.context = context;
53      cluster = context.getHBaseCluster();
54      initialStatus = cluster.getInitialClusterStatus();
55      Collection<ServerName> regionServers = initialStatus.getServers();
56      initialServers = regionServers.toArray(new ServerName[regionServers.size()]);
57    }
58  
59    public void perform() throws Exception { }
60  
61    /** Returns current region servers */
62    protected ServerName[] getCurrentServers() throws IOException {
63      Collection<ServerName> regionServers = cluster.getClusterStatus().getServers();
64      if (regionServers == null || regionServers.size() <= 0) return new ServerName [] {};
65      return regionServers.toArray(new ServerName[regionServers.size()]);
66    }
67  
68    protected void killMaster(ServerName server) throws IOException {
69      LOG.info("Killing master:" + server);
70      cluster.killMaster(server);
71      cluster.waitForMasterToStop(server, PolicyBasedChaosMonkey.TIMEOUT);
72      LOG.info("Killed master server:" + server);
73    }
74  
75    protected void startMaster(ServerName server) throws IOException {
76      LOG.info("Starting master:" + server.getHostname());
77      cluster.startMaster(server.getHostname());
78      cluster.waitForActiveAndReadyMaster(PolicyBasedChaosMonkey.TIMEOUT);
79      LOG.info("Started master: " + server);
80    }
81  
82    protected void killRs(ServerName server) throws IOException {
83      LOG.info("Killing region server:" + server);
84      cluster.killRegionServer(server);
85      cluster.waitForRegionServerToStop(server, PolicyBasedChaosMonkey.TIMEOUT);
86      LOG.info("Killed region server:" + server + ". Reported num of rs:"
87          + cluster.getClusterStatus().getServersSize());
88    }
89  
90    protected void startRs(ServerName server) throws IOException {
91      LOG.info("Starting region server:" + server.getHostname());
92      cluster.startRegionServer(server.getHostname());
93      cluster.waitForRegionServerToStart(server.getHostname(), PolicyBasedChaosMonkey.TIMEOUT);
94      LOG.info("Started region server:" + server + ". Reported num of rs:"
95          + cluster.getClusterStatus().getServersSize());
96    }
97  
98    protected void unbalanceRegions(ClusterStatus clusterStatus,
99        List<ServerName> fromServers, List<ServerName> toServers,
100       double fractionOfRegions) throws Exception {
101     List<byte[]> victimRegions = new LinkedList<byte[]>();
102     for (ServerName server : fromServers) {
103       ServerLoad serverLoad = clusterStatus.getLoad(server);
104       // Ugh.
105       List<byte[]> regions = new LinkedList<byte[]>(serverLoad.getRegionsLoad().keySet());
106       int victimRegionCount = (int)Math.ceil(fractionOfRegions * regions.size());
107       LOG.debug("Removing " + victimRegionCount + " regions from " + server.getServerName());
108       for (int i = 0; i < victimRegionCount; ++i) {
109         int victimIx = RandomUtils.nextInt(regions.size());
110         String regionId = HRegionInfo.encodeRegionName(regions.remove(victimIx));
111         victimRegions.add(Bytes.toBytes(regionId));
112       }
113     }
114 
115     LOG.info("Moving " + victimRegions.size() + " regions from " + fromServers.size()
116         + " servers to " + toServers.size() + " different servers");
117     HBaseAdmin admin = this.context.getHBaseIntegrationTestingUtility().getHBaseAdmin();
118     for (byte[] victimRegion : victimRegions) {
119       int targetIx = RandomUtils.nextInt(toServers.size());
120       admin.move(victimRegion, Bytes.toBytes(toServers.get(targetIx).getServerName()));
121     }
122   }
123 
124   protected void forceBalancer() throws Exception {
125     HBaseAdmin admin = this.context.getHBaseIntegrationTestingUtility().getHBaseAdmin();
126     boolean result = admin.balancer();
127     if (!result) {
128       LOG.error("Balancer didn't succeed");
129     }
130   }
131 
132   /**
133    * Context for Action's
134    */
135   public static class ActionContext {
136     private IntegrationTestingUtility util;
137 
138     public ActionContext(IntegrationTestingUtility util) {
139       this.util = util;
140     }
141 
142     public IntegrationTestingUtility getHBaseIntegrationTestingUtility() {
143       return util;
144     }
145 
146     public HBaseCluster getHBaseCluster() {
147       return util.getHBaseClusterInterface();
148     }
149   }
150 }