Do We Need Stateless Session Bean Pooling?

Pooling is still mentioned in the EJB 3.1 / Java EE 6 specification. The question is: do you have to care? The answers are:

  1. Pooling is not a requirement, it is just an assumption: "...Since stateless session bean instances are typically pooled, the time of the client’s invocation of the create method need not have any direct relationship to the container’s invocation of the PostConstruct/ejbCreate method on the stateless session bean instance..."[EJB 3.1 spec, page 78]
  2. EJB container can either pool the instances or create a new one for each request
  3. The most important thing is, that every transaction (often request), gets an independent instance. Then you don't have to care about low level locking mechanisms. This can be achieved with or without (=creating a new instance for each request) pooling.
  4. Pooling is no more needed in modern JVMs for performance reasons in general. This, however, is highly dependent on the JVM and garbage collector configuration.
  5. With pools you can throttle the concurrency, because most (all I know) application servers allow you the configuration of max number of instances. You can control the concurrency of every bean type (Boundary) in a fine grained way. This is important for the avoidance of DoS attacks and dealing with legacy resources.

So pooling is not needed for performance or scalability reasons, rather than for the ease of use. You can easily restrict the scalability and you get a single threaded programming model for free. In day to day development you don't have to thing about pooling or instance management.

The only thing to remember is: every transaction runs in a dedicated Session Bean instance and thread.

[See Page 20 (EJB: Introducing Consistency) in Real World Java EE Patterns - Rethinking Best Practices book]

Comments:

I've wondered that myself. I think next spec revision we should add an annotation to @Singleton that gives developers the ability to limit the number of threads that can execute concurrently against the singleton. Maybe something like @MaxConcurrency(10). This would be functionally the same as an single-threaded instance pool of 10. At which point you pretty much don't need @Stateless anymore unless you're dealing with a single-threaded resource that is expensive to load and don't want the work of managing a pool of it in your singleton.

Posted by David Blevins on January 15, 2010 at 04:33 PM CET #

I wouldn't ditch SLSB just yet. :)

In my view, the similarities between @Singleton and @Stateless end the second you introduce internal state into the bean instance. With singleton the burden is now placed on the developer to properly sprinkle read/write locks. At this point you've introduced two issues:

1) The potential to do it wrong
2) Blocking points / bottlenecks

For this reason I default to recommending SLSB, considering @Singleton where the criteria is:

* Very high-read/low write ratio
* Shared application-wide state (or no state)

Though I really like the @MaxConcurrency suggestion, which tackles the problem of resource starvation (queuing up pending requests so resources aren't spread too thin).

S,
ALR

Posted by Andrew Lee Rubinger on January 15, 2010 at 06:02 PM CET #

@David,

Andrew is right. Stateless Session Beans are very easy to use for developers - there is no contention at the bean level. Every instance is executed in a dedicated thread. You have only issues, in case you are accessing a shared data concurrently (like singletons). Similar to functional programming.

With a @Singleton you have to care about synchronization by yourself. This can be really hard....

Are you pooling or not in openEJB? It would be a nice performance comparison for pooling vs. "new" instance for every request....

thanks for your comment!

Keep your excellent openEJB work going!,

adam

Posted by Adam Bien on January 15, 2010 at 06:54 PM CET #

Another thing that occurred to me: it may be proven now that in modern JVMs there's no performance gain from pooling vs. creating new instances on the fly, but that doesn't take into account the reflection necessary to do injection of @Resource and other deps.

Just instance creation.

Plus a pool can be configured in line with finer-grained performance requirements.

Overall I advocate the pooling approach because:

1) Greater flexibility
2) At worst, performance is on par with new instance creation
3) At best, better performance
4) It's completely abstracted from the user and doesn't affect his/her view

S,
ALR

Posted by Andrew Lee Rubinger on January 15, 2010 at 08:21 PM CET #

I am not sure I agree with you. I see many systems where statelesses have heavy initialization tasks which are performed during the @PostConstruct. If the concept of pooling is abandoned this code will stop performing well. So it seems to me that "So pooling is not needed for performance or scalability reasons" is questionable.

Posted by Paulo on January 15, 2010 at 08:58 PM CET #

@Adam

Sure, the style differences will always be there and convenience and knowledge will always which someone might choose. I speak only things at the API level that prevent them from functioning equivalently.

You shouldn't need to synchronize yourself with an @Singleton. Any method that modifies instance-level state should be marked @Lock(WRITE). If you do that and stick to it, all will be well. But you're absolutely right that synchronization is hard. Ultimately @Lock annotations do not free you up from having to understand all aspects of synchronization, so definitely, Singleton is not for everyone.

In terms of Stateless pooling, I'm not aware of an implementation that doesn't pool. If we had been thinking about it during this last spec round we should have added an @PoolSize annotation for Stateless like we added an @StatefulTimeout for Stateful beans. An interesting note is that timing out Stateful beans has also never been a requirement despite the fact that every implementation has always done it.

On performance, back in Java 1.2 and prior the VM was not that great at thrashing through small objects. I once wrote an object serialization implementation for OpenEJB that was 30% faster than the built-in VM implementation simply because it reused all the byte buffers involved. In the 1.3 VM this same implementation was 10% slower. Things have only gotten better since then in regards to thrashing through small objects. The VM does a pretty amazing job at it.

So in the end whether or not pooling pays off depends entirely on what you're doing in @PostConstruct and if you need the natural throttling that a pool provides.

While we're on the subject, the concept of requiring developers to set a fixed number of Stateful beans allowed in memory is also somewhat arcane. With modern WeakReference, SoftReference and the like, we really don't need to be asking developers to guess at the magical number anymore. Then VM can now tell you. I've been dying to rewrite the Session management in OpenEJB alone those lines for a while now. Hopefully with the EJB 3.1 work we have to do, I'll get the chance.

Posted by David Blevins on January 15, 2010 at 09:38 PM CET #

@Paulo,

yes - if we take into the account the injection as well - then pooling is very important for performance and scalability. Originally pooling was "sold" as a scalability gain because of the slow "new" operator.
Now pooling is only necessary in case the initialization process itself is too slow...

thanks!,

adam

Posted by Adam Bien on January 15, 2010 at 10:08 PM CET #

@David,

then I agree with you completely:
1. We need a mechanism for throttling. Pooling worked, but is not required for that.
2. Whether the container uses pools or not, it actually doesn't matter. For stateless objects it could automatically recognize @PostConstruct "slowness" and pool them if required.
Actually: it should be enough to pool instances only in case @PostConstruct method was implemented and the DI is fast enough. My guess: Field.set isn't measurable.
3. What really isn't needed is passivation of Stateful session beans - here is enough stuff for another post... :-)

thanks for your explanation!

Posted by Adam Bien on January 15, 2010 at 10:17 PM CET #

Its IMO a little bit unrelated that you require pools to control things like instance count etc. Sure you get it for free if you have a pool but the container could control it without pooling too. A pool is just a fancy factory.

Regarding performance. There are different kinds of performance. There is throughput and determinism (real time behaviour). Pools can improve determinism but they can also decrease throughput if you pool objects with little construction overhead.

The other point to keep in mind is that pooled objects *can* even put more load on the GC (full GC pause times). More (long living) objects in the heap mean more references to follow and more objects in the old generation.

performance optimizations are highly application dependent.

http://michael-bien.com/mbien/entry/object_pooling_determinism_vs_throughput

cu, michael

Posted by michael bien on January 16, 2010 at 01:35 AM CET #

I am beginning with JEE and I was not able to comprehend why application servers create more instances of the same Stateless Session Bean when they are stateless. On the sun web I found: " the bean's instance variables may contain a state, but only for the duration of the invocation". So I understand it in that way that it is not permitted to invoke a method of SLSB instance by a thread when another thread is executing this method. Is this the only reason why SLSBs are pooled or there are another reasons? If I understand this article well are another reason transactions? Thank you.

Posted by Stan Svec on January 28, 2010 at 03:19 PM CET #

Hi Adam,

I have two questions in mind regarding the Singleton Session Bean:
1. What happens to the SessionContext? Remember when Stateless Session Bean get tied to one request (or thread), the setSessionCotext() is called so that it could be used to roll back transaction or figure out the caller identity. So with the Singleton Session Bean, how many SessionContext will be there? The same one for all requests or different one for each individual request (or thread)?
2. What will happen in the Cluster environment? With the @lock(Read/Write) annotation, we could use it to allow multiple threads read/write a shared area let's say a HashMap in the same JVM. But will Singleton Beans in other JVMs in the same cluster see the changes when one instance of Singleton Bean updates its HashMap?

Posted by Bob on January 29, 2010 at 12:49 AM CET #

I do not really agree.
In our system some SLSB have some heavy stuff done in the @PostConstruct.

Without pooling the performances would be horrible.

Posted by lilivier on March 03, 2015 at 03:47 PM CET #

Post a Comment:
  • HTML Syntax: NOT allowed
...the last 150 posts
...the last 10 comments
License