This tutorial is a follow-up to the JBoss AS 7 Performance tuning tutorial. We will focus now on the incoming request flows as they cross the WildFly borders. And we will learn how to monitor the most critical attributes.

If you want to tune a complex beast like a Java application server it is crucial that you understand the single steps that the request performs before reaching the target component. All the rest has usually a minor impact on performance.

So let's see a typical request coming from a Web front-end and reaching WildFly EJBs which in turn invoke the database:

wildfly performance tuning

As you can see from the above picture, the thread that is driving a Web based request is Undertow XNIO thread which is created by Undertow handlers. Setting the correct amount of IO threads is crucial in this scenario, otherwise you will have a bottleneck at the beginning of your request.

Provided that there are enough io-threads to serve your http request, the core-max-threads (first) and the task-max-threads (after) are used to determine in the request is served or if it is going to be discarded.

Undertow threads are configured through the IO subsystem. Here is how to set the number XNIO pool for a medium-large sized Web site:




Still in the Web layer, you need to take into account the number of sessions which are running. The parameter max-active-sessions is used to determine how many active HTTP session will be allowed. If session creation would cause the number of active sessions to exceed <max-active-sessions/>, then the oldest session known to the session manager will passivate to make room for the new session. That's a big price in terms of performance so let's see how to configure it using jboss-web.xml:




Then, keep monitoring the number of sessions using the CLI. In order to do that, you need to point to your /deployment path and enter into its undertow subsystem path:



    "outcome" => "success",

    "result" => {

        "active-sessions" => 1,
        "context-root" => "/webapp",
        "server" => "default-server",
        "sessions-created" => 1,
        "virtual-host" => "default-host",
        "servlet" => {

            "Faces Servlet" => undefined,
            "demo.DownloadServlet" => undefined


Into the EJB Container

Once the IO thread reaches the EJB container, an EJB is picked up from the Pool (Stateless EJB) or pinned from the Cache (Stateful EJB). This is the second element that you need to consider in this scenario: that you have enough resources on your EJB Container.  

As a matter of fact, if you are using Stateless Session Beans you must be aware that EJB pooling is not enabled by default on WildFly 8. The rationale behind this decision is that an accurate pool size is tightly dependent on your application and cannot be easily guessed. Therefore, a poorly configured pool of EJBs could be even detrimental in terms of performance, causing excessive cycles of garbage collections. For this reasons, it’s up to you to turn on this feature and set a correct configuration for its parameters.

This requires however just as little as a combo box selection from the EJB3 Container tab. Or a simple CLI command:


If you are using Stateful EJBs you will rather deal with a Cache of Beans that contain conversational data.

The Stateful cache by default uses a simple caching system which does not involve Passivation of data. This might be desirable in terms of performance, however if you need to use a Passivation mechanism in your application, you must learn how to configure the limits of your cache.

At first you need to enable the SFSB to use a passivation capable cache like the distributable:


Then, you can configure the maximum number of SFSB allowed in the cache. For example, the distributable cache uses the infinispan passivation-store which allows a maximum number of 10000 elements in the cache


Monitoring the EJB container

Once that you have configured your Pool or Cache, it is time to monitor if your configuration is appropriate. As for the Web layer, you can obtain this information through your deployment unit, by digging into the ejb3 subsystem as follows:



    "outcome" => "success",
    "result" => {
        "component-class-name" => "Manager",
        "declared-roles" => [],
        "execution-time" => 0L,
        "invocations" => 0L,
        "methods" => {},
        "peak-concurrent-invocations" => 0L,
        "pool-available-count" => 20,
        "pool-create-count" => 1,
        "pool-current-size" => 1,
        "pool-max-size" => 20,
        "pool-name" => "slsb-strict-max-pool",
        "pool-remove-count" => 0,
        "run-as-role" => undefined,
        "security-domain" => "other",
        "timers" => [],
        "wait-time" => 0L,
        "service" => undefined

Into the EIS

If you have enough resources in the EJB container, then the IO thread will continue its race to the last step which is usually the Database, but could be as well another EIS. 

In case you are dealing with Database connections, you must acquire a connection from the pool, that is governed by the JCA layer. The key configuration parameter is max-pool-size which specifies the maximum number of connections for a pool. (Default 20). Note that there will be a maximum limit for the number of connections allowed by the database to match.

You can set your Connection pool max size to a different attribute using this CLI:


Note in this tutorial (Monitor WildFly with your bash skills) we have demonstrated how to monitor the Connection pool with some simple bash and CLI interaction

The remote EJB request flow

In the second example, we will cover a slightly different approach which involves remote EJB calls. (Think for example of a remote EJB client). 

wildfly performance tuning

Since WildFly 8, these calls are not landing directly into the EJB Container, but they are mediated by Undertow which performs an Http upgrade towards the Remoting channel.

What is the main difference with the scenario that we have just covered ? As you can guess from the picture, the IO thread is not any more the driver of the call, but the EJB Thread pool comes into play. You can set the EJB thread pool from the ejb3 subsystem as follows:


In this example, we have set it to 100 which should be a fairly high value.

The Undertow threads still have some relevance in this scenario, as they will be used in case you are using async calls to your EJB and for providing the response to the client (Thanks to Stuart Douglas for pointing out this needful information). You can monitor the thread pool at runtime using the following CLI:

    "outcome" => "success",
    "result" => {
        "active-count" => 5,
        "completed-task-count" => 13L,
        "current-thread-count" => 3,
        "keepalive-time" => {
            "time" => 100L,
            "unit" => "MILLISECONDS"
        "largest-thread-count" => 5,
        "max-threads" => 10,
        "name" => "default",
        "queue-size" => 0,
        "rejected-count" => 0,
        "task-count" => 0L,
        "thread-factory" => undefined

In the next WildFly tuning tutorial we will learn one different scenario which involves using JMS into the flow chain.

Other resources you might be interested:

JBoss Performance Tuning part 1

JBoss performance tuning part 2

Hungry for Tuning?

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