Here are all posts of this serie on Glassfish.
This last post will be about considerations on usage of IIOP and Glassfish. IIOP is a standard, inter-operable protocol that every J2EE-compliant application server must support. In case of java-to-java communication, IIOP is sometimes a bit overhead and some application server supports alternative protocols in this special case. However, Glassfish does support only IIOP so all remote communication with go through this protocol. Compared to plain RMI, this protocol adds transaction context preparation.
Communication timeout, distributed transactions & tuning
Heavy usage of IIOP is hard to tune. There seem also that there are some bugs in Glassfish with IIOP. We also noticed that the memory consumption was significant when remote calls are frequent. We needed to adapt the TCP ORB settings in a way to avoid communication time out. The best-practice that we’ve identified can be summarized with:
- Use
-server
profile for better memory management - Tune
-Dcom.sun.corba.ee.transport.ORBTCPTimeouts=500:30000:30:999999
- Check « Allow Non Component Caller » in the data sources
- Beware RedHat Linux, there seems to be some issue with it.
There are also a few other annoyances:
- If local glassfish is running, it will always be taken as default even if JNDI specifies a remote instance
ProgrammaticLogin
doesn’t work from Tomcat to Glassfish
http://forums.java.net/jive/thread.jspa?threadID=42017
http://forums.java.net/jive/message.jspa?messageID=352907
Lookup, load balancing, fail over and host names
EJB lookup with the InitialContext
support load-balancing and fail-over. Nodes can be added/removed to the cluster dynamically; you only need to specify a subset of endpoints in jndi.properties
file. The lookup mechanism works conceptually like this: (1) one of the “bootstrapping” endpoint specified in jndi.properties
is accessed (2) The endpoint knows about the other nodes in the cluster and one of the node is assigned to the particular InitialContext
instance.
At a point in time, the server will answer back to the client providing the address of the endpoint to use for further communication. This address will depend on the configuration of the server. If the ORB was configured to listen on 0.0.0.0 the address is the hostname as resolved on the server-side. The client must be able to contact the server based on the returned address. Depending on the network configuration this may be problematic. For instance, the hostname resolution on server-side may return a hostname that is not visible to the client if they are on different subnets.
The address resolution exist even if no cluster is used and the endpoint specified in jndi.properties
is the one to use for remote communication.
http://docs.sun.com/app/docs/doc/820-4341/fxxqs?a=view
https://glassfish.dev.java.net/issues/show_bug.cgi?id=4051
@Resource for injection
As per the EJB spec, the EJB should be injected with @EJB or looked up in JNDI. Remote EJB are bound in the global JNDI and by consequence can also be injected with @Resource. This is however a bad practice and I suspect some stability issue with it. Beware this little mistake and make sure you always inject them with @EJB.
Local vs. remote calls
We’ve conducted some micro-benchmark to measure the difference between local and remote calls. We have tested the following scenario:
- POJO
- Local EJB
- Remote EJB in same EAR
- Remote EJB in separate EAR
Server-side loop
We call one EJB that performs a loop with 10’000 call to a helper object.
Pojo:0 ms |
Local:63 ms |
Remote internal:172 ms |
Remote external:1735 ms |
Client-side loop
We call 10’000x the EJB from on client, and the EJB performs one call to a helper object.
Pojo:8140 ms |
Local:6688 ms |
Remote internal:6750 ms |
Remote external:9062 ms |
We conclude that the time taken to perform the call on the server side is neglectable compared to the cost of the client-server remote call.
Mixed loop
We call one 10’000 the EJB from the client, and the EJB performs 100 calls to a helper object.
expected | |
Pojo:8640 ms | 8140 + 0 = 8140 |
Local:14031 ms | 6688 + 100×63 = 12988 |
Remote internal:23219 ms | 6750 + 100×172 = 23950 |
Remote external:170641 ms | 9062 + 100×1735 = 182562 |
On the right column is the expected time that can be estimated based on the previous results.
The cost of remote intra-JVM calls (in same EAR or different EAR, but in same JVM), is then relatively neglectable.