All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.hadoop.hbase.coprocessor.MetaTableMetrics Maven / Gradle / Ivy

There is a newer version: 3.0.0-beta-1
Show newest version
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License. You may obtain a
 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
 * law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 * for the specific language governing permissions and limitations under the License.
 */

package org.apache.hadoop.hbase.coprocessor;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CoprocessorEnvironment;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Durability;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Row;
import org.apache.hadoop.hbase.ipc.RpcServer;
import org.apache.hadoop.hbase.metrics.Meter;
import org.apache.hadoop.hbase.metrics.Metric;
import org.apache.hadoop.hbase.metrics.MetricRegistry;
import org.apache.hadoop.hbase.util.LossyCounting;
import org.apache.hadoop.hbase.wal.WALEdit;
import org.apache.yetus.audience.InterfaceAudience;
import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableMap;


/**
 * A coprocessor that collects metrics from meta table.
 * 

* These metrics will be available through the regular Hadoop metrics2 sinks (ganglia, opentsdb, * etc) as well as JMX output. *

* @see MetaTableMetrics */ @InterfaceAudience.Private public class MetaTableMetrics implements RegionCoprocessor { private ExampleRegionObserverMeta observer; private Map> requestsMap; private MetricRegistry registry; private LossyCounting clientMetricsLossyCounting, regionMetricsLossyCounting; private boolean active = false; enum MetaTableOps { GET, PUT, DELETE; } private ImmutableMap opsNameMap = ImmutableMap.builder() .put(Put.class, MetaTableOps.PUT) .put(Get.class, MetaTableOps.GET) .put(Delete.class, MetaTableOps.DELETE) .build(); class ExampleRegionObserverMeta implements RegionCoprocessor, RegionObserver { @Override public Optional getRegionObserver() { return Optional.of(this); } @Override public void preGetOp(ObserverContext e, Get get, List results) throws IOException { registerAndMarkMetrics(e, get); } @Override public void prePut(ObserverContext e, Put put, WALEdit edit, Durability durability) throws IOException { registerAndMarkMetrics(e, put); } @Override public void preDelete(ObserverContext e, Delete delete, WALEdit edit, Durability durability) throws IOException { registerAndMarkMetrics(e, delete); } private void registerAndMarkMetrics(ObserverContext e, Row row){ if (!active || !isMetaTableOp(e)) { return; } tableMetricRegisterAndMark(row); clientMetricRegisterAndMark(); regionMetricRegisterAndMark(row); opMetricRegisterAndMark(row); opWithClientMetricRegisterAndMark(row); } private void markMeterIfPresent(String requestMeter) { if (requestMeter.isEmpty()) { return; } Optional optionalMetric = requestsMap.get(requestMeter); if (optionalMetric != null && optionalMetric.isPresent()) { Meter metric = (Meter) optionalMetric.get(); metric.mark(); } } private void registerMeterIfNotPresent(String requestMeter) { if (requestMeter.isEmpty()) { return; } if (!requestsMap.containsKey(requestMeter)) { registry.meter(requestMeter); requestsMap.put(requestMeter, registry.get(requestMeter)); } } /** * Registers and counts lossyCount for Meters that kept by lossy counting. * By using lossy count to maintain meters, at most 7 / e meters will be kept (e is error rate) * e.g. when e is 0.02 by default, at most 350 Clients request metrics will be kept * also, all kept elements have frequency higher than e * N. (N is total count) * @param requestMeter meter to be registered * @param lossyCounting lossyCounting object for one type of meters. */ private void registerLossyCountingMeterIfNotPresent(String requestMeter, LossyCounting lossyCounting) { if (requestMeter.isEmpty()) { return; } synchronized (lossyCounting) { Set metersToBeRemoved = lossyCounting.addByOne(requestMeter); boolean isNewMeter = !requestsMap.containsKey(requestMeter); boolean requestMeterRemoved = metersToBeRemoved.contains(requestMeter); if (isNewMeter) { if (requestMeterRemoved) { // if the new metric is swept off by lossyCounting then don't add in the map metersToBeRemoved.remove(requestMeter); } else { // else register the new metric and add in the map registry.meter(requestMeter); requestsMap.put(requestMeter, registry.get(requestMeter)); } } for (String meter : metersToBeRemoved) { //cleanup requestsMap according to the swept data from lossy count; requestsMap.remove(meter); registry.remove(meter); } } } /** * Get table name from Ops such as: get, put, delete. * @param op such as get, put or delete. */ private String getTableNameFromOp(Row op) { String tableName = null; String tableRowKey = new String(((Row) op).getRow(), StandardCharsets.UTF_8); if (tableRowKey.isEmpty()) { return null; } tableName = tableRowKey.split(",").length > 0 ? tableRowKey.split(",")[0] : null; return tableName; } /** * Get regionId from Ops such as: get, put, delete. * @param op such as get, put or delete. */ private String getRegionIdFromOp(Row op) { String regionId = null; String tableRowKey = new String(((Row) op).getRow(), StandardCharsets.UTF_8); if (tableRowKey.isEmpty()) { return null; } regionId = tableRowKey.split(",").length > 2 ? tableRowKey.split(",")[2] : null; return regionId; } private boolean isMetaTableOp(ObserverContext e) { return TableName.META_TABLE_NAME .equals(e.getEnvironment().getRegionInfo().getTable()); } private void clientMetricRegisterAndMark() { // Mark client metric String clientIP = RpcServer.getRemoteIp() != null ? RpcServer.getRemoteIp().toString() : ""; if (clientIP == null || clientIP.isEmpty()) { return; } String clientRequestMeter = clientRequestMeterName(clientIP); registerLossyCountingMeterIfNotPresent(clientRequestMeter, clientMetricsLossyCounting); markMeterIfPresent(clientRequestMeter); } private void tableMetricRegisterAndMark(Row op) { // Mark table metric String tableName = getTableNameFromOp(op); if (tableName == null || tableName.isEmpty()) { return; } String tableRequestMeter = tableMeterName(tableName); registerAndMarkMeterIfNotPresent(tableRequestMeter); } private void regionMetricRegisterAndMark(Row op) { // Mark region metric String regionId = getRegionIdFromOp(op); if (regionId == null || regionId.isEmpty()) { return; } String regionRequestMeter = regionMeterName(regionId); registerLossyCountingMeterIfNotPresent(regionRequestMeter, regionMetricsLossyCounting); markMeterIfPresent(regionRequestMeter); } private void opMetricRegisterAndMark(Row op) { // Mark access type ["get", "put", "delete"] metric String opMeterName = opMeterName(op); if (opMeterName == null || opMeterName.isEmpty()) { return; } registerAndMarkMeterIfNotPresent(opMeterName); } private void opWithClientMetricRegisterAndMark(Object op) { // // Mark client + access type metric String opWithClientMeterName = opWithClientMeterName(op); if (opWithClientMeterName == null || opWithClientMeterName.isEmpty()) { return; } registerAndMarkMeterIfNotPresent(opWithClientMeterName); } // Helper function to register and mark meter if not present private void registerAndMarkMeterIfNotPresent(String name) { registerMeterIfNotPresent(name); markMeterIfPresent(name); } private String opWithClientMeterName(Object op) { // Extract meter name containing the client IP String clientIP = RpcServer.getRemoteIp() != null ? RpcServer.getRemoteIp().toString() : ""; if (clientIP.isEmpty()) { return ""; } MetaTableOps ops = opsNameMap.get(op.getClass()); String opWithClientMeterName = ""; switch (ops) { case GET: opWithClientMeterName = String.format("MetaTable_client_%s_get_request", clientIP); break; case PUT: opWithClientMeterName = String.format("MetaTable_client_%s_put_request", clientIP); break; case DELETE: opWithClientMeterName = String.format("MetaTable_client_%s_delete_request", clientIP); break; default: break; } return opWithClientMeterName; } private String opMeterName(Object op) { // Extract meter name containing the access type MetaTableOps ops = opsNameMap.get(op.getClass()); String opMeterName = ""; switch (ops) { case GET: opMeterName = "MetaTable_get_request"; break; case PUT: opMeterName = "MetaTable_put_request"; break; case DELETE: opMeterName = "MetaTable_delete_request"; break; default: break; } return opMeterName; } private String tableMeterName(String tableName) { // Extract meter name containing the table name return String.format("MetaTable_table_%s_request", tableName); } private String clientRequestMeterName(String clientIP) { // Extract meter name containing the client IP if (clientIP.isEmpty()) { return ""; } return String.format("MetaTable_client_%s_lossy_request", clientIP); } private String regionMeterName(String regionId) { // Extract meter name containing the region ID return String.format("MetaTable_region_%s_lossy_request", regionId); } } @Override public Optional getRegionObserver() { return Optional.of(observer); } @Override public void start(CoprocessorEnvironment env) throws IOException { observer = new ExampleRegionObserverMeta(); if (env instanceof RegionCoprocessorEnvironment && ((RegionCoprocessorEnvironment) env).getRegionInfo().getTable() != null && ((RegionCoprocessorEnvironment) env).getRegionInfo().getTable() .equals(TableName.META_TABLE_NAME)) { RegionCoprocessorEnvironment regionCoprocessorEnv = (RegionCoprocessorEnvironment) env; registry = regionCoprocessorEnv.getMetricRegistryForRegionServer(); requestsMap = new ConcurrentHashMap<>(); clientMetricsLossyCounting = new LossyCounting("clientMetaMetrics"); regionMetricsLossyCounting = new LossyCounting("regionMetaMetrics"); // only be active mode when this region holds meta table. active = true; } } @Override public void stop(CoprocessorEnvironment env) throws IOException { // since meta region can move around, clear stale metrics when stop. if (requestsMap != null) { for (String meterName : requestsMap.keySet()) { registry.remove(meterName); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy