Adam Bien's Weblog
Is it worth to use POJOs instead of EJB 3 in terms of performance? (with results, source and load scripts)
I hear from time to time funny statements like "EJB 3 are too heavyweight", or "POJOs are lightweight". If I have the chance I ask directly how the term "lightweight" is defined - and get really funny (mostly inconsistent) answers. This remembers me somehow the answers I get for questions like: "What you actually meant by serviceorientation?" or even better "What do you mean by Web 2.0?".
Lastly I was asked "...It would be interesting to see if the same web app would be faster if you only developed a web-project using JSF, Derby and TomCat as Webserver..." (instead of Glassfish with EJB 3, JSF and Derby). This request made me really curious - and I built two independent projects. An EAR "EJBLoadTest" which consists of an Servlet and to cascaded EJB 3.
public class NumberGenerator extends HttpServlet {
@EJB
private NumberGeneratorFacadeLocal numberGeneratorFacadeBean;
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println(numberGeneratorFacadeBean.getNumber());
} finally {
out.close();
}
}
}
With two local Session Beans. The first one fetches the millis, calls the second one and computes the result. The business logic is dumb, but it avoids GC optimizations.
@Local
public interface NumberGeneratorFacadeLocal {
public long getNumber();
}
@Stateless
public class NumberGeneratorFacadeBean implements NumberGeneratorFacadeLocal {
@EJB
private MillisProviderLocal millisProviderBean;
public long getNumber(){
return System.nanoTime() - millisProviderBean.getMillis();
}
}
The second bean is simple as well.
package com.abien.loadtest.ejb;
import javax.ejb.Stateless;
@Local
public interface MillisProviderLocal {
public long getMillis();
}
@Stateless
public class MillisProviderBean implements MillisProviderLocal {
public long getMillis(){
return System.currentTimeMillis();
}
}
I introduced the two beans, to maximize the overhead between the "POJOs" and EJB3. In simple applications there would be only one layer - and so less overhead.
The POJO application is identical. Instead of EJBs I used POJOs, and instead of an EAR, a WAR.
The POJO servlet comes with an additional "init" method. Because dependency injection doesn't work for POJOs (=classes without the @EJB annotation), the POJO creation was factored out in a init method:
public class NumberGenerator extends HttpServlet {
private NumberGeneratorFacadeLocal facade;
public void init(){
this.facade = new NumberGeneratorFacadeBean();
}
The same story in the facade - the DI was replaced with an constructor call:
public class NumberGeneratorFacadeBean implements NumberGeneratorFacadeLocal {
private MillisProviderLocal millisProviderBean;
public NumberGeneratorFacadeBean(){
this.millisProviderBean = new MillisProviderBean();
}
public long getNumber(){
return System.nanoTime() - millisProviderBean.getMillis();
}
}
For the load tests I used JMeter. I repeated the tests several times. The load generator and the Glassfish v2 were on the same machine. This differs a little bit from real world - but is perfectly suitable to show the EJB 3 overhead.
The results:
- EJB3: The throughput of the EJB 3 solution was 2391 transactions/second. The slowest method call took 7 milliseconds. The everage wasn't measurable. Please keep in mind that in every request two session beans were involved - so the overhead is doubled.
- POJO: The throughput of the POJO solution was 2562 requests/second (request - there are no transactions here). The slowest method call took 10 ms.
The difference is 171 requests / seconds, or 6.6% (therefore 3.3% for a single session bean).
Conclusion:
The dfference is less than expected (I expected an overhead over 10%)... However the POJO sample only works for idempotent / transient use cases. It wouldn't work for highly concurrent, database applications - I only created one instance for servlet - not request.... In that case, you will have to synchronize the access to the shared state e.g. with transactions or "instances per request". In that case a plain web container wouldn't be the simplest solution.
However the EJB 3 solution would work even with database and JMS without modification... The funny story here - the POJO solution required some more lines of code. :-).
I checked the projects (POJOLoadTest, EJB3LoadTest), the load script, as well as the results (as screenshots) into http://p4j5.dev.java.net. I used plain Netbeans 6.0 for this purpose - feel free to reexecute the load test again - and share the results :-).
Posted at 11:40AM Feb 10, 2008 by Adam Bien in Netbeans | Kommentare[11]
[my tweets]
Rss My book: Real World Java EE - Rethinking Best Practices


