Adam Bien's Weblog

Sunday Feb 10, 2008

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 :-).

 


[my tweets]  Rss My book: Real World Java EE - Rethinking Best Practices

Kommentare:

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 #

Senden Sie einen Kommentar:
  • HTML Syntax: Ausgeschaltet
Interviews/About
My Recent Book
Java One 2009
CommunityOne East N.Y.C
JavaONE 2008 Interview
Search
...the last 150 posts
...the last 10 comments
greenfire.dev.java.net
Links
my.netbeans.org
Visitors
License