activemq-artemis/docs/user-manual/zh/perf-tuning.xml

234 lines
17 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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 AttributionShare 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. -->
<!-- ============================================================================= -->
<chapter id="perf-tuning">
<title>性能调优</title>
<para>本章讲述如何优化ActiveMQ的性能</para>
<section>
<title>持久层的优化</title>
<itemizedlist>
<listitem>
<para>将消息日志放到单独的物理卷上。如果与其它数据共享,例如事务管理、数据库或其它日志等,那么就会
增加读写的负担,磁头会在多个不同文件之间频繁地移动,极大地降低性能。我们的日志系统采用的是只
添加的模式,目的就是最大程度減少磁头的移动。如果磁盘被共享,那么这一目的将不能达到。另外如果
你使用分页转存或大消息功能时,你最好分别将它们放到各自的独立卷中。</para>
</listitem>
<listitem>
<para>尽量减少日志文件的数量。<literal>journal-min-files</literal>参数的设置应以满足平均
运行需要为准。如果你发现系统中经常有新的日志文件被创建,这说明持久的数据量很大,你需要适当增加
这个参数的值以使ActiveMQ更多时候是在重用文件而不是创建新文件。</para>
</listitem>
<listitem>
<para>日志文件的大小。日志文件的大小最好要与磁盘的一个柱面的容量对齐。默认值是10MiB它在绝大多数
的系统中能够满足需要。</para>
</listitem>
<listitem>
<para>使用AIO日志。在Linux下尽量使用AIO型的日志。AIO的可扩展性要好于Java的NIO。</para>
</listitem>
<listitem>
<para>优化 <literal>journal-buffer-timeout</literal>。如果增加它的值,吞吐量会增加,但是
延迟也会增加。</para>
</listitem>
<listitem>
<para>如果使用AIO适当增加<literal>journal-max-io</literal>可能会提高性能。如果使用的是NIO
请不要改变这个参数。</para>
</listitem>
</itemizedlist>
</section>
<section>
<title>优化JMS</title>
<para>如果使用JMS接口有以下几个方面可以改进性能。</para>
<itemizedlist>
<listitem>
<para>关闭消息id。如果你不需要这个id<literal>MessageProducer</literal>
<literal>setDisableMessageID()</literal>方法可以关闭它。这可以减少消息的大小并且
省去了创建唯一ID的时间。</para>
</listitem>
<listitem>
<para>关闭消息的时间戳。如果不需要时间戳,用<literal
>MessageProducer</literal><literal
>setDisableMessageTimeStamp()</literal>方法将其关闭。</para>
</listitem>
<listitem>
<para>尽量避免使用<literal>ObjectMessage</literal><literal>ObjectMessage</literal>会带
来额外的开销。<literal>ObjectMessage</literal>使用Java的序列化将它序列化为字节流。在对小的对象
进行序列化会占用大量的空间使传输的数据量加大。另外Java的序列化与其它定制的技术相比要慢。只有在不得
以的情况下才使用它。比如当你在运行时不知道对象的具体类型时可以用ObjectMessage。</para>
</listitem>
<listitem>
<para>避免使用<literal>AUTO_ACKNOWLEDGE</literal><literal>AUTO_ACKNOWLEDGE</literal>
使得每收到一个消息就要向服务器发送一个通知--这样增加的网络传输的负担。如果可能,尽量使用
<literal>DUPS_OK_ACKNOWLEDGE</literal>或者<literal
>CLIENT_ACKNOWLEDGE</literal>。或者使用事务性会话,将通知在提交时批量完成。</para>
</listitem>
<listitem>
<para>避免持久化消息。默认情况下JMS消息是持久的。如果你不需要持久消息则将其设定为非持久。
持久消息都会被写到磁盘中,这给系统带来了明显的负担。</para>
</listitem>
<listitem>
<para>将多个发送或通知放到一个事务中完成。这样ActiveMQ只需要一次网络的往返来发生事务的提交而不是每次发送
或通知就需要一次网络的往返通迅。</para>
</listitem>
</itemizedlist>
</section>
<section>
<title>其它优化</title>
<para>在ActiveMQ中还有其它一些地方可以优化</para>
<itemizedlist>
<listitem>
<para>使用异步发送通知。如果你在非事务条件下发送持久的消息并且要保证在send()返回时持久消息已经到达服
务器,不要使用阻塞式发送的方式,应该使用异步发送通知的方式。参见<xref
linkend="send-guarantees"/>中的说明。</para>
</listitem>
<listitem>
<para>使用预先通知模式。预先通知就是在消息发往客户端<literal>之前</literal>进行通知。它节省了正常
的消息通知所占用的通迅时间。详细的解释请参见
<xref linkend="pre-acknowledge"/></para>
</listitem>
<listitem>
<para>关闭安全。将<literal>activemq-configuration.xml</literal>文件中的<literal>security-enabled</literal>
参数设为<literal>false</literal>以关闭安全。这可以带来一些性能的提高。</para>
</listitem>
<listitem>
<para>关闭持久化。如果不你不需要消息持久化,可以将<literal>activemq-configuration.xml</literal>
文件中的<literal>persistence-enabled</literal>参数设为false来完全关闭持久功能。</para>
</listitem>
<listitem>
<para>采用延迟方式事务同步。将<literal>activemq-configuration.xml</literal>文件中的<literal
>journal-sync-transactional</literal>参数设为<literal>false</literal>可以得到
更好的事务持久化的性能。但是这样做可能会造成在发生故障时事务的丢失。有关详细的说明参见
<xref linkend="send-guarantees"/></para>
</listitem>
<listitem>
<para>采用延迟方式非事务同步。将<literal>activemq-configuration.xml</literal>文件中的<literal
>journal-sync-non-transactional</literal>参数设为<literal>false</literal>可以得到
更好的非事务持久化的性能。但是这样做可能会造成在发生故障时持久消息的丢失。有关详细的说明参见
<xref linkend="send-guarantees"/></para>
</listitem>
<listitem>
<para>采用非阻塞方式发送消息。将文件<literal>hornetq-jms.xml</literal>中的参数
<literal>block-on-non-durable-send</literal>设为<literal>false</literal>
使用JMS和JNDI时或者直接在上进行相应的设置可以使
消息发送时不阻塞等待服务器的响应。参见 <xref linkend="send-guarantees"/></para>
</listitem>
<listitem>
<para>如果你的接收者速度很快你可以增加consumer-window-size。这样实际上就关闭了流控制的功能。</para>
</listitem>
<listitem>
<para>套接字NIO与旧的IO对比。默认情况下ActiveMQ在服务器端使用套接字NIO技术而在客户端则使用旧的阻塞
IO参见传输配置一章<xref linkend="configuring-transports"/>。NIO比旧的阻塞式IO有更
强的可扩展性但是也会带来一些延时。如果你的服务器要同时有数千个连接使用NIO效果比较好。但是如果
连接数并没有这么多你可以配置接收器使用旧的IO还提高性能。</para>
</listitem>
<listitem>
<para>尽量使用核心接口而不用JMS。使用JMS接口会稍微比使用核心接口性能要低些。这是因为所有JMS操作
实际上要转化为核心的操作才能为服务器所处理。在使用核心接口时,尽量使用带有
<literal>SimpleString</literal>类型参数的方法。<literal>SimpleString</literal>
java.lang.String不同它在写入传输层时不需要拷贝。所以你如果在调用中重用<literal
>SimpleString</literal>对象可以避免不必要的拷贝。</para>
</listitem>
</itemizedlist>
</section>
<section>
<title>传输层的优化</title>
<itemizedlist>
<listitem>
<para>TCP缓存大小。如果你的网络速度很快并且你的主机也很快你可以通过增加TCP的发送和接收缓存
来提高性能。参见<xref linkend="configuring-transports"/>中的详细说明。</para>
<note>
<para>注意某些操作系统如最近的Linux版本中包括了TCP自动优化功能。如果再手工设置TCP缓存
会导致自动优化失效,最終使性能下降!
</para>
</note>
</listitem>
<listitem>
<para>增加服务器中文件句柄数量限制。如果你的服务器将要处理很多并行的连接,或者客户端在快速不停地
打开和关闭连接,你要确保在服务器端有足够的文件句柄以供使用。</para>
<para>这个限制在不同平台有不同的方法。在Linux系统中你可以编辑文件<literal
>/etc/security/limits.conf</literal>,增加以下内容:
<programlisting>
serveruser soft nofile 20000
serveruser hard nofile 20000
</programlisting>
它设置了用户<literal>serveruser</literal>可以最多打开20000个文件句柄。</para>
</listitem>
<listitem>
<para>利用参数<literal>batch-delay</literal>并将参数<literal>direct-deliver</literal>
设为false来提高小消息的处理效率。ActiveMQ在其<literal>activemq-configuration.xml</literal>
中预先配置了一个连接器/接受器对(<literal>netty-throughput</literal>),并且在
<literal>hornetq-jms.xml</literal>中配置了一个JMS连接工厂
<literal>ThroughputConnectionFactory</literal>)。它们可以用在小消息的处理应用中以提
供最佳呑吐量。参见<xref
linkend="configuring-transports"/></para>
</listitem>
</itemizedlist>
</section>
<section>
<title>优化虚拟机</title>
<para>我们强烈建议你使用最新的Java 6虚拟机。它在很多方面对以前Java 5的虚拟机进行了改进特别是在网络功能方面。
这是根据我们内部使用Sun的实现测试的結果可能不适用于其它的Java实现例如IBM或JRockit</para>
<itemizedlist>
<listitem>
<para>拉圾回收。为了使服务器的运行比较平滑我们建议使用并行拉圾回收的算法。例如在Sun的JDK使用
JVM选项<literal>-XX:+UseParallelOldGC</literal>.</para>
</listitem>
<listitem id="perf-tuning.memory">
<para>内存设置。尽量为服务器分配更多的内存。ActiveMQ利用其分页转存技术可以在很少的内存下运行
<xref linkend="paging"/>中有说明)。但是如果所有队列都在内存运行,性能将会很好。具体需要
多少内存要由你的队列的大小和数量以及消息的大小和数量决定。使用JVM参数<literal>-Xms</literal>
<literal>-Xmx</literal>来为你的服务器分配内存。我们建议两个参数的设为相同的值。</para>
</listitem>
<listitem>
<para>主动选项Aggressive options。不同JVM有不同的JVM优化参数。对于Sun的Hotspot JVM<ulink
url="http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp"
>这里</ulink>有一个完整的参数列表。我们建议至少要使用 <literal
>-XX:+AggressiveOpts</literal><literal>
-XX:+UseFastAccessorMethods</literal>选项。根据不同的平台,可能还有其它一些参数供你使用,
以提高JVM的性能。</para>
</listitem>
</itemizedlist>
</section>
<section>
<title>避免违背设计模式</title>
<itemizedlist>
<listitem>
<para>重用连接/会话/接收者/发送者。最常见的错误恐怕就是每发送/接收一个消息都要创建一个新的连接
/会话/发送者或接收者。这样非常浪费资源。这些对象的创建要占用时间和网络带宽。它们应该进行重用。</para>
<note>
<para>有些常用的框架如Spring JMS Template在使用JMS时违背了设计模式。如果你在使用了它后性能
受到了影响。这不是ActiveMQ的原因Spring的JMS模板只有与能缓存JMS会话的应用服务器一起使用
才是安全的,并且只能是用于发送消息。使用它在应用服务器中同步接收消息是不安全的。</para>
</note>
</listitem>
<listitem>
<para>避免使用繁锁的消息格式。如XML它会使数据量变大进而降低性能。所以应该尽量避免在消息体中使用XML。</para>
</listitem>
<listitem>
<para>不要为每个请求都创建新的临时队列。临时队列通常用于请求-响应模式的消息应用。在这个模式中消息被发往
一个目的它带有一个reply-to的头属性指向一个本地的临时队列的地址。当消息被收到后接收方将响应做为消息发
往那个reply-to指定的临时的地址。如果每发一个消息都创建一个临时队列那么性能将会受很大影响。正确的
作法是在发送消息时重用临时队列。</para>
</listitem>
<listitem>
<para>尽量不要使用MDB。使用MDB消息的接收过程要比直接接收复杂得多要执行很多应用服务器内部的代码。
在设计应用时要问一下是否真的需要MDB可不可以直接使用消息接收者完成同样的任务</para>
</listitem>
</itemizedlist>
</section>
</chapter>