-
Notifications
You must be signed in to change notification settings - Fork 3.4k
HBASE-24718 : Generic NamedQueue framework for multiple use-cases (Refactor SlowLog responses) #2052
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HBASE-24718 : Generic NamedQueue framework for multiple use-cases (Refactor SlowLog responses) #2052
Changes from 1 commit
ddb784c
f5da0a2
560e9cd
41563f8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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; | ||
|
|
@@ -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 | ||
| * 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<>(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
|
|
||
| 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(); | ||
|
|
@@ -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); | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -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; | ||
| } | ||
|
|
||
|
|
@@ -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()); | ||
|
|
@@ -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()); | ||
|
|
@@ -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(); | ||
| } | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.