1
2
3
4
5
6
7
8
9
10
11
12 package org.apache.hadoop.hbase.coprocessor;
13
14 import java.io.IOException;
15 import java.nio.charset.StandardCharsets;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.concurrent.ConcurrentHashMap;
20 import org.apache.hadoop.hbase.Cell;
21 import org.apache.hadoop.hbase.CoprocessorEnvironment;
22 import org.apache.hadoop.hbase.TableName;
23 import org.apache.hadoop.hbase.classification.InterfaceAudience;
24 import org.apache.hadoop.hbase.client.Delete;
25 import org.apache.hadoop.hbase.client.Durability;
26 import org.apache.hadoop.hbase.client.Get;
27 import org.apache.hadoop.hbase.client.Put;
28 import org.apache.hadoop.hbase.client.Row;
29 import org.apache.hadoop.hbase.ipc.RpcServer;
30 import org.apache.hadoop.hbase.metrics.Meter;
31 import org.apache.hadoop.hbase.metrics.Metric;
32 import org.apache.hadoop.hbase.metrics.MetricRegistry;
33 import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
34 import org.apache.hadoop.hbase.util.LossyCounting;
35
36 import com.google.common.base.Optional;
37 import com.google.common.collect.ImmutableMap;
38
39
40
41
42
43
44
45
46
47 @InterfaceAudience.Private
48 public class MetaTableMetrics extends BaseRegionObserver {
49
50 private Map<String, Optional<Metric>> requestsMap;
51 private RegionCoprocessorEnvironment regionCoprocessorEnv;
52 private LossyCounting clientMetricsLossyCounting;
53 private boolean active = false;
54
55 enum MetaTableOps {
56 GET, PUT, DELETE;
57 }
58
59 private ImmutableMap<Class, MetaTableOps> opsNameMap =
60 ImmutableMap.<Class, MetaTableOps>builder()
61 .put(Put.class, MetaTableOps.PUT)
62 .put(Get.class, MetaTableOps.GET)
63 .put(Delete.class, MetaTableOps.DELETE)
64 .build();
65
66 @Override
67 public void preGetOp(ObserverContext<RegionCoprocessorEnvironment> e, Get get,
68 List<Cell> results) throws IOException {
69 if (!active || !isMetaTableOp(e)) {
70 return;
71 }
72 tableMetricRegisterAndMark(e, get);
73 clientMetricRegisterAndMark(e);
74 regionMetricRegisterAndMark(e, get);
75 opMetricRegisterAndMark(e, get);
76 opWithClientMetricRegisterAndMark(e, get);
77 }
78
79 @Override
80 public void prePut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit,
81 Durability durability) throws IOException {
82 if (!active || !isMetaTableOp(e)) {
83 return;
84 }
85 tableMetricRegisterAndMark(e, put);
86 clientMetricRegisterAndMark(e);
87 regionMetricRegisterAndMark(e, put);
88 opMetricRegisterAndMark(e, put);
89 opWithClientMetricRegisterAndMark(e, put);
90 }
91
92 @Override
93 public void preDelete(ObserverContext<RegionCoprocessorEnvironment> e, Delete delete,
94 WALEdit edit, Durability durability) throws IOException {
95 if (!active || !isMetaTableOp(e)) {
96 return;
97 }
98 tableMetricRegisterAndMark(e, delete);
99 clientMetricRegisterAndMark(e);
100 regionMetricRegisterAndMark(e, delete);
101 opMetricRegisterAndMark(e, delete);
102 opWithClientMetricRegisterAndMark(e, delete);
103 }
104
105 private void markMeterIfPresent(String requestMeter) {
106 if (requestMeter.isEmpty()) {
107 return;
108 }
109 Metric metric =
110 requestsMap.get(requestMeter).isPresent() ? requestsMap.get(requestMeter).get() : null;
111 if (metric != null) {
112 ((Meter) metric).mark();
113 }
114 }
115
116 private void registerMeterIfNotPresent(ObserverContext<RegionCoprocessorEnvironment> e,
117 String requestMeter) {
118 if (requestMeter.isEmpty()) {
119 return;
120 }
121 if (!requestsMap.containsKey(requestMeter)) {
122 MetricRegistry registry = regionCoprocessorEnv.getMetricRegistryForRegionServer();
123 registry.meter(requestMeter);
124 requestsMap.put(requestMeter, registry.get(requestMeter));
125 }
126 }
127
128
129
130
131
132
133
134
135
136
137 private void registerLossyCountingMeterIfNotPresent(
138 ObserverContext<RegionCoprocessorEnvironment> e,
139 String requestMeter, LossyCounting lossyCounting) {
140 if (requestMeter.isEmpty()) {
141 return;
142 }
143 Set<String> metersToBeRemoved = lossyCounting.addByOne(requestMeter);
144 if(!requestsMap.containsKey(requestMeter) && metersToBeRemoved.contains(requestMeter)){
145 for(String meter: metersToBeRemoved) {
146
147 requestsMap.remove(meter);
148 MetricRegistry registry = regionCoprocessorEnv.getMetricRegistryForRegionServer();
149 registry.remove(meter);
150 }
151
152 return;
153 }
154
155 if (!requestsMap.containsKey(requestMeter)) {
156 MetricRegistry registry = regionCoprocessorEnv.getMetricRegistryForRegionServer();
157 registry.meter(requestMeter);
158 requestsMap.put(requestMeter, registry.get(requestMeter));
159 }
160 }
161
162
163
164
165
166 private String getTableNameFromOp(Row op) {
167 String tableName = null;
168 String tableRowKey = new String(((Row) op).getRow(), StandardCharsets.UTF_8);
169 if (tableRowKey.isEmpty()) {
170 return null;
171 }
172 tableName = tableRowKey.split(",").length > 0 ? tableRowKey.split(",")[0] : null;
173 return tableName;
174 }
175
176
177
178
179
180 private String getRegionIdFromOp(Row op) {
181 String regionId = null;
182 String tableRowKey = new String(((Row) op).getRow(), StandardCharsets.UTF_8);
183 if (tableRowKey.isEmpty()) {
184 return null;
185 }
186 regionId = tableRowKey.split(",").length > 2 ? tableRowKey.split(",")[2] : null;
187 return regionId;
188 }
189
190 private boolean isMetaTableOp(ObserverContext<RegionCoprocessorEnvironment> e) {
191 return TableName.META_TABLE_NAME.toString()
192 .equals(new String(e.getEnvironment().getRegionInfo().getTable().getName(),
193 StandardCharsets.UTF_8));
194 }
195
196 private void clientMetricRegisterAndMark(ObserverContext<RegionCoprocessorEnvironment> e) {
197 String clientIP = RpcServer.getRemoteIp() != null ? RpcServer.getRemoteIp().toString() : "";
198
199 String clientRequestMeter = clientRequestMeterName(clientIP);
200 registerLossyCountingMeterIfNotPresent(e, clientRequestMeter, clientMetricsLossyCounting);
201 markMeterIfPresent(clientRequestMeter);
202 }
203
204 private void tableMetricRegisterAndMark(ObserverContext<RegionCoprocessorEnvironment> e,
205 Row op) {
206
207 String tableName = getTableNameFromOp(op);
208 String tableRequestMeter = tableMeterName(tableName);
209 registerMeterIfNotPresent(e, tableRequestMeter);
210 markMeterIfPresent(tableRequestMeter);
211 }
212
213 private void regionMetricRegisterAndMark(ObserverContext<RegionCoprocessorEnvironment> e,
214 Row op) {
215
216 String regionId = getRegionIdFromOp(op);
217 String regionRequestMeter = regionMeterName(regionId);
218 registerMeterIfNotPresent(e, regionRequestMeter);
219 markMeterIfPresent(regionRequestMeter);
220 }
221
222 private void opMetricRegisterAndMark(ObserverContext<RegionCoprocessorEnvironment> e,
223 Row op) {
224 String opMeterName = opMeterName(op);
225 registerMeterIfNotPresent(e, opMeterName);
226 markMeterIfPresent(opMeterName);
227 }
228
229 private void opWithClientMetricRegisterAndMark(ObserverContext<RegionCoprocessorEnvironment> e,
230 Object op) {
231 String opWithClientMeterName = opWithClientMeterName(op);
232 registerMeterIfNotPresent(e, opWithClientMeterName);
233 markMeterIfPresent(opWithClientMeterName);
234 }
235
236 private String opWithClientMeterName(Object op) {
237 String clientIP = RpcServer.getRemoteIp() != null ? RpcServer.getRemoteIp().toString() : "";
238 if (clientIP.isEmpty()) {
239 return "";
240 }
241 MetaTableOps ops = opsNameMap.get(op.getClass());
242 String opWithClientMeterName = "";
243 switch (ops) {
244 case GET:
245 opWithClientMeterName = String.format("MetaTable_client_%s_get_request", clientIP);
246 break;
247 case PUT:
248 opWithClientMeterName = String.format("MetaTable_client_%s_put_request", clientIP);
249 break;
250 case DELETE:
251 opWithClientMeterName = String.format("MetaTable_client_%s_delete_request", clientIP);
252 break;
253 default:
254 break;
255 }
256 return opWithClientMeterName;
257 }
258
259 private String opMeterName(Object op) {
260 MetaTableOps ops = opsNameMap.get(op.getClass());
261 String opMeterName = "";
262 switch (ops) {
263 case GET:
264 opMeterName = "MetaTable_get_request";
265 break;
266 case PUT:
267 opMeterName = "MetaTable_put_request";
268 break;
269 case DELETE:
270 opMeterName = "MetaTable_delete_request";
271 break;
272 default:
273 break;
274 }
275 return opMeterName;
276 }
277
278 private String tableMeterName(String tableName) {
279 return String.format("MetaTable_table_%s_request", tableName);
280 }
281
282 private String clientRequestMeterName(String clientIP) {
283 if (clientIP.isEmpty()) {
284 return "";
285 }
286 return String.format("MetaTable_client_%s_request", clientIP);
287 }
288
289 private String regionMeterName(String regionId) {
290 return String.format("MetaTable_region_%s_request", regionId);
291 }
292
293 @Override
294 public void start(CoprocessorEnvironment env) throws IOException {
295 if (env instanceof RegionCoprocessorEnvironment
296 && ((RegionCoprocessorEnvironment) env).getRegionInfo().getTable() != null
297 && ((RegionCoprocessorEnvironment) env).getRegionInfo().getTable()
298 .equals(TableName.META_TABLE_NAME)) {
299 regionCoprocessorEnv = (RegionCoprocessorEnvironment) env;
300 requestsMap = new ConcurrentHashMap<>();
301 clientMetricsLossyCounting = new LossyCounting();
302
303 active = true;
304 }
305 }
306
307 @Override
308 public void stop(CoprocessorEnvironment env) throws IOException {
309
310 if (requestsMap != null) {
311 for (String meterName : requestsMap.keySet()) {
312 MetricRegistry registry = regionCoprocessorEnv.getMetricRegistryForRegionServer();
313 registry.remove(meterName);
314 }
315 }
316 }
317
318 }