Monday, August 23, 2010

Improving a Transactional Server Architecture


In my professional experience, so far I’ve made two medium to big-sized Server applications. The first one was for an online payment server, written in Java; the second was for an MMORPG online game, written in C++. Right now, I’ve been assigned to design and implement a server similar to my first Server application, which is also in Java. This time, I took a lot of time researching in order to make better software than before.

My first server architecture was a quite plain one. Picture below maybe will give a brief explanation.



A thread listens for connection, and put the socket of a connection into a queue. Then one of the may worker thread which are already waiting for an element of a queue take it, process it, and send the reply directly using the very socket it took from queue.
This architecture server quite well before, and I don’t see a reason it wouldn’t this time. Still I googled the web to improve it. In my search, I found two of the most significant improvement, that is:
• Use SocketChannel instead of plain java Socket
• Ensuring 1 thread/client will give better throughput
But then, I found an interesting word from somewhere here, that discourage using a queue, because it enforcing one more context switching, where it should be minimize.
It tickles my brain for a while, until someday I had a 'click'. The idea is to take remove the connection listener thread and of the queue. But how does the port listening being done if no thread to do it? The answer is, the worker do it.
Yes, all the worker thread should listen to the specified port. In detail, inside the worker code, exist something like:

While(!Stop){
Socket tSocket = mBindedSocket.accept();
…….. // the work goes here
}

First I thought it was weird, but then I try to implement this concept. Quite amazed by it, that concept is actually works! Now the architecture looks like this:


As a result, it’s a much simpler architecture, and logically faster because of the excluding of queue filling and taking, thus reducing the number of context switching occurred.
I had run some test, and the result pretty much expected. The new architecture require less time than the original architecture.
Test number original new
1 26 sec 24 sec
2 25 sec 23 sec
3 25 sec 23 sec
4 25 sec 23 sec
5 26 sec 23 sec

The test scenario was a simple one, the server returned ‘hello world’ every time a client connects to it, without read the message from client.
Maybe this finding isn’t impressive at all, but at least this was useful for me, as it feels good because I could improve what I made years ago, so that I know my skill is improving even if just a little, :)

No comments:

Post a Comment