You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@hbase.apache.org by "Hiroshi Ikeda (JIRA)" <ji...@apache.org> on 2015/11/04 07:57:27 UTC

[jira] [Commented] (HBASE-14331) a single callQueue related improvements

    [ 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)