very nice work, adam. Thanks a lot. I didnt expect this result. I'd thought the difference would be a good deal bigger...
For business management reasons, whats the difference in money between running a glassfish-app-server and a tomcat?
Greetings from Stuttgart
Gesendet von daniel am February 10, 2008 at 06:10 PM CET #
In my experience there is also very little performance difference, but the POJO (or POJO + Spring) approach is lightweight also because it doesn't have such a heavy conceptual load / mindfuck. The EJB 3.0 spec might have improved things, but it's still too heavy on concepts that don't really help the vast majority of applications where EJB-s have been used.
Of course, Spring has lots of extra concepts as well, most applications probably don't need all of them. But Spring makes it a lot easier to just use the parts that you need and ignore the rest.
Gesendet von Erkki Lindpere am February 10, 2008 at 11:09 PM CET #
I also thought that the difference would be bigger. And a good point for EJBs here ;o)
It would be interesting to measure this example with a database plugged in. The POJOs could use JTA to commit the transaction and the EJBs use the default REQUIRED tx mode. POJOs will get a worse performance but by how much.
Gesendet von Antonio Goncalves am February 11, 2008 at 10:11 AM CET #
Hi Daniel,
Glassfish is as free as Tomcat. However commercial support is available as well - which is even more important in real world (don't underestimate politics and management issues - technology is not everything). Even better having an EAR you can actually decide between Glassfish and JBoss...
Gesendet von Adam Bien am February 11, 2008 at 10:06 PM CET #
Erkki,
I like the term "mindfuck". It would be a great name for an opensource project :-). However what you mean by that? Perhaps we can prune something in EJB 3.1 :-). If you would like to be really "lightweight", consider to user Google's Guice. The whole documentation fits to 22 pages, and the whole framework is smaller than 1 MB... However in my example even got rid of spring and just used POJO's. Less isn't possible :-)
Thanks for your comment!
Gesendet von Adam Bien am February 11, 2008 at 10:09 PM CET #
Antonio,
having a database would be unfair. We had to manage the concurrency and especially the association between the threads, transactions and e.g. the Entity Manager or / and the Connection/DataSource.
The performance of EJBs should be better - even more important - there are no issues in concurrent applications...
So actually EJB 3 are more lightweight, than one would expect... In my Java EE projects we consider to use an EJB 3 first - having a POJO is rather an exception... :-).
Gesendet von Adam Bien am February 11, 2008 at 10:13 PM CET #
Hi Adam,
Glassfish is as free as Tomcat, i know. However you have to pay for a root server to install glassfish and thats more expensive than a web-server.
I know, enterprises dont care about that, but if you like to run such an app for private purposes...
i dont like my mac to run 24 hours a day ;)
Greetings
Daniel
Gesendet von daniel am February 12, 2008 at 01:47 PM CET #
Daniel,
I really don't see any difference between both. To run the Java EE application a simple webserver isn't sufficient. You will need a webcontainer. Then the difference is really very small...
regards,
adam
Gesendet von Adam Bien am February 13, 2008 at 10:06 AM CET #
Adam Bien:
>I checked the projects (POJOLoadTest, EJB3LoadTest), the load script, as well as the results (as screenshots) into http://p4j5.dev.java.net
Could be please direct me here. I cannot find anything there.
Thanks
Gesendet von Techieexchange am February 13, 2008 at 05:20 PM CET #
both projects:
https://p4j5.dev.java.net/source/browse/p4j5/trunk/PojoLoadTest/
https://p4j5.dev.java.net/source/browse/p4j5/trunk/EJB3LoadTest/
and here are general svn checkout instructions:
https://p4j5.dev.java.net/source/browse/p4j5/
Gesendet von Michael Bien am February 13, 2008 at 08:17 PM CET #
Hi Adam,
What about memory consumption ?
Scalability of applications can be limited by the amount of available memory.
I offer you a free memory consumption analysis If you could provide me with 2 heap dumps taken during the test :)
Here is a description of how to get heap dumps : https://wiki.sdn.sap.com/wiki/x/sII
Regards,
Markus
Gesendet von Markus Kohler am March 12, 2008 at 08:47 PM CET #