I was thinking how could i save time on looking up remote ejb reference through jndi. I had an application that needed to work very fast, but it also had to call remote ejb which slowed it down.
So my solution was something like this:
I took apache commons-pool library and used its StackObjectPool implementation for my remote ejb references cache.
private static final ObjectPool pool = new StackObjectPool(new RemoteEjbFactory());
Factory looks something like this:
public static class RemoteEjbFactory extends BasePoolableObjectFactory {
#Override
public Object makeObject() {
try {
return ServiceLocator.lookup(jndi);
} catch (NamingException e) {
throw new ConfigurationException("Could not find remote ejb by given name", e);
}
}
}
Then i take object by borrowing it from pool (if no free object in pool it uses factory to create one):
SomeEjbRemote someEjb = null;
try {
someEjb = (SomeEjbRemoteImpl) pool.borrowObject();
someEjb.invokeRemoteMethod();
} catch (Throwable t) {
if (someEjb != null) {
pool.invalidateObject(someEjb);
}
pool.clear(); // Maybe its not neccessary
someEjb = (SomeEjbRemoteImpl) pool.borrowObject();
someEjb.invokeRemoteMethod(); // this time it should work
}
And of course returning ejb back to pool after successful invokacion
finally {
try {
pool.returnObject(someEjb);
} catch (Exception e) {
logger.error("Could not return object to pool.", e);
}
}
As i understand there is no guarantee that remote reference will stay connected so if we catch exception using cached remote ejb, we just invalidate that object and retry.
What do you think about such approach? Is it correct? Maybe some other solutions, advices?
From the spec
3.4.9 Concurrent Access to Session Bean References
It is permissable to
acquire a session bean reference and
attempt to invoke the same reference
object concurrently from multiple
threads. However, the resulting client
behavior on each thread depends on
the concurrency semantics of the
target bean. See Section 4.3.14 and Section 4.8.5 for details of
the concurrency behavior for session beans.
Summary of § 4.3.14:
If the bean is SLSB, each call will be served by one EJB in the app. server pool. The app. server synchronizes the calls the EJB instances, so each EJB instance are never accessed concurrently.
For SFSB, each call is dispatch to one specific EJB instance, and the app. server does not synchronises the call. So two concurrent calls to the remote reference might lead to a concurrent access to the EJB instance which raises then a javax.ejb.ConcurrentAccessException. The client is responsible of the correct synchronization of the access to the remote reference.
And § 4.8.5 is about EJB singleton, probably not what you are using.
I assume you use SLSB, so you don't need to have a pool on the client-side: look up the remote bean once, and use the same reference from multiple threads.
You could however do a benchmark to see if using multiple reference improves performance, but the gain -- if any -- is probably neglectable compare to the cost of the remote invocation itself.
If then you still decide to have more than one remote reference, I would suggest an other design. Based on your question I assume you have a multi-threaded app. You probable already use a pool for the threads, so a pool for the reference is maybe redundant. If each thread gets a remote reference when it is created, and threads are pooled, there won't be that many remote lookup and the design is simplified.
My 2 cents
I'm answering for JBoss AS since I have limited experience with other AS:s.
Remote JNDI-references are just (load-balancing) connection-less proxies (see JBoss clustering proxy architecture). Serializing them is fine, which means that you can keep them as members in other EJBs, and cache them as you do (I don't know if your pool serializes your objects, some caches do).
Regarding invalidation of proxies:
The proxies will open a connection only for the duration of the method call, and therefore does not have a 'connected' state per se. The proxies can additionally have multiple IP-addresses and load-balance. In JBoss the node list is dynamically updated at every method call, so the risk of a reference to go stale is small. Still there is a chance for this to happen if all nodes go down or the proxy remains inactive while all node IP addresses go stale. Depending on the pool reuse policy (LRU or other?) the the probability that the rest of the cached proxies are invalid once one is will vary. A fair policy will minimize the risk of having very old entries in the pool, which you would like to avoid in this scenario.
With a fair policy in place, the probability that all go stale for the same reason increases, and your 'clear pool once one is stale' policy would make sense. Additionally, you need to take the case of the other node being down into account. As it is now, your algorithm would go into a busy-loop looking up references while the other node is down. I would implement an exponential back-off for the retries, or just consider it a fatal failure and make the exception a runtime exception, depending on whether you can live with the remote EJB being gone for a while or not. And make the exception you catch specific (like RemoteCommunicationFailedException), avoid catching generic exceptions or errors like Exception, Error or Throwable.
Another question you must ask yourself is the amount of concurrency that you want. Normally proxies are thread-safe for SLSBs and single thread only for SFSBs. SFSBs themselves are not thread safe, and SLSBs serialize access per default. This means that unless you enable concurrent access to your EJB 3.1 beans (see tss link) you will need one remote reference per thread. That is: pooling N SLSB remote references will give you N threads concurrent access. If you enable concurrent access and write your SLSB as a thread-safe bean with the annotation #ConcurrencyAttribute(NO_LOCK) you can get unlimited concurrency with just one proxy, and drop your whole pool. Your pick.
EDIT:
ewernli was right, the thread-safe SLSB proxy creates one new instance on the server per call. This is specified in 4.3.14:
There is no need for any restrictions
against concurrent client access to
stateless session beans because the
container routes each request to a
different instance of the stateless
session bean class.
This means that you don't need any pool at all. Just use one remote ref.
Related
I can't understand how the EJB container manage thread-safety for #Stateless beans with instance variables. So I will give a simple example before explaining my concerns:
#Stateless
public class BeanTest{
#Inject
private String var;
private Connection connection;
#Resource(name = "jdbc/TestDB")
private DataSource dataSource;
public void modify() {
var = "TestName";
}
#PostConstruct
public void initialize() {
try {
connection = dataSource.getConnection();
} catch (SQLException sqle) {
sqle.printStackTrace();
}
}
#PreDestroy
public void cleanup() {
try {
connection.close();
connection = null;
} catch (SQLException sqle) {
sqle.printStackTrace();
}
}
}
Here is my questions, assuming that our container supports pooling:
1. Pooling vs Thread-safe:
User 1 used an instance of BeanTest and modified the var using the modify method, then he finished and the container put the instance of BeanTest in the managed pool. When User 2 tries to use the same bean for a request, he might get the same instance of BeanTest intially modified by User 1 (I understand that might get another instance too). So which state of the instance variable var he will find (default value which is null or "TestName")? if its the new modified one, do that mean that even #Stateless beans are not 100% thread-safe? So finnaly there is no container added -value regarding thread safety, as not using instance variable makes a bean thread safe even if it's not a #Stateless bean
2. Pooling vs #PreDestroy
If the bean is returned to the managed pool and not destroyed, do that mean that the #Predestroy method will not be called and in that case the connection will stay opened ? So, if we have 30 inctance of that bean in the pool, we may have 30 open connection that is not used, isn't that a performance issue? or this not how #Predestroy is working conbined with pooling? (using Connection is just an example, we may have other kind of ressource that we need to close in #Predestroy)
NB: This is not a real life example, so I'am not looking for an alternative solution, my concern is to understand the whole concept and how things are managed in the Application Server, what is happening under the hood
I think the Thread-Safety you are referring to is the non-reenterant clause
The Responsibilities of the Container Provider
Enterprise JavaBeans 3.2, Final Release Session Bean Component Contract
April 10, 2013 2:59 pm Oracle
4.10.13 Non-reentrant Instances The container must ensure that on ly one thread can be executing a st ateless or stateful session bean
instance at any time. Therefore, statef ul and stateless session beans
do not have to be coded as reentrant. One implication of this rule
is that an application ca nnot make loopback calls to a stateless or
stateful session bean instance
You could in a stateless session bean, ignore the EJB programming restrictions, create a bunch of threads and do something non-Thread safe. the container won't stop you. This may cause all sorts of errors due to thread management conflicts.
The container only promises that it will only allow 1 thread access to the stateless ejb at a time. (there are some different rules around singletons)
you are right, that if the instances are returned to a pool that the connections in your example could build up. because of course the been instance still exists.
If you dig in to app server docs, ie Glassfish EJB pool tuning chapter, you will find that the default is to destroy the object instances rather than return them to the pool. same with the JDBC connections, which would get closed and cleaned up. Re-use is an option, in which case you could consume some extra memory if you attempt to create state in SSBs. I don't think there is much performance impact if the instance is sitting idle in a pool.
the exact pooling implementation is up to the application server vendor, so long as they obey the spec. I think you will find the default behavior is to destroy the instance after use. Which causes managed resources to get cleaned up.
But all this is kind of mute, in your example you are trying to store a state, the connection field, in the class. There is no need to create state in a stateless component, that is not what this type of component is for. Other parts of the Java EE architecture handle state. (entities, statefulbeans, JCA)
1) The container guarantees Thread safety which means that a single thread can access a given SLSB at a time. It has nothing to do with guaranteeing that the state won't be changed. BTW having mutable state inside SLSB makes no sense at all.
2) You don't want to keep a connection during the lifetime of a SLSB because you're effectively preventing it from returning to the pool risking an exhaustion.
If the injected AnotherBean is stateless, then it makes no sense to call AnotherBean.setName(). If it is statefull, then it does not make sense to inject a stateful bean in a stateless one (check what stateful beans are made for). About thread-safety: the container cannot make your classes thread safe themself, but it guarantees that a single client thread will use a certain EJB instance at a time (check the quotation from Chris' answer). So, if you do not use an EJB in different threads in your EJB client, then your code is thread-safe by using thread confinment.
Do not use instance variables other then injected ones in a stateless bean. Otherwise you are not consistent with your #Stateful annotation. So, remove the connection state variable. Anyway, you do not want to keep an open connection for long only for your bean: get it every time from the datasource. Also do not forget to close the connection after you used it (in a try/finally clause). With pooling, it works like a JDBC connection pool: when the pool/EJB container decides it does not need the instance anymore (e.g when it wants to reduce the number of instances or when a non application exception is thrown), then the #PreDestroy method wil be called.
I have a war file deployed in glassfish. We have some stateless session beans and we have 1 synchronized method in it.
However, I am noticing that more than 1 thread is able to enter the synchronized method concurrently. Is it possible that glassfish is instantiating 2 instances of this bean class? Is there any way around this?
Yes, of course it's possible. The spec even mandates that concurrent calls are handled by different instances.: this is one of the services offered by the container: it makes sure that concurrent calls are handled concurrently, and not sequentially, and you're free to implement your sesssion bean without caring about thread-safety (for example, by using instance variables), because the container takes care of it.
What you want is a singleton.
The spec for JMS sessions warns that Session objects/instances must only be used on the thread in which they are created when there are MessageListener instances registered to a Session. However, it doesn't say anything about being thread-un-safe, or perhaps more accurately, "thread-bound", when using MessageConsumer objects (only).
http://docs.oracle.com/javaee/1.3/api/javax/jms/Session.html
(by "thread-bound", I mean that the object must only be used, ever, on a specific thread, not just that it's unsafe to use it on multiple threads without synchronization or other coordination)
The answer to this question also suggests that Sessions are thread-bound: Relationship between JMS connections, sessions, and producers/consumers
However, there may or may not be some assumptions the author is making, and the question is also more about writing messages than about reading them.
Does anybody know if you can read a message in a Session on one thread, and then have another thread deal with the message and do a commit/rollback for the message (with the session) on that other thread? Only commit (or rollback) would be called against the Session from within the processing thread -- no other calls would be made to the Connection / Session / MessageConsumer / Message chain. Also, the Session would not be used to read again until after the commit/rollback occurred.
The following S/O questions seem closely related, but do no satisfactorily address what I am proposing:
How to continuously read JMS Messages in a thread and achnowledge them based on their JMSMessageID in another thread?
Reason for a JMS Session object to be used in a single threaded context
While I would like to use a Session on multiple threads, there will never be overlapping message requests/transactions.
I'm trying to avoid further refactoring of existing code, so I'm considering doing something a little odd, rather than having a Session on each worker thread.
edit (July 26) - - -
This question, Using a JMS Session from different threads, seems to suggest that it is OK to do synchronized operations with a session on different threads, but I am uncertain which version of the spec is referenced.
Maybe you have found a way in the specification.
A quote from the doc of Sessionhttp://docs.oracle.com/javaee/1.3/api/javax/jms/Session.html
A Session object is a single-threaded context for producing and consuming messages. Although it may allocate provider resources outside the Java virtual machine (JVM), it is considered a lightweight JMS object.
So it's single-threaded; and it's not expensive to create one.
And you have to pay attention to
The close method is the only session method that can be called while some other session method is being executed in another thread.
So you have to make sure that read and commit do not overlap, for example.
From a technical point of view I would refactor it; the code will be easier to read/maintain. Resource handling (open/close) would be in one thread (one method) only. This would simplify exception handling as well.
[From a legal point of view: You admit that you are doing something "odd" - against the recommendation. I would not deliver such a piece of software.]
What is the reason why the Application Servers pool the Stateless EJBs?
I can understand that it is usefull to control the workload of the application for incomming invokations, but this only justifies the pooling of the EJBs that server as FAÇADE with the invoker client.
Does it have any benefit to pool the internal EJBs (those that are not exposed and only invoked internally to perform business logic)?? instead of use a shared single instance (like Spring does).
I can think about at least one downside: a highly used internal EJB could act as a bottleneck.
Stateless session bean EJBs are not necessarily thread-safe. They can be holding resources like JMS sessions which cannot be shared with more than one thread at a time so the server will pool them so that it can serve multiple requests for the same bean concurrently (JMS resources are also pooled, but I'm just using that for the sake of example).
I would also like to know why stateless EJBs are pooled. But i want to know why they're pooled rather than being created and destroyed on demand. The fact that instances can be reused for unrelated requests significantly complicates the implementation of stateless beans (it means you have to be incredibly careful about the use of instance fields), and i don't see any significant benefit to it.
Specifically, i don't see any performance benefit to it. I poked through the implementation of stateless beans in JBoss (6, IIRC), and its only the bean instance itself that's pooled; the plumbing to handle method invocation is recreated from scratch each time it's used. That means that the only performance saving is a single object creation, which should be a trivial amount of time. The only situation in which i can see it being non-trivial is if the bean acquires heavyweight resources, and holds on to them between invocations. However, in that case, the bean is really being used as a glorified, badly-managed, pool; the correct solution would be to pool the resource directly!
Now, EJB has been around a long time. Back when they first came out, object creation was expensive, so it made sense to pool them. But those days are long gone. Why was pooling not dropped in EJB3?
Also, does the object that is being set have to be thread safe in order to guarantee that we know what the state of the object stored in session is known.
Also, I was reading on the web that some suggest using:
synchronized(session) {
session.setAttribute("abc", "abc");
}
Is this a valid suggestion?
Servlet 2.5 spec:
Multiple servlets executing request
threads may have active access to the
same session object at the same time.
The container must ensure that
manipulation of internal data
structures representing the session
attributes is performed in a
threadsafe manner. The Developer has
the responsibility for threadsafe
access to the attribute objects
themselves. This will protect the
attribute collection inside the
HttpSession object from concurrent
access, eliminating the opportunity
for an application to cause that
collection to become corrupted.
This is safe:
// guaranteed by the spec to be safe
request.getSession().setAttribute("foo", 1);
This is not safe:
HttpSession session = request.getSession();
Integer n = (Integer) session.getAttribute("foo");
// not thread safe
// another thread might be have got stale value between get and set
session.setAttribute("foo", (n == null) ? 1 : n + 1);
This is not guaranteed to be safe:
// no guarantee that same instance will be returned,
// nor that session will lock on "this"
HttpSession session = request.getSession();
synchronized (session) {
Integer n = (Integer) session.getAttribute("foo");
session.setAttribute("foo", (n == null) ? 1 : n + 1);
}
I have seen this last approach advocated (including in J2EE books), but it is not guaranteed to work by the Servlet specification. You could use the session ID to create a mutex, but there must be a better approach.
No. And since you don't want the same client (with session) to be doing concurrent requests, you should serialize these requests like the AbstractController does in Spring MVC
In some ways, this depends on your client design.
Do you have the opportunity, in your web design, for a single client to have multiple outstanding simultaneous requests using the same HTTP session? This seems difficult to do unless you tie a single HTTP session to multiple sockets. (aka, AJAX) Short of doing this, a given client's HTTP access will be single-threaded as far as the server is concerned, which means a single session is effectively Thread safe.
Synchronization of your session objects will make the application safer against future changes that make your web application capable of having multiple simultaneous requests, so it's not a bad idea. In modern Java implementations, synchronization does not have the large cost that was previously associated with it, especially when the synchronization is usually uncontended. If your application uses AJAX, which implies that you expect multiple in-flight simultaneous requests to your web server, then synchronization is a must.
They are not, but most of the times, your clients will only access them with a single thread.
Different clients will have different threads and each one will have its own Session.
As Eddie points out, one situation where you may face two thread accessing the same session is two ajax calls are attempting to modify the same session attribute. Otherwise you won't have problems.
The session is not thread safe and neither the get not the set methods are guaranteed to be thread safe. In general in a servlet container you should assume to be in a multi threaded environment and no provided tooling is safe.
This also goes for the objects you store in the session. The session itself will not manipulate the stored object but you can retrieve the object in different thread and attempt to manipulate it. It is up to you to examine your own code to see if race conditions are possible.
The code example you posted is valid, but the problem may exist beyond the limited scope of your example. It assures there are no conditions while setting to the session, but there is nothing preventing an other thread to override the set. If the code in your request depends of the value remaining unchanged you could still be in trouble.