On 9/27/06, Doug Cutting <[EMAIL PROTECTED]> wrote:
Feng Jiang wrote: > As for the IPC (it used to be RPC about one year ago) implementation, I > think it has some performance problem. I don't know why the Listener has to > read the data and prepare the Call instance then put the Call instance into > a queue. The reading process may be a long time, and other Calls are > blocked. I think that is the reason why you have to catch the > OutOfMemoryError. I don't completely understand your concern. The queue is used to limit the number of requests that will be processed simultaneously by worker threads. A single thread reads requests off the socket and queues them for worker threads to process and write results. Unless we break requests and responses into chunks and re-assemble them, the reading and writing of individual requests and responses must block other requests and responses on that connection. Previously there was server thread per connection, reading requests. (Responses are written directly by worker threads.) Recently this has been re-written so that a single thread uses nio selectors to read requests from all connections. Calls are still queued for worker threads to process and reply. > I used to implemented another RPC Server and Client based on your code, by > simply using java's ThreadPool, the performance is about 10-20% higher than > that implementation one years ago. The main algorithm is: > 1. Server has a threadpool, initially it is small and grows as need. > 2. Listen accept a connection, then put the connection into threadpool. > 3. The threads in the pool handle everything for the connections. This does not permit a slow request from a given client to be passed by a fast request from that client, i.e., out-of-order responses. The IPC protocol was originally designed for search, where some queries take significantly longer than others. All front-ends send each query to all backends. In this case we do not want queries which are fast to process to be stuck behind those which are slow to process. Permitting out-of-order responses does increase the base latency a bit, since a thread switch is required between reading the request and writing the response. Perhaps that accounts for the 10-20% difference you saw. It is possible to combine the approaches. Worker threads could use synchronization to directly listen on the socket and process requests as soon as they are complete. That would avoid the thread switch, but I think it would be complicated to develop.
I understand the importance of out-of-order RPC call. Actually the "id" attribute in "Call" class is used to identity the Call object in client side, since the Client object may send a lot of request, and it needs the "id" to know which Call has been completed. In my implementation, I still permit the out-of-order RPC call by the same way. the only difference between my impl and your previous impl is: 1. I made use of threadpool(JDK1.5) to replace the "Handler" threads. I believe the JDK's impl should not be worse than ourselves, and threadpool could be grows or shrinks dynamically, even more, I can control the pool size, core size, etc. 2. Since I just put the connection into the threadpool directly, I removed the queue, and that is why i believe my impl should save more memory than your previous impl. Because you have only 100 threads, if the 101th client sends a request to you, you have to put the connection into the queue, so the queue may become bigger and bigger. In my impl, if the 101th client comes, the listener will be blocked until the threadpool is available (if i limit the threadpool's max size. If not, the listener will never be blocked, the each request always has chance to be executed).
by this way, it saves memory usage and threadpool's schedule should be > better than our own. We are using a thread pool for worker threads. The difference is that worker threads call wait() to wait for a request, and the listener thread call notify() to tell the worker thread that a request is ready, and the scheduler must switch from running the listener to the worker. Doug