Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,16 @@
import org.apache.hadoop.hbase.CallQueueTooBigException;
import org.apache.hadoop.hbase.CellScanner;
import org.apache.hadoop.hbase.DoNotRetryIOException;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.Server;
import org.apache.hadoop.hbase.conf.ConfigurationObserver;
import org.apache.hadoop.hbase.exceptions.RequestTooBigException;
import org.apache.hadoop.hbase.io.ByteBuffAllocator;
import org.apache.hadoop.hbase.monitoring.MonitoredRPCHandler;
import org.apache.hadoop.hbase.monitoring.TaskMonitor;
import org.apache.hadoop.hbase.regionserver.RSRpcServices;
import org.apache.hadoop.hbase.regionserver.slowlog.RpcLogDetails;
import org.apache.hadoop.hbase.regionserver.slowlog.SlowLogRecorder;
import org.apache.hadoop.hbase.namequeues.RpcLogDetails;
import org.apache.hadoop.hbase.namequeues.NamedQueueRecorder;
import org.apache.hadoop.hbase.security.HBasePolicyProvider;
import org.apache.hadoop.hbase.security.SaslUtil;
import org.apache.hadoop.hbase.security.SaslUtil.QualityOfProtection;
Expand Down Expand Up @@ -94,10 +95,9 @@ public abstract class RpcServer implements RpcServerInterface,
private static final String MULTI_GETS = "multi.gets";
private static final String MULTI_MUTATIONS = "multi.mutations";
private static final String MULTI_SERVICE_CALLS = "multi.service_calls";
private static final String GET_SLOW_LOG_RESPONSES = "GetSlowLogResponses";
private static final String CLEAR_SLOW_LOGS_RESPONSES = "ClearSlowLogsResponses";

private final boolean authorize;
private final boolean isOnlineLogProviderEnabled;
protected boolean isSecurityEnabled;

public static final byte CURRENT_VERSION = 0;
Expand Down Expand Up @@ -229,7 +229,7 @@ public abstract class RpcServer implements RpcServerInterface,
/**
* Use to add online slowlog responses
*/
private SlowLogRecorder slowLogRecorder;
private NamedQueueRecorder namedQueueRecorder;

@FunctionalInterface
protected interface CallCleanup {
Expand Down Expand Up @@ -304,6 +304,8 @@ public RpcServer(final Server server, final String name,
saslProps = Collections.emptyMap();
}

this.isOnlineLogProviderEnabled = conf.getBoolean(HConstants.SLOW_LOG_BUFFER_ENABLED_KEY,
HConstants.DEFAULT_ONLINE_LOG_PROVIDER_ENABLED);
this.scheduler = scheduler;
}

