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

 


NEW workshop: Microservices with Java EE 7 and Java 8, January 26th, 2015, Airport Munich

A book about rethinking Java EE Patterns

Comments:

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

Posted by daniel on February 10, 2008 at 07: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.

Posted by Erkki Lindpere on February 11, 2008 at 12:09 AM 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.

Posted by Antonio Goncalves on February 11, 2008 at 11: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...

Posted by Adam Bien on February 11, 2008 at 11: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!

Posted by Adam Bien on February 11, 2008 at 11: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... :-).

Posted by Adam Bien on February 11, 2008 at 11: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

Posted by daniel on February 12, 2008 at 02: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

Posted by Adam Bien on February 13, 2008 at 11: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

Posted by Techieexchange on February 13, 2008 at 06: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/

Posted by Michael Bien on February 13, 2008 at 09: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

Posted by Markus Kohler on March 12, 2008 at 09:47 PM CET #

The post is very interesting. Thanks a lot :)
Nevertheless, I think that using only one or two ejb calls is not a sufficient basis. Many teams who use ejb tend to generalize their usage in almost every services (facade or not). We have soon 4 or 5 ejb calls by user request.
If a single call cost 3.3%.
4 calls cost 13.2%. So, application may suffer a slowness of 13.2% compared to pojo version, which is not unimportant.

After, 13.2% is not so huge. So, we still can resize the environment to counter this slowness.

It will be interesting to have the same kind of experience for Spring.
If you allow me, I could use your projects to keep the same measure unity.

Posted by 78.192.206.141 on February 27, 2011 at 01:29 AM CET #

Hi Adam,

Thank you for that post. 2011 now, and it is still a current issues. During the last year and since ejb 3, we have seen more and more apps using a lot of ejb 3.x beans even for small things, they use it like spring beans.

So i also would ask the same question as markus kohler above.

What about the system resource consumtion ?

Your example uses a bean and a second bean or pojo. this could be simplified by avoiding the first bean.

Session Beans are pooled so your solution pools it in each example.
if a pool is established the overhead should be minimal. And here with your example you should always have pool hits for both examples ? and therefore the overhead is still (IMHO) quite a lot.

if the ejb pool is effected the overhead should then be more (how much?) because other resouces (e.g. for JMX) are created -> in additon.

thanks.

Posted by Christian Schäfer on March 10, 2011 at 04:48 PM CET #

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