Jay Kreps created KAFKA-747:
-------------------------------

             Summary: RequestChannel re-design
                 Key: KAFKA-747
                 URL: https://issues.apache.org/jira/browse/KAFKA-747
             Project: Kafka
          Issue Type: New Feature
            Reporter: Jay Kreps
             Fix For: 0.8.1


We have had some discussion around how to handle queuing requests. There are 
two competing concerns:
1. We need to maintain request order on a per-socket basis.
2. We want to be able to balance load flexibly over a pool of threads so that 
if one thread blocks on I/O request processing continues.

Two Approaches We Have Considered

1. Have a global queue of unprocessed requests. All I/O threads read requests 
off this global queue and process them. To avoid re-ordering have the network 
layer only read one request at a time.
2. Have a queue per I/O thread and have the network threads statically map 
sockets to I/O thread request queues.

Problems With These Approaches

In the first case you are not able to get any per-producer parallelism. That is 
you can't read the next request while the current one is being handled. This 
seems like it would not be a big deal, but preliminary benchmarks show that it 
might be. 

In the second case there are two problems. The first is that when an I/O thread 
gets blocked all request processing for sockets attached to that I/O thread 
will grind to a halt. If you have 10,000 connections, and  10 I/O threads, then 
each blockage will stop 1,000 producers. If there is one topic that has long 
synchronous flush times enabled (or is experiencing fsync locking) this will 
cause big latency blips for all producers using that I/O thread. The next 
problem is around backpressure and memory management. Say we use BlockingQueues 
to feed the I/O threads. And say that one I/O thread stalls. It's request queue 
will fill up and it will then block ALL network threads, since they will block 
on inserting into that queue, even though the other I/O threads are unused and 
have empty queues.

A Proposed Better Solution

The problem with the first solution is that we are not pipelining requests. The 
problem with the second approach is that we are too constrained in moving work 
from one I/O thread to another.

Instead we should have a single request queue-like structure, but internally 
enforce the condition that requests are not re-ordered.

Here are the details. We retain RequestChannel but refactor its internals. 
Internally we replace the blocking queue with a linked list. We also keep an 
in-flight-keys array with one entry per I/O thread. When removing a work item 
from the list we can't just take the first thing. Instead we need to walk the 
list and look for something with a request key not in the in-flight-keys array. 
When a response is sent, we remove that key from the in-flight array.

This guarantees that requests for a socket with key K are ordered, but that 
processing for K can only block requests made by K.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira

Reply via email to