JBoss performance tuning tips and hints – Part 2

Important notice: This article has been originally written for JBoss EAP 5 and contains some best practices to tune the application server and the environment where it's running. Although some indications are still valid, we recommend also taking a look at the following articles which are more recent:

JBoss Performance Tuning Part 2

Tip 15: Lots of EJB requests ? switch to the PoolInvoker

JBoss uses RMI for EJB communication and by default creates a single thread for every incoming request.

When the number of requests is very large this could be a bottleneck. However you can switch from the standard jrmp service invoker to the pool invoker. How to do it ? open standardjboss.xml and find the following fragment:


  On JBoss 4.x you should find 4 occurrences of it: stateless-rmi-invoker, clustered-stateless-rmi-invoker, stateful-rmi-invoker,entity-rmi-invoker. Now replace this fragment with :


Notice you can even have a mixed environment: that is stateless invocation managed by the pool and all others by jrmp.

If you want to change the default attributes of your pool then open jboss-service.xml

 <mbean code="org.jboss.invocation.pooled.server.PooledInvoker"
  <attribute name="NumAcceptThreads">1</attribute>
  <attribute name="MaxPoolSize">300</attribute>
  <attribute name="ClientMaxPoolSize">300</attribute>
  <attribute name="SocketTimeout">60000</attribute>
  <attribute name="ServerBindAddress">${jboss.bind.address}</attribute>
  <attribute name="ServerBindPort">4445</attribute>
  <attribute name="ClientConnectAddress">${jboss.bind.address}</attribute>
  <attribute name="ClientConnectPort">0</attribute>
  <attribute name="ClientRetryCount">1</attribute>
  <attribute name="EnableTcpNoDelay">false</attribute>

There are two key attributes for the PooledInvoker in regards to how many threads are used in processing requests.  The first is the NumAcceptThreads attribute.  The value for this attribute will determine how many threads are created to listen for incoming requests. These threads will be the ones that call the accept() method of the server socket (which is a blocking call and will wait there till data is received on the network interface for the server socket).

The MaxPoolSize is the other key factor: it’s the size of the pool containing the ServerThreads .
How can MaxPoolSize become a bottleneck ?  if the accept thread can not get a worker thread from the pool and the pool size has reached the MaxPoolSize value, it will wait for one to become available (instead of creating a new one).

Tip 16: Have you got readonly Entity Beans ? tell it to JBoss

JBoss offers a way to handle this situation by defining either an entire EJB as being “read-only” or simply as a subset of its methods. When accessing a read-only method (or EJB), while JBoss still prevents concurrent access to the same bean instance, the bean will not be enrolled in the transaction and will not be locked during the whole transaction lifetime. Consequently, other transactions can directly use it for their own work.


Tip 17: Disable the hot deployer in production

See this tip: How to configure JBoss to disable hot deployment ?

Tip 18: Configure the EJB container to use cache, when possible.

If the EJB container has exclusive access to the persistent store, it doesn’t need to synchronize the in-memory bean state from the persistent store at the beginning of each transaction. So you could activate the so-called Commit-A option that caches entity bean state between transactions. In order to activate this option :


 <container-configuration extends=
 "Standard CMP 2.x EntityBean">
 <container-name>CMP 2.x and Cache</container-name>
 CMP 2.x and Cache</configuration-name>

Tip 19: Use Cache invalidation in a Cluster for Commit Option A
Commit option A can boost your Entity Bean but what happens when running in a cluster ? in a cluster configuration more than one JBoss node will access the same database. Furthermore, they will not only read data, but may also update the db store.Consequently, we now have as many points of write access to the database as we have JBoss instances in the cluster.

For these scenarios, JBoss incorporates a handy tool: the cache invalidation framework. It provides automatic invalidation of cache entries in a single node or across a cluster of JBoss instances. As soon as an entity bean is modified on a node, an invalidation message is automatically sent to all related containers in the cluster and the related entry is removed from the cache. The next time the data is required by a node, it will not be found in cache, and will be reloaded from the database.

