16 min read

 

Various subsystem configurations

 

This article by Arnold Johansson and Anders Welen, the authors of WildFly Performance Tuning, talks about the various subsystem configurations available for WildFly.

In a high-performance environment, every costly resource instantiation needs to be minimized. This can be done effectively using pools. The different subsystems in WildFly often use various pools of resources to minimize the cost of creating new ones. These resources are often threads or various connection objects. Another benefit is that the pools work as a gatekeeper, hindering the underlying system from being overloaded. This is performed by preventing client calls from reaching their target if a limit has been reached.

In the upcoming sections of this article, we will provide an overview of the different subsystems and their pools.

 

The thread pool executor subsystem

 

The thread pool executor subsystem was introduced in JBoss AS 7. Other subsystems can reference thread pools configured in this one. This makes it possible to normalize and manage the thread pools via native WildFly management mechanisms, and it allows you to share thread pools across subsystems.

 

The following code is an example taken from the WildFly Administration Guide

(https://docs.jboss.org/author/display/WFLY8/Admin+Guide) that describes how the Infinispan subsystem may use the subsystem, setting up four different pools:

 

<subsystem > <thread-factory name=”infinispan-factory” priority=”1″/> <bounded-queue-thread-pool name=”infinispan-transport”>

 

<core-threads count=”1″/> <queue-length count=”100000″/> <max-threads count=”25″/>

<thread-factory name=”infinispan-factory”/> </bounded-queue-thread-pool> <bounded-queue-thread-pool name=”infinispan-listener”>

 

<core-threads count=”1″/> <queue-length count=”100000″/> <max-threads count=”1″/>

<thread-factory name=”infinispan-factory”/> </bounded-queue-thread-pool>

 

<scheduled-thread-pool name=”infinispan-eviction”> <max-threads count=”1″/>

 

<thread-factory name=”infinispan-factory”/> </scheduled-thread-pool>

 

<scheduled-thread-pool name=”infinispan-repl-queue”> <max-threads count=”1″/>

 

<thread-factory name=”infinispan-factory”/> </scheduled-thread-pool>

 

</subsystem>

 

 

<cache-container name=”web” default-cache=”repl” listener-executor=”infinispan-listener” eviction-executor=”infinispan-eviction” replication-queue-executor=”infinispan-repl-queue”> <transport executor=”infinispan-transport”/> <replicated-cache name=”repl” mode=”ASYNC” batching=”true”>

 

<locking isolation=”REPEATABLE_READ”/> <file-store/>

</replicated-cache> </cache-container>

 

The following thread pools are available:

 

        unbounded-queue-thread-pool

 

        bounded-queue-thread-pool

 

        blocking-bounded-queue-thread-pool

 

        queueless-thread-pool

 

        blocking-queueless-thread-pool

 

        scheduled-thread-pool

 

The details of these thread pools are described in the following sections:

 

unbounded-queue-thread-pool

 

The unbounded-queue-thread-pool thread pool executor has the maximum size and an unlimited queue. If the number of running threads is less than the maximum size when a task is submitted, a new thread will be created. Otherwise, the task is placed in a queue. This queue is allowed to grow infinitely.

The configuration properties are shown in the following table:

max-threads             Max allowed threads running simultaneously

This specifies the amount of time that pool threads should be keepalive-time kept running when idle. (If not specified, threads will run until

 

the executor is shut down.)

 

thread-factory           This specifies the thread factory to use to create worker threads.

bounded-queue-thread-pool

 

The bounded-queue-thread-pool thread pool executor has a core, maximum size, and a specified queue length. If the number of running threads is less than the core size when a task is submitted, a new thread will be created; otherwise, it will be put in

 

the queue. If the queue’s maximum size has been reached and the maximum number of threads hasn’t been reached, a new thread is also created. If max-threads is hit, the call will be sent to the handoff-executor. If no handoff-executor is configured, the call will be discarded.

 

The configuration properties are shown in the following table:

core-threads             Optional and should be less that max-threads


 

queue-length

 

max-threads

 

 

keepalive-time


 

This specifies the maximum size of the queue.

 

This specifies the maximum number of threads that are allowed to run simultaneously.

 

This specifies the amount of time that pool threads should be kept running when idle. (If not specified, threads will run until the executor is shut down.)


 

handoff-

This specifies an executor to which tasks will be delegated, in

executor

the event that a task cannot be accepted.

allow-core-

This specifies whether core threads may time-out; if false, only

timeout

threads above the core size will time-out.

thread-factory

This specifies the thread factory to use to create worker threads.

 

blocking-bounded-queue-thread-pool

 

The blocking-bounded-queue-thread-pool thread pool executor has a core, a maximum size and a specified queue length. If the number of running threads is less than the core size when a task is submitted, a new thread will be created. Otherwise, it will be put in the queue. If the queue’s maximum size has been reached, a new thread is created; if not, max-threads is exceeded. If so, the call is blocked.


The configuration properties are shown in the following table:

core-threads             Optional and should be less that max-threads


 

queue-length max-threads

 

keepalive-time


 

This specifies the maximum size of the queue.

 

This specifies the maximum number of simultaneous threads allowed to run.

 

This specifies the amount of time that pool threads should be kept running when idle. (If not specified, threads will run until the executor is shut down.)


 

allow-core-

This specifies whether core threads may time-out; if false, only

timeout

threads above the core size will time-out.

thread-factory

This specifies the thread factory to use to create worker threads

 

queueless-thread-pool

 

The queueless-thread-pool thread pool is a thread pool executor without any queue. If the number of running threads is less than max-threads when a task is submitted, a new thread will be created; otherwise, the handoff-executor will be called. If no handoff-executor is configured the call will be discarded.

 

The configuration properties are shown in the following table:

 

max-threads

Max allowed threads running simultaneously

 

The amount of time that pool threads should be kept running

keepalive-time   when idle. (If not specified, threads will run until the executor is

 

shut down.)

handoff-

Specifies an executor to delegate tasks to in the event that a task

executor

cannot be accepted

thread-factory

The thread factory to use to create worker threads

 

blocking-queueless-thread-pool

 

The blocking-queueless-thread-pool thread pool executor has no queue. If the number of running threads is less than max-threads when a task is submitted, a new thread will be created. Otherwise, the caller will be blocked.


The configuration properties are shown in the following table:

max-threads             Max allowed threads running simultaneously

This specifies the amount of time that pool threads should be keepalive-time kept running when idle. (If not specified, threads will run until

the executor is shut down.)

 

thread-factory   This specifies the thread factory to use to create worker threads

scheduled-thread-pool

 

The scheduled-thread-pool thread pool is used by tasks that are scheduled to trigger at a certain time.

 

The configuration properties are shown in the following table:

max-threads             Max allowed threads running simultaneously

This specifies the amount of time that pool threads should be keepalive-time kept running when idle. (If not specified, threads will run until

the executor is shut down.)

 

thread-factory   This specifies the thread factory to use to create worker threads

Monitoring

 

All of the pools just mentioned can be administered and monitored using both

CLI and JMX (actually, the Admin Console can be used to administer, but not see, any live data). The following example and screenshots show the access to an unbounded-queue-thread-pool called test.

 

Using CLI, run the following command:

 

/subsystem=threads/unbounded-queue-thread-pool=test:read-resource(include-runtime=true)

 

The response to the preceding command is as follows:

 

{

 

“outcome” => “success”, “result” => {

 

“active-count” => 0, “completed-task-count” => 0L, “current-thread-count” => 0, “keepalive-time” => undefined,

 

“largest-thread-count” => 0, “max-threads” => 100, “name” => “test”, “queue-size” => 0, “rejected-count” => 0, “task-count” => 0L,

 

“thread-factory” => undefined

 

}

 

}

 

Using JMX (query and result in the JConsole UI), run the following code:

 

jboss.as:subsystem=threads,unbounded-queue-thread-pool=test

 

An example thread pool by JMX is shown in the following screenshot:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

An example thread pool by JMX


The following screenshot shows the corresponding information in the Admin Console

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Example thread pool—Admin Console

 

The future of the thread subsystem

 

According to the official JIRA case WFLY-462 (https://issues.jboss.org/browse/WFLY-462), the central thread pool configuration has been targeted forremoval in future versions of the application server. It is, however, uncertain that all subprojects will adhere to this. The actual configuration will then be moved out to the subsystem itself. This seems to be the way the general architecture of WildFly is moving in terms of pools—moving away from generic ones and making them subsystem-specific. The different types of pools described here are still valid though.

 

Note that, contrary to previous releases, Stateless EJB is no longer pooled by default. More information of this is available in the JIRA case WFLY-1383. It can be found at

 

 https://issues.jboss.org/browse/WFLY-1383.

 

Java EE Connector Architecture and resource adapters

 

The Java EE Connector Architecture (JCA) defines a contract for an Enterprise Information Systems (EIS) to use when integrating with the application server. EISincludes databases, messaging systems, and other servers/systems external to an application server. The purpose is to provide a standardized API for developers and integration of various application server services such as transaction handling.

 

The EIS provides a so called Resource Adaptor (RA) that is deployed in WildFly and configured in the resource-adaptor subsystem. The RA is normally realized as one or more Java classes with configuration files stored in a Resource Archive (RAR) file. This file has the same characteristics as a regular Java Archive (JAR) file, but with the rar suffix.

 

The following code is a dummy example of how a JCA connection pool setup may appear in a WildFly configuration file:

 

<subsystem > <resource-adapters>

 

<resource-adapter> <archive>eisExample.rar</archive>

 

<!– Resource adapter level config-property –> <config-property name=”Server”>

 

localhost </config-property> <config-property name=”Port”>

 

6666 </config-property> <transaction-support>

 

LocalTransaction </transaction-support> <connection-definitions>

 

<connection-definition class-name=”ManagedConnectionFactory” jndi-name=”java:/eisExample/ConnectionFactory” pool-name=”EISExampleConnectionPool”>

 

<pool> <min-pool-size>10</min-pool-size> <max-pool-size>100</max-pool-size> <prefill>true</prefill>

 

</pool> </connection-definition>

 

</connection-definitions> </resource-adapter>

</resource-adapters> </subsystem>

 

By default in WildFly, these pools will not be populated until used for the first time. By setting prefill to true, the pool will be be populated during deployment.

 

Retrieving and using a connection as a developer is easy. Just perform a JNDI lookup for the factory at java:/eisExample/ConnectionFactory and then get a connection from that factory. Other usages that will be running for a long time will not benefit from pooling and will create their connection directly from the RA. An example of this is a Message Driven Bean (MDB) that listens on a RA for messages.

 

The settings for this connection pool can be fetched in runtime by running the following command in the CLI:

 

/subsystem=resource-adapters/resource-adapter=eisExample.rar/connection-definitions=EISExampleConnectionPool:read-resource(include-runtime=true)

 

The response to the preceding command is as follows:

 

{

 

“outcome” => “success”, “result” => {

 

“allocation-retry” => undefined, “allocation-retry-wait-millis” => undefined, “background-validation” => false, “background-validation-millis” => undefined, “blocking-timeout-wait-millis” => undefined, “capacity-decrementer-class” => undefined, “capacity-decrementer-properties” => undefined,

 

“capacity-incrementer-class” => undefined, “capacity-incrementer-properties” => undefined, “class-name” => “ManagedConnectionFactory”, “enabled” => true,

 

“enlistment” => true,

 

“flush-strategy” => “FailingConnectionOnly”, “idle-timeout-minutes” => undefined, “initial-pool-size” => undefined, “interleaving” => false,

 

“jndi-name” => “java:/eisExample/ConnectionFactory”, “max-pool-size” => 100,

 

“min-pool-size” => 10, “no-recovery” => false, “no-tx-separate-pool” => false, “pad-xid” => false, “pool-prefill” => false, “pool-use-strict-min” => false, “recovery-password” => undefined,

 

“recovery-plugin-class-name” => undefined, “recovery-plugin-properties” => undefined, “recovery-security-domain” => undefined, “recovery-username” => undefined, “same-rm-override” => undefined, “security-application” => false, “security-domain” => undefined, “security-domain-and-application” => undefined, “sharable” => true,

 

“use-ccm” => true, “use-fast-fail” => false, “use-java-context” => true, “use-try-lock” => undefined, “wrap-xa-resource” => true,

 

“xa-resource-timeout” => undefined, “config-properties” => undefined

}

 

}

 

Using JMX (URI and result in the JConsole UI):

 

jboss.as:subsystem=resource-adapters, resource-adapter=eisExample.rar, connection-definitions=EISExampleConnectionPool

 

An example connection pool for a RA is shown in the following screenshot:

 

                                                                An example connection pool for an RA

Besides the connection pool, the JCA subsystem in WildFly uses two internal thread pools:

 

        short-running-threads

 

        long-running-threads

These thread pools are of the type blocking-bounded-queue-thread-pool and the behavior of this type is described earlier in the Thread pool executor subsystem section.


The following command is an example of a CLI command to change queue-length for the short-running-threads pool:

 

/subsystem=jca/workmanager=default/short-running-threads=default:write-attribute(name=queue-length, value=100)

 

These pools can all be administered and monitored using both CLI and JMX. The following example and screenshot show the access to the short-running-threads pool:

 

Using CLI, run the following command:

 

/subsystem=jca/workmanager=default/short-running-threads=default:read-resource(include-runtime=true)

 

The response to the preceding command is as follows:

 

{

 

“outcome” => “success”, “result” => {

 

“allow-core-timeout” => false, “core-threads” => 50, “current-thread-count” => 0, “handoff-executor” => undefined, “keepalive-time” => {

 

“time” => 10L, “unit” => “SECONDS”

}

 

“largest-thread-count” => 0, “max-threads” => 50,

 

“name” => “default”, “queue-length” => 50, “queue-size” => 0, “rejected-count” => 0, “thread-factory” => undefined

 

}

 

}

 

Using JMX (URI and result in the JConsole UI):

 

jboss.as:subsystem=jca,workmanager=default,short-running-threads=default

 

The JCA thread pool can be seen in the following screenshot:

 

 

 

 

 

 

 

 

 

The JCA thread pool

 

If your application depends heavily on JCA, these pools should be monitored, and perhaps tuned as needed, to provide improved performance.

 

The Batch API subsystem

 

The Batch API is new in JEE 7 and is implemented in WildFly by the Batch subsystem. Internally it uses an unbounded-queue-thread-pool (see the description earlier in this article). If the application uses the Batch API extensively, the pool settings may need adjustment.

 

The configuration can be fetched using the CLI or by JMX. Using CLI, run the following command:

/subsystem=batch/thread-pool=batch:read-resource(include-runtime=true)

 

The response to the preceding command is as follows:

 

{

 

“outcome” => “success”, “result” => {

 

“keepalive-time” => { “time” => 100L,

“unit” => “MILLISECONDS”

 

},

 

“max-threads” => 10, “name” => “batch”,

“thread-factory” => undefined

 

}

 

}

 

Using JMX (URI and result in the JConsole UI):

 

jboss.as:subsystem=batch,thread-pool=batch

 

The Batch API thread pool is shown in the following screenshot:

 

 

 

 

 

 

The Batch API thread pool

 

The Remoting subsystem

 

The Remoting subsystem exposes a connector to allow inbound communications with JNDI, JMX, and the EJB subsystem through multiplexing over the HTTP port (default 8080).

 

What happens is that the web container (the subsystem Undertow in WildFly) uses something called HTTP Upgrade to redirect, for example, EJB3 calls to the Remoting subsystem, if applicable. This new feature in WildFly makes life easier

 

for administrators as all the scattered ports from earlier versions are now narrowed down to two: one for the application (8080) and one for management (9990).

All this is based on Java NIO API and utilizes a framework called XNIO

(http://www.jboss.org/xnio).

 

The XNIO-based implementation uses a bounded-queue-thread-pool

(see the description earlier in this article) with the following attributes:

 

Attribute

Description

 

task-core-threads

This specifies the number of core threads for the Remoting

 

worker task thread pool

 

 

 

task-max-threads

This specifies the maximum number of threads for the

 

Remoting worker task thread pool

 

task-keepalive

This specifies the number of milliseconds to keep noncore

 

Remoting worker task threads alive

 

 

 

task-limit

This specifies the maximum number of Remoting worker

 

tasks to allow before rejecting

 

 

 

 

The settings can be managed using CLI by running the following command:

 

/subsystem=remoting:read-resource(include-runtime=true)

 

The response to the preceding command is as follows:

 

{

 

“outcome” => “success”, “result” => {

 

“worker-read-threads” => 1, “worker-task-core-threads” => 4, “worker-task-keepalive” => 60, “worker-task-limit” => 16384, “worker-task-max-threads” => 8, “worker-write-threads” => 1, “connector” => undefined,

 

“http-connector” => {“http-remoting-connector” => undefined}, “local-outbound-connection” => undefined, “outbound-connection” => undefined, “remote-outbound-connection” => undefined

 

}

 

}

 

The Transactions subsystem

 

The Transaction subsystem has a fail-safe transaction log. It will, by default, store data on disk at ${jboss.server.data.dir}/tx-object-store. For a standalone server instance, this will point to the $WILDFLY_HOME/standalone/data/tx-object-store/ directory. The disk you choose to store your transaction log mustgive high performance and must be reliable. A good choice would be a local RAID, configured to write through cache. Even if remote disk storage is possible, the network overhead can be a performance bottleneck.

 

One way to point out another path for this object storage is to use the following CLI commands specifying an absolute path:

 

/subsystem=transactions:write-attribute(name=object-store-path,value=”/ mount/diskForTx”)

 

reload

 

XA – Two Phase Commit (2PC)

 

The use of XA is somewhat costly and it shouldn’t be used if it isn’t necessary with distributed transaction between two or more resources (often databases, but also such things as JMS). If needed, we strongly recommend using XA instead of

 

trying to build something yourself, such as compensating transactions to guarantee consistency between the resources. Such solutions can very quickly become quite advanced and the result will probably not outperform the XA protocol anyway.

 

Even though WildFly supports Last Resource Commit Optimization (LRCO), it shouldn’t be used for performance optimization. It is only intended as a workaround to provide limited support to use one non-XA resource within an XA transaction.

 

These were the various configurations possible in WildFly.

LEAVE A REPLY

Please enter your comment!
Please enter your name here