Expand Down Expand Up @@ -432,11 +434,11 @@ public Pair<Message, CellScanner> call(RpcCall call,
tooLarge, tooSlow,
status.getClient(), startTime, processingTime, qTime,
responseSize, userName);
if (this.slowLogRecorder != null) {
if (this.namedQueueRecorder != null && this.isOnlineLogProviderEnabled) {
// send logs to ring buffer owned by slowLogRecorder
final String className = server == null ? StringUtils.EMPTY :
server.getClass().getSimpleName();
this.slowLogRecorder.addSlowLogPayload(
final String className =
server == null ? StringUtils.EMPTY : server.getClass().getSimpleName();
this.namedQueueRecorder.addRecord(
new RpcLogDetails(call, param, status.getClient(), responseSize, className, tooSlow,
tooLarge));
}
Expand Down Expand Up @@ -819,12 +821,8 @@ public void setRsRpcServices(RSRpcServices rsRpcServices) {
}

@Override
public void setSlowLogRecorder(SlowLogRecorder slowLogRecorder) {
this.slowLogRecorder = slowLogRecorder;
public void setNamedQueueRecorder(NamedQueueRecorder namedQueueRecorder) {
this.namedQueueRecorder = namedQueueRecorder;
}

@Override
public SlowLogRecorder getSlowLogRecorder() {
return slowLogRecorder;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import org.apache.hadoop.hbase.io.ByteBuffAllocator;
import org.apache.hadoop.hbase.monitoring.MonitoredRPCHandler;
import org.apache.hadoop.hbase.regionserver.RSRpcServices;
import org.apache.hadoop.hbase.regionserver.slowlog.SlowLogRecorder;
import org.apache.hadoop.hbase.namequeues.NamedQueueRecorder;
import org.apache.hadoop.hbase.util.Pair;
import org.apache.hadoop.security.authorize.PolicyProvider;
import org.apache.yetus.audience.InterfaceAudience;
Expand Down Expand Up @@ -102,12 +102,8 @@ Pair<Message, CellScanner> call(RpcCall call, MonitoredRPCHandler status)
/**
* Set Online SlowLog Provider
*
* @param slowLogRecorder instance of {@link SlowLogRecorder}
* @param namedQueueRecorder instance of {@link NamedQueueRecorder}
*/
void setSlowLogRecorder(final SlowLogRecorder slowLogRecorder);
void setNamedQueueRecorder(final NamedQueueRecorder namedQueueRecorder);

/**
* @return Retrieve instance of {@link SlowLogRecorder} maintained by RpcServer
*/
SlowLogRecorder getSlowLogRecorder();
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* limitations under the License.
*/

package org.apache.hadoop.hbase.regionserver.slowlog;
package org.apache.hadoop.hbase.namequeues;

import com.lmax.disruptor.ExceptionHandler;
import org.apache.yetus.audience.InterfaceAudience;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,24 @@
* limitations under the License.
*/

package org.apache.hadoop.hbase.regionserver.slowlog;
package org.apache.hadoop.hbase.namequeues;

import com.lmax.disruptor.EventHandler;
import com.lmax.disruptor.RingBuffer;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.client.SlowLogParams;
import org.apache.hadoop.hbase.ipc.RpcCall;
import org.apache.hadoop.hbase.slowlog.SlowLogTableAccessor;
import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -50,64 +50,83 @@
import org.apache.hadoop.hbase.shaded.protobuf.generated.TooSlowLog.SlowLogPayload;

/**
* Event Handler run by disruptor ringbuffer consumer
* Event Handler run by disruptor ringbuffer consumer.
* Although this is generic implementation for namedQueue, it can have individual queue specific
Comment thread
virajjasani marked this conversation as resolved.
* logic.
*/
@InterfaceAudience.Private
class LogEventHandler implements EventHandler<RingBufferEnvelope> {

private static final Logger LOG = LoggerFactory.getLogger(LogEventHandler.class);

private static final String SYS_TABLE_QUEUE_SIZE =
"hbase.regionserver.slowlog.systable.queue.size";
private static final int DEFAULT_SYS_TABLE_QUEUE_SIZE = 1000;
private static final int SYSTABLE_PUT_BATCH_SIZE = 100;
private static final String SLOW_LOG_RING_BUFFER_SIZE =
"hbase.regionserver.slowlog.ringbuffer.size";

// Map that binds namedQueues.
// If NamedQueue of specific type is enabled, corresponding Queue will be used to
// insert and retrieve records.
// Individual queue sizes should be determined based on their individual configs.
private final Map<NamedQueuePayload.NamedQueueEvent, Queue> namedQueues = new HashMap<>();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, the caller should be able to determine which queue implementations (and its related services) should be loaded. That would isolate LogEventHandler from being constantly modified by additional services requiring this type of loggings.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strategy pattern is good thought but we don't have common payload coming from client so far. Specifically when admin client will talk to RSRpcServer and that will talk to LogEventHandler, they expect specific payload for specific use-case. However, this fits well for strategy pattern and we should have common request payload. Let me try this one. Thanks for the suggestion @wchevreuil .


private final Queue<SlowLogPayload> queueForRingBuffer;
private final Queue<SlowLogPayload> queueForSysTable;
private final boolean isSlowLogTableEnabled;
private final SlowLogPersistentService slowLogPersistentService;

private Configuration configuration;
LogEventHandler(final Configuration conf) {
// Initialize SlowLog Queue
int slowLogQueueSize = conf.getInt(SLOW_LOG_RING_BUFFER_SIZE,
HConstants.DEFAULT_SLOW_LOG_RING_BUFFER_SIZE);
EvictingQueue<SlowLogPayload> evictingQueue = EvictingQueue.create(slowLogQueueSize);

private static final ReentrantLock LOCK = new ReentrantLock();
// Add slowLog queue in the namedQueue map
Queue<SlowLogPayload> slowLogQueue = Queues.synchronizedQueue(evictingQueue);
namedQueues.put(NamedQueuePayload.NamedQueueEvent.SLOW_LOG, slowLogQueue);

LogEventHandler(int eventCount, boolean isSlowLogTableEnabled, Configuration conf) {
this.configuration = conf;
EvictingQueue<SlowLogPayload> evictingQueue = EvictingQueue.create(eventCount);
queueForRingBuffer = Queues.synchronizedQueue(evictingQueue);
this.isSlowLogTableEnabled = isSlowLogTableEnabled;
this.isSlowLogTableEnabled = conf.getBoolean(HConstants.SLOW_LOG_SYS_TABLE_ENABLED_KEY,
HConstants.DEFAULT_SLOW_LOG_SYS_TABLE_ENABLED_KEY);
if (isSlowLogTableEnabled) {
int sysTableQueueSize = conf.getInt(SYS_TABLE_QUEUE_SIZE, DEFAULT_SYS_TABLE_QUEUE_SIZE);
EvictingQueue<SlowLogPayload> evictingQueueForTable =
EvictingQueue.create(sysTableQueueSize);
queueForSysTable = Queues.synchronizedQueue(evictingQueueForTable);
slowLogPersistentService = new SlowLogPersistentService(conf);
} else {
queueForSysTable = null;
slowLogPersistentService = null;
}
}

/**
* Called when a publisher has published an event to the {@link RingBuffer}
* Called when a publisher has published an event to the {@link RingBuffer}.
* This is generic consumer of disruptor ringbuffer and for each new namedQueue that we
* add, we should also provide specific consumer logic here.
*
* @param event published to the {@link RingBuffer}
* @param sequence of the event being processed
* @param endOfBatch flag to indicate if this is the last event in a batch from
* the {@link RingBuffer}
* @throws Exception if the EventHandler would like the exception handled further up the chain
*/
@Override
public void onEvent(RingBufferEnvelope event, long sequence, boolean endOfBatch)
throws Exception {
final RpcLogDetails rpcCallDetails = event.getPayload();
final RpcCall rpcCall = rpcCallDetails.getRpcCall();
final String clientAddress = rpcCallDetails.getClientAddress();
final long responseSize = rpcCallDetails.getResponseSize();
final String className = rpcCallDetails.getClassName();
final SlowLogPayload.Type type = getLogType(rpcCallDetails);
public void onEvent(RingBufferEnvelope event, long sequence, boolean endOfBatch) {
final NamedQueuePayload namedQueuePayload = event.getPayload();
// consume ringbuffer payload based on event type
if (NamedQueuePayload.NamedQueueEvent.SLOW_LOG
.equals(namedQueuePayload.getNamedQueueEvent())) {
consumeSlowLogEvent((RpcLogDetails) namedQueuePayload);
}
}

/**
* This implementation is specific to slowLog event. This consumes slowLog event from
* disruptor and inserts records to EvictingQueue.
*
* @param rpcLogDetails Input for slow/largeLog events
*/
private void consumeSlowLogEvent(RpcLogDetails rpcLogDetails) {
final RpcCall rpcCall = rpcLogDetails.getRpcCall();
final String clientAddress = rpcLogDetails.getClientAddress();
final long responseSize = rpcLogDetails.getResponseSize();
final String className = rpcLogDetails.getClassName();
final SlowLogPayload.Type type = getLogType(rpcLogDetails);
if (type == null) {
return;
}
Descriptors.MethodDescriptor methodDescriptor = rpcCall.getMethod();
Message param = rpcCallDetails.getParam();
Message param = rpcLogDetails.getParam();
long receiveTime = rpcCall.getReceiveTime();
long startTime = rpcCall.getStartTime();
long endTime = System.currentTimeMillis();
Expand Down Expand Up @@ -153,10 +172,10 @@ public void onEvent(RingBufferEnvelope event, long sequence, boolean endOfBatch)
.setType(type)
.setUserName(userName)
.build();
queueForRingBuffer.add(slowLogPayload);
namedQueues.get(NamedQueuePayload.NamedQueueEvent.SLOW_LOG).add(slowLogPayload);
if (isSlowLogTableEnabled) {
if (!slowLogPayload.getRegionName().startsWith("hbase:slowlog")) {
queueForSysTable.add(slowLogPayload);
slowLogPersistentService.addToQueueForSysTable(slowLogPayload);
}
}
}
Expand All @@ -183,13 +202,12 @@ private SlowLogPayload.Type getLogType(RpcLogDetails rpcCallDetails) {
/**
* Cleans up slow log payloads
*
* @param namedQueueEvent type of queue to clear
* @return true if slow log payloads are cleaned up, false otherwise
*/
boolean clearSlowLogs() {
if (LOG.isDebugEnabled()) {
LOG.debug("Received request to clean up online slowlog buffer..");
}
queueForRingBuffer.clear();
boolean clearNamedQueue(NamedQueuePayload.NamedQueueEvent namedQueueEvent) {
LOG.debug("Received request to clean up online slowlog buffer..");
namedQueues.get(namedQueueEvent).clear();
return true;
}

Expand All @@ -200,8 +218,10 @@ boolean clearSlowLogs() {
* @return list of slow log payloads
*/
List<SlowLogPayload> getSlowLogPayloads(final AdminProtos.SlowLogResponseRequest request) {
Queue<SlowLogPayload> slowLogQueue =
namedQueues.get(NamedQueuePayload.NamedQueueEvent.SLOW_LOG);
List<SlowLogPayload> slowLogPayloadList =
Arrays.stream(queueForRingBuffer.toArray(new SlowLogPayload[0]))
Arrays.stream(slowLogQueue.toArray(new SlowLogPayload[0]))
.filter(e -> e.getType() == SlowLogPayload.Type.ALL
|| e.getType() == SlowLogPayload.Type.SLOW_LOG)
.collect(Collectors.toList());
Expand All @@ -219,8 +239,10 @@ List<SlowLogPayload> getSlowLogPayloads(final AdminProtos.SlowLogResponseRequest
* @return list of large log payloads
*/
List<SlowLogPayload> getLargeLogPayloads(final AdminProtos.SlowLogResponseRequest request) {
Queue<SlowLogPayload> largeLogQueue =
namedQueues.get(NamedQueuePayload.NamedQueueEvent.SLOW_LOG);
List<SlowLogPayload> slowLogPayloadList =
Arrays.stream(queueForRingBuffer.toArray(new SlowLogPayload[0]))
Arrays.stream(largeLogQueue.toArray(new SlowLogPayload[0]))
.filter(e -> e.getType() == SlowLogPayload.Type.ALL
|| e.getType() == SlowLogPayload.Type.LARGE_LOG)
.collect(Collectors.toList());
Expand All @@ -232,34 +254,12 @@ List<SlowLogPayload> getLargeLogPayloads(final AdminProtos.SlowLogResponseReques
}

/**
* Poll from queueForSysTable and insert 100 records in hbase:slowlog table in single batch
* Add all slowLog events to system table. This is only for slowLog event's persistence on
* system table.
*/
void addAllLogsToSysTable() {
if (queueForSysTable == null) {
// hbase.regionserver.slowlog.systable.enabled is turned off. Exiting.
return;
}
if (LOCK.isLocked()) {
return;
}
LOCK.lock();
try {
List<SlowLogPayload> slowLogPayloads = new ArrayList<>();
int i = 0;
while (!queueForSysTable.isEmpty()) {
slowLogPayloads.add(queueForSysTable.poll());
i++;
if (i == SYSTABLE_PUT_BATCH_SIZE) {
SlowLogTableAccessor.addSlowLogRecords(slowLogPayloads, this.configuration);
slowLogPayloads.clear();
i = 0;
}
}
if (slowLogPayloads.size() > 0) {
SlowLogTableAccessor.addSlowLogRecords(slowLogPayloads, this.configuration);
}
} finally {
LOCK.unlock();
void addAllSlowLogsToSysTable() {
if (slowLogPersistentService != null) {
slowLogPersistentService.addAllLogsToSysTable();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* limitations under the License.
*/

package org.apache.hadoop.hbase.regionserver.slowlog;
package org.apache.hadoop.hbase.namequeues;

import java.util.ArrayList;
import java.util.List;
Expand Down
Loading