[
https://issues.apache.org/jira/browse/HBASE-14331?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14989030#comment-14989030
]
Hiroshi Ikeda commented on HBASE-14331:
---------------------------------------
I'm now thinking about directly executing tasks when the Leader/Followers
pattern is applied to RpcServer (HBASE-14479).
By removing threads in RpcExecutor with increasing the reader threads in
RpcServer, we expect the non-trivial overhead of park/unpark will be reduced.
Also bypassing the call-queues in a low load will remove the overhead of the
call-queues themselves.
In this case, the call-queue would be required to have methods offer and poll,
instead of put and take, which might be not compatible with the way I have done
in this issue.
Pseudo code I'm thinking:
{code}
final AtomicLong stateRef = new ...
void dispatch (task) {
boolean taskQueued = false;
while (true) {
long state = stateRef.get();
int taskThreads = toTaskThreads(state);
int queuedTasks = toQueuedTasks(state);
if (! taskQueued && (taskThreads > 20 || queuedTasks > 0)) {
callQueue.offer(task);
taskQueued = true;
}
boolean join = taskThreads <= 20 ||
(taskQueued ? queuedTasks + 1 : queuedTasks) > 1000;
if (join) {
if (stateRef.compareAndSet(toState(taskThreads + 1,
queuedTasks)) {
break;
}
} else {
assert taskQueued;
if (stateRef.compareAndSet(toState(taskThreads,
queuedTasks + 1)) {
return;
}
}
}
execute(taskQueued ? callQueue.poll() : task);
while (true) {
long state = stateRef.get();
int taskThreads = toTaskThreads(state);
int queuedTasks = toQueuedTasks(state);
if (queuedTasks > 1000 || queuedTasks > 0 && taskThreads <= 20)
{
if (stateRef.compareAndSet(toState(taskThreads,
queuedTasks - 1))) {
execute(callQueue.poll());
}
} else {
if (stateRef.compareAndSet(toState(taskThreads - 1,
queuedTasks))) {
return;
}
}
}
}
{code}
> a single callQueue related improvements
> ---------------------------------------
>
> Key: HBASE-14331
> URL: https://issues.apache.org/jira/browse/HBASE-14331
> Project: HBase
> Issue Type: Improvement
> Components: IPC/RPC, Performance
> Reporter: Hiroshi Ikeda
> Assignee: Hiroshi Ikeda
> Priority: Minor
> Attachments: BlockingQueuesPerformanceTestApp-output.pdf,
> BlockingQueuesPerformanceTestApp-output.txt,
> BlockingQueuesPerformanceTestApp.java, CallQueuePerformanceTestApp.java,
> HBASE-14331-V2.patch, HBASE-14331-V3.patch, HBASE-14331-V4.patch,
> HBASE-14331-V5.patch, HBASE-14331-V6.patch, HBASE-14331-V6.patch,
> HBASE-14331.patch, HBASE-14331.patch, SemaphoreBasedBlockingQueue.java,
> SemaphoreBasedLinkedBlockingQueue.java,
> SemaphoreBasedPriorityBlockingQueue.java
>
>
> {{LinkedBlockingQueue}} well separates locks between the {{take}} method and
> the {{put}} method, but not between takers, and not between putters. These
> methods are implemented to take locks at the almost beginning of their logic.
> HBASE-11355 introduces multiple call-queues to reduce such possible
> congestion, but I doubt that it is required to stick to {{BlockingQueue}}.
> There are the other shortcomings of using {{BlockingQueue}}. When using
> multiple queues, since {{BlockingQueue}} blocks threads it is required to
> prepare enough threads for each queue. It is possible that there is a queue
> starving for threads while there is another queue where threads are idle.
> Even if you can tune parameters to avoid such situations, the tuning is not
> so trivial.
> I suggest using a single {{ConcurrentLinkedQueue}} with {{Semaphore}}.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)