activemq-artemis/docs/user-manual/en/thread-pooling.xml

157 lines
11 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<!-- ============================================================================= -->
<!-- Licensed to the Apache Software Foundation (ASF) under one or more -->
<!-- contributor license agreements. See the NOTICE file distributed with -->
<!-- this work for additional information regarding copyright ownership. -->
<!-- The ASF licenses this file to You under the Apache License, Version 2.0 -->
<!-- (the "License"); you may not use this file except in compliance with -->
<!-- the License. You may obtain a copy of the License at -->
<!-- -->
<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
<!-- -->
<!-- Unless required by applicable law or agreed to in writing, software -->
<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -->
<!-- See the License for the specific language governing permissions and -->
<!-- limitations under the License. -->
<!-- ============================================================================= -->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "ActiveMQ_User_Manual.ent">
%BOOK_ENTITIES;
]>
<chapter id="thread-pooling">
<title>Thread management</title>
<para>This chapter describes how ActiveMQ uses and pools threads and how you can manage
them.</para>
<para>First we'll discuss how threads are managed and used on the server side, then we'll look
at the client side.</para>
<section>
<title>Server-Side Thread Management</title>
<para>Each ActiveMQ Server maintains a single thread pool for general use, and a scheduled
thread pool for scheduled use. A Java scheduled thread pool cannot be configured to use
a standard thread pool, otherwise we could use a single thread pool for both scheduled
and non scheduled activity.</para>
<para>A separate thread pool is also used to service connections. ActiveMQ can use "old"
(blocking) IO or "new" (non-blocking) IO also called NIO. Both of these options use
a separate thread pool, but each of them behaves uniquely.</para>
<para>Since old IO requires a thread per connection its thread pool is unbounded. The thread
pool is created via <literal>
java.util.concurrent.Executors.newCachedThreadPool(ThreadFactory)</literal>. As the
JavaDoc for this method states:
<quote>Creates a thread pool that creates new threads as needed, but will reuse previously
constructed threads when they are available, and uses the provided ThreadFactory to create
new threads when needed.</quote>
Threads from this pool which are idle for more than 60 seconds will time out and be
removed. If old IO connections were serviced from the standard pool the pool would
easily get exhausted if too many connections were made, resulting in the server "hanging"
since it has no remaining threads to do anything else. However, even an unbounded thread
pool can run into trouble if it becomes too large. If you require the server to handle
many concurrent connections you should use NIO, not old IO.</para>
<para>When using new IO (NIO), ActiveMQ will, by default, cap its thread pool at three times
the number of cores (or hyper-threads) as reported by <literal>
Runtime.getRuntime().availableProcessors()</literal> for processing incoming packets.
To override this value, you can set the number of threads by specifying the parameter
<literal>nio-remoting-threads</literal> in the transport configuration. See the
<xref linkend="configuring-transports"/> for more information on this.</para>
<para>There are also a small number of other places where threads are used directly, we'll
discuss each in turn.</para>
<section id="server.scheduled.thread.pool">
<title>Server Scheduled Thread Pool</title>
<para>The server scheduled thread pool is used for most activities on the server side
that require running periodically or with delays. It maps internally to a <literal
>java.util.concurrent.ScheduledThreadPoolExecutor</literal> instance.</para>
<para>The maximum number of thread used by this pool is configure in <literal
>activemq-configuration.xml</literal> with the <literal
>scheduled-thread-pool-max-size</literal> parameter. The default value is
<literal>5</literal> threads. A small number of threads is usually sufficient
for this pool.</para>
</section>
<section>
<title>General Purpose Server Thread Pool</title>
<para>This general purpose thread pool is used for most asynchronous actions on the
server side. It maps internally to a <literal
>java.util.concurrent.ThreadPoolExecutor</literal> instance.</para>
<para>The maximum number of thread used by this pool is configure in <literal
>activemq-configuration.xml</literal> with the <literal
>thread-pool-max-size</literal> parameter.</para>
<para>If a value of <literal>-1</literal> is used this signifies that the thread pool
has no upper bound and new threads will be created on demand if there are not enough
threads available to satisfy a request. If activity later subsides then threads are
timed-out and closed.</para>
<para>If a value of <literal>n</literal> where <literal>n</literal>is a positive integer
greater than zero is used this signifies that the thread pool is bounded. If more
requests come in and there are no free threads in the pool and the pool is full then
requests will block until a thread becomes available. It is recommended that a
bounded thread pool is used with caution since it can lead to dead-lock situations
if the upper bound is chosen to be too low.</para>
<para>The default value for <literal>thread-pool-max-size</literal> is <literal
>30</literal>.</para>
<para>See the <ulink
url="http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.htm"
>J2SE javadoc</ulink> for more information on unbounded (cached), and bounded
(fixed) thread pools.</para>
</section>
<section>
<title>Expiry Reaper Thread</title>
<para>A single thread is also used on the server side to scan for expired messages in
queues. We cannot use either of the thread pools for this since this thread needs to
run at its own configurable priority.</para>
<para>For more information on configuring the reaper, please see <xref
linkend="message-expiry"/>.</para>
</section>
<section>
<title>Asynchronous IO</title>
<para>Asynchronous IO has a thread pool for receiving and dispatching events out of the
native layer. You will find it on a thread dump with the prefix
ActiveMQ-AIO-poller-pool. ActiveMQ uses one thread per opened file on the journal
(there is usually one).</para>
<para>There is also a single thread used to invoke writes on libaio. We do that to avoid
context switching on libaio that would cause performance issues. You will find this
thread on a thread dump with the prefix ActiveMQ-AIO-writer-pool.</para>
</section>
</section>
<section id="thread-pooling.client.side">
<title>Client-Side Thread Management</title>
<para>On the client side, ActiveMQ maintains a single static scheduled thread pool and a
single static general thread pool for use by all clients using the same classloader in
that JVM instance.</para>
<para>The static scheduled thread pool has a maximum size of <literal>5</literal> threads,
and the general purpose thread pool has an unbounded maximum size.</para>
<para>If required ActiveMQ can also be configured so that each <literal
>ClientSessionFactory</literal> instance does not use these static pools but instead
maintains its own scheduled and general purpose pool. Any sessions created from that
<literal>ClientSessionFactory</literal> will use those pools instead.</para>
<para>To configure a <literal>ClientSessionFactory</literal> instance to use its own pools,
simply use the appropriate setter methods immediately after creation, for
example:</para>
<programlisting>
ServerLocator locator = ActiveMQClient.createServerLocatorWithoutHA(...)
ClientSessionFactory myFactory = locator.createClientSessionFactory();
myFactory.setUseGlobalPools(false);
myFactory.setScheduledThreadPoolMaxSize(10);
myFactory.setThreadPoolMaxSize(-1); </programlisting>
<para>If you're using the JMS API, you can set the same parameters on the
ClientSessionFactory and use it to create the <literal>ConnectionFactory</literal>
instance, for example:</para>
<programlisting>
ConnectionFactory myConnectionFactory = ActiveMQJMSClient.createConnectionFactory(myFactory);</programlisting>
<para>If you're using JNDI to instantiate <literal>ActiveMQConnectionFactory</literal>
instances, you can also set these parameters in the <literal>activemq-jms.xml</literal>
file where you describe your connection factory, for example:</para>
<programlisting>
&lt;connection-factory name="ConnectionFactory">
&lt;connectors>
&lt;connector-ref connector-name="netty"/>
&lt;/connectors>
&lt;entries>
&lt;entry name="ConnectionFactory"/>
&lt;entry name="XAConnectionFactory"/>
&lt;/entries>
&lt;use-global-pools>false&lt;/use-global-pools>
&lt;scheduled-thread-pool-max-size>10&lt;/scheduled-thread-pool-max-size>
&lt;thread-pool-max-size>-1&lt;/thread-pool-max-size>
&lt;/connection-factory></programlisting>
</section>
</chapter>