mirror of
https://github.com/apache/activemq-artemis.git
synced 2025-02-08 19:15:08 +00:00
204 lines
12 KiB
XML
204 lines
12 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="connection-ttl">
|
|||
|
<title>Detecting Dead Connections</title>
|
|||
|
<para>In this section we will discuss connection time-to-live (TTL) and explain how HornetQ
|
|||
|
deals with crashed clients and clients which have exited without cleanly closing their
|
|||
|
resources.</para>
|
|||
|
<section id="dead.connections">
|
|||
|
<title>Cleaning up Dead Connection Resources on the Server</title>
|
|||
|
<para>Before a HornetQ client application exits it is considered good practice that it
|
|||
|
should close its resources in a controlled manner, using a <literal>finally</literal>
|
|||
|
block.</para>
|
|||
|
<para>Here's an example of a well behaved core client application closing its session and
|
|||
|
session factory in a finally block:</para>
|
|||
|
<programlisting>
|
|||
|
ServerLocator locator = null;
|
|||
|
ClientSessionFactory sf = null;
|
|||
|
ClientSession session = null;
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
locator = HornetQClient.createServerLocatorWithoutHA(..);
|
|||
|
|
|||
|
sf = locator.createClientSessionFactory();;
|
|||
|
|
|||
|
session = sf.createSession(...);
|
|||
|
|
|||
|
... do some stuff with the session...
|
|||
|
}
|
|||
|
finally
|
|||
|
{
|
|||
|
if (session != null)
|
|||
|
{
|
|||
|
session.close();
|
|||
|
}
|
|||
|
|
|||
|
if (sf != null)
|
|||
|
{
|
|||
|
sf.close();
|
|||
|
}
|
|||
|
|
|||
|
if(locator != null)
|
|||
|
{
|
|||
|
locator.close();
|
|||
|
}
|
|||
|
}</programlisting>
|
|||
|
<para>And here's an example of a well behaved JMS client application:</para>
|
|||
|
<programlisting>
|
|||
|
Connection jmsConnection = null;
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
ConnectionFactory jmsConnectionFactory = HornetQJMSClient.createConnectionFactoryWithoutHA(...);
|
|||
|
|
|||
|
jmsConnection = jmsConnectionFactory.createConnection();
|
|||
|
|
|||
|
... do some stuff with the connection...
|
|||
|
}
|
|||
|
finally
|
|||
|
{
|
|||
|
if (connection != null)
|
|||
|
{
|
|||
|
connection.close();
|
|||
|
}
|
|||
|
}</programlisting>
|
|||
|
<para>Unfortunately users don't always write well behaved applications, and sometimes
|
|||
|
clients just crash so they don't have a chance to clean up their resources!</para>
|
|||
|
<para>If this occurs then it can leave server side resources, like sessions, hanging on the
|
|||
|
server. If these were not removed they would cause a resource leak on the server and
|
|||
|
over time this result in the server running out of memory or other resources.</para>
|
|||
|
<para>We have to balance the requirement for cleaning up dead client resources with the fact
|
|||
|
that sometimes the network between the client and the server can fail and then come
|
|||
|
back, allowing the client to reconnect. HornetQ supports client reconnection, so we
|
|||
|
don't want to clean up "dead" server side resources too soon or this will prevent any
|
|||
|
client from reconnecting, as it won't be able to find its old sessions on the
|
|||
|
server.</para>
|
|||
|
<para>HornetQ makes all of this configurable. For each <literal
|
|||
|
>ClientSessionFactory</literal> we define a <emphasis>connection TTL</emphasis>.
|
|||
|
Basically, the TTL determines how long the server will keep a connection alive in the
|
|||
|
absence of any data arriving from the client. The client will automatically send "ping"
|
|||
|
packets periodically to prevent the server from closing it down. If the server doesn't
|
|||
|
receive any packets on a connection for the connection TTL time, then it will
|
|||
|
automatically close all the sessions on the server that relate to that
|
|||
|
connection.</para>
|
|||
|
<para>If you're using JMS, the connection TTL is defined by the <literal
|
|||
|
>ConnectionTTL</literal> attribute on a <literal>HornetQConnectionFactory</literal>
|
|||
|
instance, or if you're deploying JMS connection factory instances direct into JNDI on
|
|||
|
the server side, you can specify it in the xml config, using the parameter <literal
|
|||
|
>connection-ttl</literal>.</para>
|
|||
|
<para>The default value for connection ttl on an "unreliable" connection (e.g. a Netty
|
|||
|
connection) is <literal>60000</literal>ms, i.e. 1 minute. The default value for connection
|
|||
|
ttl on a "reliable" connection (e.g. an in-vm connection) is <literal>-1</literal>. A
|
|||
|
value of <literal>-1</literal> for <literal>ConnectionTTL</literal> means the server
|
|||
|
will never time out the connection on the server side.</para>
|
|||
|
<para id="connection-ttl.override">If you do not wish clients to be able to specify their own connection TTL, you can
|
|||
|
override all values used by a global value set on the server side. This can be done by
|
|||
|
specifying the <literal>connection-ttl-override</literal> attribute in the server side
|
|||
|
configuration. The default value for <literal>connection-ttl-override</literal> is
|
|||
|
<literal>-1</literal> which means "do not override" (i.e. let clients use their own
|
|||
|
values).</para>
|
|||
|
<section>
|
|||
|
<title>Closing core sessions or JMS connections that you have failed to close</title>
|
|||
|
<para>As previously discussed, it's important that all core client sessions and JMS
|
|||
|
connections are always closed explicitly in a <literal>finally</literal> block when
|
|||
|
you are finished using them. </para>
|
|||
|
<para>If you fail to do so, HornetQ will detect this at garbage collection time, and log
|
|||
|
a warning similar to the following in the logs (If you are using JMS the warning
|
|||
|
will involve a JMS connection not a client session):</para>
|
|||
|
<programlisting>
|
|||
|
[Finalizer] 20:14:43,244 WARNING [org.hornetq.core.client.impl.DelegatingSession] I'm closing a ClientSession you left open. Please make sure you close all ClientSessions explicitly before let
|
|||
|
ting them go out of scope!
|
|||
|
[Finalizer] 20:14:43,244 WARNING [org.hornetq.core.client.impl.DelegatingSession] The session you didn't close was created here:
|
|||
|
java.lang.Exception
|
|||
|
at org.hornetq.core.client.impl.DelegatingSession.<init>(DelegatingSession.java:83)
|
|||
|
at org.acme.yourproject.YourClass (YourClass.java:666)</programlisting>
|
|||
|
<para>HornetQ will then close the connection / client session for you.</para>
|
|||
|
<para>Note that the log will also tell you the exact line of your user code where you
|
|||
|
created the JMS connection / client session that you later did not close. This will
|
|||
|
enable you to pinpoint the error in your code and correct it appropriately.</para>
|
|||
|
</section>
|
|||
|
</section>
|
|||
|
<section>
|
|||
|
<title>Detecting failure from the client side.</title>
|
|||
|
<para>In the previous section we discussed how the client sends pings to the server and how
|
|||
|
"dead" connection resources are cleaned up by the server. There's also another reason
|
|||
|
for pinging, and that's for the <emphasis>client</emphasis> to be able to detect that
|
|||
|
the server or network has failed.</para>
|
|||
|
<para>As long as the client is receiving data from the server it will consider the
|
|||
|
connection to be still alive. </para>
|
|||
|
<para>If the client does not receive any packets for <literal
|
|||
|
>client-failure-check-period</literal> milliseconds then it will consider the
|
|||
|
connection failed and will either initiate failover, or call any <literal
|
|||
|
>FailureListener</literal> instances (or <literal>ExceptionListener</literal>
|
|||
|
instances if you are using JMS) depending on how it has been configured.</para>
|
|||
|
<para>If you're using JMS it's defined by the <literal>ClientFailureCheckPeriod</literal>
|
|||
|
attribute on a <literal>HornetQConnectionFactory</literal> instance, or if you're
|
|||
|
deploying JMS connection factory instances direct into JNDI on the server side, you can
|
|||
|
specify it in the <literal>hornetq-jms.xml </literal> configuration file, using the
|
|||
|
parameter <literal>client-failure-check-period</literal>.</para>
|
|||
|
<para>The default value for client failure check period on an "unreliable" connection (e.g.
|
|||
|
a Netty connection) is <literal>30000</literal>ms, i.e. 30 seconds. The default value
|
|||
|
for client failure check period on a "reliable" connection (e.g. an in-vm connection)
|
|||
|
is <literal>-1</literal>. A value of <literal>-1</literal> means the client will never fail the
|
|||
|
connection on the client side if no data is received from the server. Typically this is
|
|||
|
much lower than connection TTL to allow clients to reconnect in case of transitory
|
|||
|
failure.</para>
|
|||
|
</section>
|
|||
|
<section id="connection-ttl.async-connection-execution">
|
|||
|
<title>Configuring Asynchronous Connection Execution</title>
|
|||
|
<para>Most packets received on the server side are executed on the remoting thread. These packets
|
|||
|
represent short-running operations and are always executed on the remoting thread for
|
|||
|
performance reasons.</para>
|
|||
|
<para>However, by default some kinds of packets are executed using a thread from a
|
|||
|
thread pool so that the remoting thread is not tied up for too long. Please note that
|
|||
|
processing operations asynchronously on another thread adds a little more latency. These packets
|
|||
|
are:</para>
|
|||
|
<itemizedlist>
|
|||
|
<listitem>
|
|||
|
<para><literal>org.hornetq.core.protocol.core.impl.wireformat.RollbackMessage</literal></para>
|
|||
|
</listitem>
|
|||
|
<listitem>
|
|||
|
<para><literal>org.hornetq.core.protocol.core.impl.wireformat.SessionCloseMessage</literal></para>
|
|||
|
</listitem>
|
|||
|
<listitem>
|
|||
|
<para><literal>org.hornetq.core.protocol.core.impl.wireformat.SessionCommitMessage</literal></para>
|
|||
|
</listitem>
|
|||
|
<listitem>
|
|||
|
<para><literal>org.hornetq.core.protocol.core.impl.wireformat.SessionXACommitMessage</literal></para>
|
|||
|
</listitem>
|
|||
|
<listitem>
|
|||
|
<para><literal>org.hornetq.core.protocol.core.impl.wireformat.SessionXAPrepareMessage</literal></para>
|
|||
|
</listitem>
|
|||
|
<listitem>
|
|||
|
<para><literal>org.hornetq.core.protocol.core.impl.wireformat.SessionXARollbackMessage</literal></para>
|
|||
|
</listitem>
|
|||
|
</itemizedlist>
|
|||
|
<para>To disable asynchronous connection execution, set the parameter
|
|||
|
<literal>async-connection-execution-enabled</literal> in
|
|||
|
<literal>hornetq-configuration.xml</literal> to <literal>false</literal> (default value is
|
|||
|
<literal>true</literal>).</para>
|
|||
|
</section>
|
|||
|
</chapter>
|