158 lines
11 KiB
XML
158 lines
11 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
||
<!-- ============================================================================= -->
|
||
<!-- Copyright © 2009 Red Hat, Inc. and others. -->
|
||
<!-- -->
|
||
<!-- The text of and illustrations in this document are licensed by Red Hat under -->
|
||
<!-- a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). -->
|
||
<!-- -->
|
||
<!-- An explanation of CC-BY-SA is available at -->
|
||
<!-- -->
|
||
<!-- http://creativecommons.org/licenses/by-sa/3.0/. -->
|
||
<!-- -->
|
||
<!-- In accordance with CC-BY-SA, if you distribute this document or an adaptation -->
|
||
<!-- of it, you must provide the URL for the original version. -->
|
||
<!-- -->
|
||
<!-- Red Hat, as the licensor of this document, waives the right to enforce, -->
|
||
<!-- and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent -->
|
||
<!-- permitted by applicable law. -->
|
||
<!-- ============================================================================= -->
|
||
|
||
<!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 "HornetQ_User_Manual.ent">
|
||
%BOOK_ENTITIES;
|
||
]>
|
||
<chapter id="thread-pooling">
|
||
<title>Thread management</title>
|
||
<para>This chapter describes how HornetQ 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 HornetQ 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. HornetQ 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), HornetQ 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
|
||
>hornetq-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
|
||
>hornetq-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
|
||
HornetQ-AIO-poller-pool. HornetQ 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 HornetQ-AIO-writer-pool.</para>
|
||
</section>
|
||
</section>
|
||
<section id="thread-pooling.client.side">
|
||
<title>Client-Side Thread Management</title>
|
||
<para>On the client side, HornetQ 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 HornetQ 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 = HornetQClient.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 = HornetQJMSClient.createConnectionFactory(myFactory);</programlisting>
|
||
<para>If you're using JNDI to instantiate <literal>HornetQConnectionFactory</literal>
|
||
instances, you can also set these parameters in the <literal>hornetq-jms.xml</literal>
|
||
file where you describe your connection factory, for example:</para>
|
||
<programlisting>
|
||
<connection-factory name="ConnectionFactory">
|
||
<connectors>
|
||
<connector-ref connector-name="netty"/>
|
||
</connectors>
|
||
<entries>
|
||
<entry name="ConnectionFactory"/>
|
||
<entry name="XAConnectionFactory"/>
|
||
</entries>
|
||
<use-global-pools>false</use-global-pools>
|
||
<scheduled-thread-pool-max-size>10</scheduled-thread-pool-max-size>
|
||
<thread-pool-max-size>-1</thread-pool-max-size>
|
||
</connection-factory></programlisting>
|
||
</section>
|
||
</chapter>
|