原文:
http://www.mastertheboss.com/jboss-server/jboss-performance/jboss-as-7-performance-tuning?showall=&start=2
TUNING EJB connection pool
The creation and destruction of beans can be an expensive operation, especially if they acquire external resources. To reduce this cost, The EJB container creates pool of beans which, therefore, don't need to be re-initialized every time they are needed.
The Stateless EJB pool and MDB pool are used to provide stateless business services to their client, acquiring beans from the pool when they are requested and releasing the bean to the pool as soon as they are finished.
A typical EJB pool configuration looks like the following:
1
2
3
4
5
6
|
<
pools
>
<
bean-instance-pools
>
<
strict-max-pool
name
=
"slsb-strict-max-pool"
max-pool-size
=
"20"
instance-acquisition-timeout
=
"5"
instance-acquisition-timeout-unit
=
"MINUTES"
/>
<
strict-max-pool
name
=
"mdb-strict-max-pool"
max-pool-size
=
"20"
instance-acquisition-timeout
=
"5"
instance-acquisition-timeout-unit
=
"MINUTES"
/>
</
bean-instance-pools
>
</
pools
>
|
At the time of writing in AS 7, there is only support for strict-max-pool as a bean instance pool.
A strict max pool allows you to configure a maximum upper limit for the pool. At runtime, when all the bean instances from the pool are in use and a new bean invocation request comes in, the pool blocks the request till the next bean instance is available or till a timeout (set in instance-acquisition-timeout) is reached.
Monitoring the EJB pools will be soon available through the CLI, which will have a set of minimal operations to check the pool metrics. Setting up a self-made solution to monitor the current pool size is, however, not too complicated: you can use the handy EJB3 Interceptor API to monitor the EJB which have been taken from the pool and those which have been released.
In the following Interceptor, we are simply setting a single EJB Singleton field before contacting the EJB, and after that, it has completed its job and hence returned to the pool.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package
com.packtpub.chapter12;
import
javax.ejb.EJB;
import
javax.interceptor.AroundInvoke;
import
javax.interceptor.InvocationContext;
public
class
EJBInterceptor {
@EJB
EJBCounter singleton;
@AroundInvoke
public
Object defaultMethod(InvocationContext context)
throws
Exception{
// Take a bean from the pool
singleton.getFromPool();
// Invoke the EJB method
Object result = context.proceed();
// Return the bean to the pool
singleton.returnToPool();
// Prints out the current pool size
singleton.dumpPoolSize();
return
result;
}
}
|
The EJBCounter is a singleton EJB which merely contains the counter variable, holding the EJB max-pool-size.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package
com.packtpub.chapter12;
import
javax.ejb.Singleton;
@Singleton
public
class
EJBCounter {
private
int
count=
20
;
public
void
getFromPool() {
count--;
}
public
void
returnToPool() {
count++;
}
public
void
dumpPoolSize() {
System.out.println(
"Current pool size is "
+count);
}
}
|
You can further refine this approach by adding a @PostContruct annotation which loads this variable from an external source such as the DB or a property file.
Another viable option is launching a CLI script which collects the value from the max-pool-size attribute. Here's an example:
{xtypo_code}[standalone@localhost:9999 /] /subsystem=ejb3/strict-max-bean-instance-pool=slsb-strict-max-pool:read-attribute(name="max-pool-size")
{
"outcome" => "success",
"result" => 20
}{/xtypo_code}
The interceptors can be then applied to the stateless EJB which are used by your application either by means of a simple annotation or by declaring them into the ejb-jar.xml configuration file. For example, here's how to intercept all EJB invocations via the @Interceptors annotation:
1
2
3
4
5
6
7
8
|
import
javax.ejb.Stateless;
import
javax.interceptor.Interceptors;
@Stateless
@Interceptors
(EJBInterceptor.
class
)
public
class
EJBTest {
. . .
}
|
Turning off the EJB pool
Although this might sound weird to you, there can be some scenarios where you don't want your EJB resources to be managed by a pool but created on demand. For example, if your EJB does not need a costly initialization (like acquiring an external resources), it can be advantageous, in terms of performance, to avoid using the EJB 3 pool. (the JBoss 5 Performance tuning book, for example, shows a case where a so-called heavy Stateful EJB can even outperform the Stateless counterpart. This is mostly due to the fact that handling the stateless pool is not a trivial task in terms of performance).
Switching off the EJB pool just requires to comment/evict the bean-instance-pool-ref element which refers to the EJB pool:
1
2
3
4
5
|
<
stateless
>
<!--
<bean-instance-pool-ref pool-name="slsb-strict-max-pool"/>
-->
</
stateless
>
|
Of course, it is strongly recommended to run a consistent test bed to demonstrate that your application can benefit from such a change, which will take away any check on the number of EJB instances.