I have the following interesting results on conducting performance tests on data access. I have a database table with around twenty-five rows and three columns residing in a Adaptive SQL Anywhere database. I am trying to retrieve all the data from this table from a Java standalone client, through a datasource configured on WLS 6.1 with the following configurations. WLS, data server and the client reside on the same machine.
(1) An entity EJB with local interface that provides a business method that returns a value object encapsulating the persistent fields. The local home object exposes a findAll method. A remote stateless session bean accesses the local entity bean, creates a collection of the value objects and returns it to the Java client.
Average time over ten iterations: 2.106 Seconds
(2) An entity EJB with local interface that exposes the CMP accessor methods through the local interface. The local home object exposes a findAll method. A remote stateless session bean accesses the local entity bean, creates values objects by accessing the individual CMP methods exposed by the local object and return the collection to the client.
Average time over ten iterations: 2.140 Seconds
(3) An entity EJB with remote interface that provides a business method that returns a value object encapsulating the persistent fields. The remote home object exposes a findAll method. A remote stateless session bean accesses the remote entity bean, creates a collection of the value objects and returns it to the Java client.
Average time over ten iterations: 2.130 Seconds
(4) An entity EJB with remote interface that exposes the CMP accessor methods through the remote interface. The remote home object exposes a findAll method. A remote stateless session bean accesses the remote entity bean, creates values objects by accessing the individual CMP methods exposed by the remote object and return the collection to the client.
Average time over ten iterations: 2.126 Seconds
(5) An entity EJB with remote interface that provides a business method that returns a value object encapsulating the persistent fields. The remote home object exposes a findAll method. The client directly accesses the entity bean component interface.
Average time over ten iterations: 2.214 Seconds
(6) An entity EJB with remote interface that exposes the CMP accessor methods through the remote interface. The remote home object exposes a findAll method. The client directly accesses the individual CMP methods exposed by the remote component interface.
Average time over ten iterations: 2.775 Seconds
(7) A remote session bean acts as a DAO, issues direct JDBC and returns a collection of value objects created from the resultset.
Average time over ten iterations: 2.226 Seconds
The inference I make is performance is not significantly improved by changing remote references to local references. I think the number of load and store calls significantly affects data access performance. WLS provides container specific way of controlling these calls. The interesting aspect I noticed is the use of a DAO for bulk read has not improved performance significantly. However, I feel, performance can be astronomically improved by using rowset implementations in the DAOs instead of using VOs. I couldn't test the CachedRowSet implementation from Sun as the JConnect driver from Sybase doesn't support some of the methods.
Meeraj, I believe Weblogic has an in-house version of RMI implemented that doesn't do serialization/remote calls when two objects in the same server communicate via remote interface. This could be the cause of your odd results.
This is true of JBoss as well, I understand. If you're using one of the embedded web server combinations (such as Tomcat or Jetty embedded into JBoss) access to EJB's from the web application (e.g. servlets, JSP's) is optimized to avoid serialization.
According to my BEA Sales Engineer, the BEA WLS has done non network/RMI local calls when it deems this possible on Remote interfaces since WLS 5.1.
Just another proof of the "one size fits all performance recommendations" falling flat when not considering anything but the base J2EE spec.
You can turn off the default pass-by-reference WLS optimization in the weblogic-ejb jar deployment descriptor to force it to use the standard pass-by-value. I'd be interested to see what happens when you do that (assuming you haven't).
Another thing you might want to consider (besides the other point cited above, which are correct: we pass by reference by default in the same VM):
The architecture you are testing is probably not a good testcase for the validity of local interfaces. In your scenario, basically half of the traffic happens locally and the other half remotely.
If you consider a more realistic scenario involving several tables, a great deal of the finders and joins will happen between EJB's connected by relations, i.e. living in the server. In that case, you will probably see a clear improvement in performances since the remote marshalling (value object -> local interface and back) will only be seen at both ends of the whole process.
In case what I said above is not clear (probability: 80% considering the time), I am basically saying that you are comparing making ten remote RMI calls with making one remote call, then eight local calls and then one more remote.
That still doesn't explain why DAOs using straight JDBC to create VOs are slower than using entity EJBs.
It would be interesting to see the CMP SQL calls and compare it with the SQL calls in the DAO.
Most probably there is no database connection pooling happening during direct JDBC call. What JDBC version are you using?
I am using a pooled connection from WLS and it is the pool used by the EJB container as well.
does anyone have a link to weblogic's optimization of using local interface? i read one before, but don't seem to be able to locate it now. thanks, CC
Although not related to now so famous intra-container optimizations, I think performance of bulk reads/writes with DAOs is highly dependent on the size and complexity of your beans. Also calling findAll may be a stupid thing to do for a large production database mapped to complex EJB entitities.
Just another proof that sometimes design patterns may scale and perform better than the quick and dirty solutions ;)
My VO is a very simple one with three attributes...
It's not only a question of performance; it's also a question of scaleability. So, one more thing which I think is more important to measure is the consumption of resources. For example a local ejb does not need to be exported, skeletons does not need to be generated and so forth. A remote object is always a more heavy-weight object, this also affects the overhead of passing the object as a variable to other local methods.
A more interesting and relevant test could be to do load-testing and see how the two different implementations behave under increased load.
"A remote object is always a more heavy-weight object, this also affects the overhead of passing the object as a variable to other local methods."
Unless I misunderstand what you meant, that is not true. It is just as fast to pass a gigabyte of data or to pass a byte (both are passed as one word).
The only things that are slightly "slower" to pass (theoretically) are "double" and "long" values because they require a two-word push.
There is no need to create skeletons for remote EJB's either. This is an implementation detail. It is entirely possible to only use one remote object for the entire server with all beans, hence making it cheap to add more remote EJB's. JBoss used to do this, but now uses one remote object per container. JBoss 3 will move back to the one remote object concept (IIRC).
Yes, I experienced the same results with the WLS 6.0 (since its beta). Why don't you try Borland AppServer; Borland Application Server's Local interface implementation is significantly faster than the Remote. Also, inter-EJB
communication is much faster too.
If you are clustering and have the db-is-shared setting to false in the weblogic-ejb-jar.xml, and you have transaction Required on the entity bean the ejbLoad method will be called for each of the individual accessors.
Bebop Software LLC
Rob: "If you are clustering and have the db-is-shared setting to false in the weblogic-ejb-jar.xml, and you have transaction Required on the entity bean the ejbLoad method will be called for each of the individual accessors."
Assuming you are calling from a non-transactional context, it does not matter what the transaction attribute will be because the ejb will always have to load its data.
Blocks of work, including read-only work, should be done as transactions in J2EE for optimal performance.
My illustration represents a few "gotchas" within a worst case scenario that "sneaks up" when you turn on clustering, and this is why I favor the value holder vs. calling accessors. The typical developer does not work in clustered mode and may not encounter this scenario while coding. When the code is deployed in a cluster performance is reduced because the accessor calls become very expensive due to excessive ejbLoad calls forced by the Required option.
Many examples show entity beans configured with Required, I prefer Supports so that read only session access can be performed without a transaction. I do not agree that read only access should be performed within a transaction, but if you must then I agree with your statement that a single transaction gives the best performance. This can be achieved by using a single value holder accessor or by using the Supports method on the Entity bean and Required on corresponding the Session bean.
Rob: "Many examples show entity beans configured with Required, I prefer Supports so that read only session access can be performed without a transaction."
I used to also until I realized that each call was creating a "local" transaction on the J2EE side and that the database was doing a transaction as well behind the scenes, so I wasn't saving anything.
Rob: "I do not agree that read only access should be performed within a transaction, but if you must then I agree with your statement that a single transaction gives the best performance."
The purpose for maintaining that transactional scope around all invocations is to allow the container to avoid multiple loads and stores of the same data. Usually applications use a facade pattern on a session bean to accomplish this on the non-read-only portion of the processing, which is good, but then the read-only work (if it uses EJBs) usually has terrible performance. Depending on the nature of the application, a single read-only operation that returns a value object has the same net result - one read-only transaction - but as soon as you have two operations then it is better to encapsulate all in one user tx from the web container.
Oh yeah, Read Only Entity beans can be cached with db-is-shared set to false and Not Supported so ejbLoad is not called as often. If you have read only data this rocks.
Of course the local interface is significantly faster than the remote - by more than factor 1000, but this doesn't matter in your test.
The remote interface is very fast when you transfer not much data like simple objects with 3 fields.
You are measuring the speed of your entity bean (jdbc, database, etc.), which is pretty slow. So the difference between local an remote calls in your test ist negligible.
A remote call takes around x times 10 ms. x depends on data size and data complexity.
x is 1 for simple objects with simple data types.
x can be 100 to 1000 for big objects or complex objects.
A local call takes some microseconds (1/1000th of a ms) independend of size or complexity of objects. It should depend a little bit (but not measurable) on the number of parameters.
When talking about local calls, we should disginguish between 'real' locals call - like normal java. That's what I talked about. And there are optimized remote calls of appservers that use local calls for locally reachable EJBs. The optimized remote calls are in between remote calls and 'real' local calls performance wise, because the parameters and results have to be copied to follow the EJB rules and cannot be passed by reference. That's why the optimized remote calls also depend on size and complexity of the objects but not on network speed, tcpip stack speed and so on like the remote calls.
Your EJB is very slow (for 25 rows and 3 columns). The operations should take some 10-100 ms. Then you could notice more differences between your implementation choices.
Now the db seems to take all the time and you are optimizing on maximum 5% of the total time. If the 5% are not there, you will not notice it.
Generally speaking, the local interface will have similar performance characteristics to remote interfaces with copy-by-value semantics turned off since the container has to deal with a transaction manager and a security infrastructure in both modes. Almost every vendor offered a flag to allow copy-by-reference as an implementation feature, but this was also a violation of the J2EE certification rules. The spec was augmented to allow vendors to provide what they were already providing with arguably clearer semantics for bean developers.
In expert group discussions, most vendors argued that this was the primary, necessary optimization for entity beans (the model was later extended to all bean types). It's hard to say whether this is true for the majority of cases: we experimented with reference apps at Bluestone and had results that varied widely.
At one point a much lighter local model where the transaction and security checks would be omitted was discussed in the expert group. Keep in mind that contention issues that will only manifest themselves during load testing will often be your primary culprit for performance problems.
There was also a proposal to separate persistence itself from the EJB spec and one to formalize the existing optimizations through deployment descriptor settings, neither of which gained much traction.