In order to activate it, add to your Entity Bean the cache-invalidation tag:

   <configuration-name>Standard CMP 2.x with cache invalidation</configuration-name>

Tip 20: Synchronize at commit time when possible.
The sync-on-commit-only element configures a performance optimization that will cause entity bean state to be synchronized with the database only at commit time. Normally the state of all the beans in a transaction would need to be synchronized when an finder method is called or when an remove method is called :

 <container-name>Standard Pessimistic CMP 2.x EntityBean</container-name>

Tip 21: Use Prepared Statement Cache:

In JBoss, by default,prepared statements are not cached. To improve performance one can configure a prepared statement cache of an arbitrary size. You can use in your -ds.xml file the <prepared-statement-cache-size> : this is the number of prepared statements per connection to be kept open and reused in subsequent requests.

Tip 22: Remove services you don’t need

JBoss ships with lots of services, however you’ll seldom need to use them all. The service is usually deployed as *-service.xml under the deploy directory. Sometimes it’s also deployed as .sar/.rar archive. In order to remove the service, remove the file in the “Server/deploy” column. If needed remove also the relative libs stated under “Server/lib” 

Mail service
mail-plugin.jar, mail.jar,activation.jar
Cache invalidation service
J2EE client deployer service
Hibernate HAR support
jboss-hibernate.jar, hibernate2.jar, cglib-full-2.0.1.jar, odmg-3.0.jar
hsqldb-plugin.jar, hsqldb.jar
Default JMS Service
jms folder
HTTP Invoker (tunnels RMI through HTTP)
XA Datasources
JMX Console
Web Console
Monitoring mail alerts
Schedule Manager
scheduler-plugin.jar, scheduler-plugin-example.jar
Sample Schedule service

If you are removing a core JBoss service like JMS or EAR Deployer then you need to remove it also from the jboss-service.xml :

 <mbean code="org.jboss.management.j2ee.LocalJBossServerDomain"
 <attribute name="MainDeployer">jboss.system:service=MainDeployer</attribute>
 <attribute name="SARDeployer">jboss.system:service=ServiceDeployer</attribute>
 <attribute name="EARDeployer">jboss.j2ee:service=EARDeployer</attribute>
 <attribute name="EJBDeployer">jboss.ejb:service=EJBDeployer</attribute>
 <attribute name="RARDeployer">jboss.jca:service=RARDeployer</attribute>
 <attribute name="CMDeployer">jboss.jca:service=ConnectionFactoryDeployer</attribute>
 <attribute name="WARDeployer">jboss.web:service=WebServer</attribute>
 <attribute name="CARDeployer">jboss.j2ee:service=ClientDeployer</attribute>
 <attribute name="MailService">jboss:service=Mail</attribute>
 <attribute name="JMSService">jboss.mq:service=DestinationManager</attribute>
 <attribute name="JNDIService">jboss:service=Naming</attribute>
 <attribute name="JTAService">jboss:service=TransactionManager</attribute>
 <attribute name="UserTransactionService">jboss:service=ClientUserTransaction</attribute>
 <attribute name="RMI_IIOPService">jboss:service=CorbaORB</attribute>

Simply comment the attribute relative to the unwanted service

Tip 22: Tell log4j to shut up !

Wel not really anyway Log4j uses a valuable amount of time/CPU so you had better remove unnecessary logs, for example :

  • Remove logs from Console

Comment the following line in log4j.xml in order to remove logs on the Console:

<!-- <appender-ref ref=CONSOLE"></appender-ref>  -->  
<appender-ref ref="FILE"></appender-ref>

remove also the relative appender:

<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender"> 
  • Raise log priority

Consider raising the log level to the highest level possible in production. Here only error logs are written:

   <priority value="ERROR"  />  
    <!--<appender-ref ref="CONSOLE"></appender-ref> -->   
    <appender-ref ref="FILE" />

Hungry for Tuning?

     Speed-up your Enterprise Applications with our WildFly Performance Tuning guide!