Hi guys, I'm a bit concerned with the scalability of a proposed design for our servlet-based multi-service handler system.
Here's a brief description:
1. A single controller servlet get's an Xml message.
2. The message contains info, incuding the sub-application it belongs to. The controller uses a Dispatcher object to locate a handler object for that sub-application, and passes along the message to it.
3. The app-handler gets info from the message describing a specific action that need be executed, and the required parameters. It maintains a pool of action handlers, so it locates the proper one and passes along the data.
4. The action handler executes and returns a response message.
5. The response is propagated back to the original servlet and is sent back to the caller.
Although that "architecture" enables us to dynamically add sub-applicatins & actions to the system, I'm afraid that it might not scale well. Everything is executed within the original servlet's thread, and the application handler is usually a single instance saved in the Application attributes.
1. A first proposed amend is to use JNDI to get a reference to the sub-application handlers through a Factory object that maintains a pool of application handler instances. I'm assuming that the Factory will be run in a separate VM on the same machine, or even another one. (Perhaps it could even be a SessionBean on an App. Server ? ). Still however, the response need be passed back to the original servlet instance that serviced the call.
I'd like to be able to pass the output stream to the handler and just forget about it from the servlet, just like I'd do if i were using a plain socket server, but I doubt I could give it an OutputStream parameter through the two separate VM's ( or could I ? )
2. Perhaps maintain a pool of sub-application handlers within the servlet, in a member variable that get's initialised in the servlet's init() method, and get the reference through JNDI, but wouldn't that place a heavy bourdon on my little Tomcat servler ? And again, the original servlet that serviced the call would have to give the response back to the caller ...
Before we start trying out the possible alternatives, I thought I'd ask around for some opinions. It's no use spending the time to proof-test a solution that costs valuable time before asking a second opinion.
Anyhow, thanks for the help people, any ideas would be much appreciated.
Infact I am just architecting one J2EE system moreor less on similar idea but uses other design pattersn along.
1. Ok so your servlet is the FACADE, it would be a good idea to create pool of servlet, say "25. This should not hamper your application performance as different thereads are available to service client request.
2. You wish to execute everything in a single transaction or the current servlet thread, so the processing is synchronous.Synchronous processing often demands that load be balanced in terms of memory, threads and DB connections.I think if you scale to a high load a cluster environment of Tomcat is needed.
3. Its a good design practice to break the J2EE service layesr into Communication, controller, Handler, Coarse grain service,fine grain service, Data accessors and configuration loaders.As you say the indirection of calls flowing ni your application may sound little wierd, but it helps you design a maintainable system.
4. JNDI lookup is good, but JNDI looup for service/Handlers may be ovrkill as lookup is expensive. due to this many EJB applications go for EJBHomefactory where lookup is on demand/lazy loading and later cached in some cache resource.I suggest you take a look at Avalon Excaliber component management framework, it maintains single instance of handlers in the JVM, which can be stored in the handler factory.
hmmm I think this should be ok for the architecture you have in mind.
- Never use XML for transport layer its a overkill.
- Use connection/object factories.
- read configuration files at application startup.
- Divide the J2EE layers in sub layers e.g comms, domain, persistence etc
- Use DTOs or value objects
- Use service locators
etc....as need be.
As you mentioned, everything executes within the original servlet's thread, and being in the same VM, you cannot really scale horizontally. You could probably beef-up the servers your application is hosted on, but cannot add/remove nodes (or cannot even really cluster currently).
1. I think you sound rather confused about where you want to keep the sub-application handlers. If you use JNDI lookups to obtain sub-application handlers, then those would should ideally be on a different tier (why use lookups otherwise?).
2. JNDI lookups with the Factory on an AppServer is good. Create a shared pool of them on application startup, which will be shared by all Servlets. It wouldn't be such a big hit on startup as you think.
3. I understand when you want to transfer/pass the OutputStream of the servlet to the sub-application handler so you don't have to worry about the ouput. Alas, streams are not serializable. Which is why typical N-tier applications are forced to make remote calls :-). However, I'm not a big fan of making remote calls from Servlets anyway. If you are using Struts, use your Struts actions to make the calls. So in the Servlet, all you do is response read/write or simple transformations.
A lot of people have toyed with asynchronous systems wherein the web-tier sends an asynchronous message to the underlaying layer (possibly in a different thread) and keep polling for them to write the response in the queue, and then "push" it out to the client. Not something I'd recommend though.
And as someone else mentioned, you would have a number of other choices to make. Best practices would come to your rescue there