13.1 ActiveMQ通用调优技术
13.1 General techniques |
13.1 ActiveMQ通用调优技术 |
||||||||||||||||||||||||||||||
You can do two simple things to improve JMS messaging performance: use nonpersistentmessaging, or if you really need guaranteed messaging, then use transactions tobatch up large groups of messages. Usually nonpersistent message delivery isn’t a considerationunless you don’t care that a message will be lost (for example, in real-timedata feeds, since the status will be sent repeatedly within such a short period of time),and batching messages in transactions won’t always be applicable. But ActiveMQ incorporatesfailsafes for reliable delivery of nonpersistent messages so that only catastrophicfailure would result in message loss. In this section we’ll explain why nonpersistentmessage delivery and batching messages are faster, and why they could beapplicable to use in your application if you don’t need to absolutely guarantee thatmessages will never be lost. | 有两种简单方式可以提升JMS消息性能:使用非持久化消息,或者在需要确保消息发送成功时使用事务来将消息分批组合.通常不考虑使用非持久化消息分发除非你不在乎消息可能会丢失(比如,一个实时的数据源,因为状态数据在很短的时间内会重复发送),并且使用事务将消息分批也不总是可行的.但是ActiveMQ为非持久化的消息分发采用了失效安全策略,因此只有灾难性的失败才会导致消息丢失.本节中我们将解释为什么非持久化消息和消息分批会更快,以及为什么在不需要绝对保证消息不会丢失的情况下,可以将它们可应用在你的程序中. | ||||||||||||||||||||||||||||||
13.1.1 Persistent versus nonpersistent messages |
13.1.1 持久化消息 VS 非持久化消息 |
||||||||||||||||||||||||||||||
The JMS specification allows for two message delivery modes: persistent and nonpersistentdelivery. The default delivery mode is persistent. When a producer sends a messageto the broker that’s marked as persistent, the message broker will always persist itto its message store before dispatching it to a consumer. This is to guard against catastrophicfailure, or for later delivery to consumers who might not yet be active. | JMS规范允许两种消息分发模式:持久化分发和非持久化分发.默认的分发模式是持久化分发.当消息生产者发送具有持久化标识的消息到代理时,消息代理将持久化消息到消息存储中然后在发送消息给消费者.这样是为了应对在灾难性失败或者在稍后时间再发送消息给目前尚未激活的消息消费者. | ||||||||||||||||||||||||||||||
If you’re using nonpersistent delivery, then the JMS specification allows themessaging provider to make best efforts to deliver the message to currentlyactive message consumers. ActiveMQ provides additional reliability here, whichis covered later in this section. Nonpersistent messages are significantlyfaster than persistent messages— there are two reasons for this:
? Messages are sent asynchronously from the message producer, so the producerdoesn’t have to wait for a receipt from the broker. This is shown in figure13.1. |
如果你正在使用非持久化消息分发,则JMS允许消息服务提供者使用最大的效率发送消息给当前活动的消息消费者.ActiveMQ对于非持久化消息分发还提供了额外的可靠性保证,本节稍后就此展开介绍.非持久化消息明显比持久化消息快,主要因为下面两点: (1) 消息生产者通过异步方式发送消息,所以生产者无需等待代理的回执.如图13.1所示. (2) 持久化消息保存到消息存储(通常需要写磁盘数据)比在网络中传输消息要慢. |
||||||||||||||||||||||||||||||
The main reason for using persistence is to negate message loss in the case of a systemoutage. But as we saw in chapter 12, ActiveMQ can be configured to prevent this byconfiguring the failover transport to cache asynchronous messages to resend again ona transport failure (using the trackMessages failover transport property). ActiveMQalso prevents duplicate messages by using message auditing at both the client and theActiveMQ broker. So for usage scenarios where only reliability is required (as opposedto guaranteed message delivery), a nonpersistent delivery mode can meet your needs. | 使用持久化消息的一个主要理由是在系统崩溃时防止消息丢失.但是正如12章中所述,可以配置ActiveMQ代理的失效转移协议来缓存异步消息,并且在传输连接器失效时重新发送消息(使用失效转移协议的trackMessages属性).同样,ActiveMQ还可以通过客户端或代理端的消息审计以防止消息重复发送.因此,对于各种仅需保证可靠性的应用场景(相对于确保消息能成功送达的场景)来说使用非持久化消息分发模式即可满足你的需求. | ||||||||||||||||||||||||||||||
As by default the message delivery mode is persistent, you have to explicitly set thedelivery mode on the MessageProducer to send nonpersistent messages as can be seenin the following listing. Listing 13.1 Persistent message delivery |
因为默认情况下消息分发模式是持久化的,你需要在MessageProducer中明确制定以非持久化方式发送消息,如下代码所示: 代码清单13.1 非持久化消息分发 |
||||||||||||||||||||||||||||||
MessageProducer producer = session.createProducer(topic); producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); |
|||||||||||||||||||||||||||||||
We’ve seen why there’s such a big performance difference between persistent andnonpersistent delivery of messages, and the steps that ActiveMQ takes to improve reliabilityof nonpersistent messages. The benefit of reliable message delivery allows nonpersistentmessages to be used in many more cases than would be typical of a JMSprovider. | 我们已经看到为何使用用持久化消息分发和非持久化消息分发会有那么大的性能差异,并且了解了ActiveMQ为改善非持久化消息分发的可靠性而采取的措施.保证消息分发可靠性的好处是允许非持久化消息不仅可用于典型的JSM提供者,而且可以用于更多其他场景中. | ||||||||||||||||||||||||||||||
Having covered nonpersistent messages, let’s move on to the second generalizedtechnique for improving performance of delivering messages in your application—batching messages together. The easiest way to batch messages is to use transactionboundaries, which are explained next. | 了解了非持久化消息之后,让我把目光转向程序中可用的第二种通用的消息分发调优技术–消息分批.使用消息分批最简单的方式是使用事务边界,这将在下一节中介绍. | ||||||||||||||||||||||||||||||
13.1.2 Transactions |
13.1.2 事务 |
||||||||||||||||||||||||||||||
When you send messages using a transaction, only the transaction boundary (theSession.commit() method) results in synchronous communication with the messagebroker. So it’s possible to batch up the production and/or the consumption of messagesto improve performance of sending persistent messages. An example of this isshown next. Listing 13.2 Transacted and nontransacted example |
当发送消息使用了事务时,只有在事务的边界处(即,Session.commit()方法)会导致与消息代理的同步通信.因此,可以通过批量化的消息生产和消息消费来改善发送持久化消息的性能.下面是相关的代码示例: 代码清单13.2 事务化和非事务化示例: |
||||||||||||||||||||||||||||||
public void sendTransacted() throws JMSException { ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(); Connection connection = cf.createConnection(); connection.start(); Session session = connection.createSession(true, Session.SESSION_TRANSACTED); Topic topic = session.createTopic("Test.Transactions"); MessageProducer producer = session.createProducer(topic); int count =0; for (int i =0; i < 1000; i++) { Message message = session.createTextMessage("message " + i); producer.send(message); if (i!=0 && i%10==0) { session.commit(); } } } public void sendNonTransacted() throws JMSException { ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(); Connection connection = cf.createConnection(); connection.start(); //create a default session (no transactions) Session session = connection.createSession(false, Session.AUTO_ACKNOWELDGE); Topic topic = session.createTopic("Test.Transactions"); MessageProducer producer = session.createProducer(topic); int count =0; for (int i =0; i < 1000; i++) { Message message = session.createTextMessage("message " + i); producer.send(message); } } |
|||||||||||||||||||||||||||||||
So we’ve covered some of the easy pickings in terms of performance, use of nonpersistentmessaging where possible, and now use of transaction boundaries for persistentmessages if it makes sense for your application. | 至此我们已经了解了性能调优的几个简单方式:如果可行的化使用非持久化消息,以及上面介绍的,在合适的情况下,在应用程序中使用事务边界发送持久化消息. | ||||||||||||||||||||||||||||||
We’re now going to start (slowly) delving into some ActiveMQ specifics fortechniques that can aid performance. The first is to use an embedded broker.Embedded brokers cut down on the amount of serialization and network trafficthat ActiveMQ uses, as messages can be passed around in the same JVM. | 下面我们将(逐步地)介绍一些ActiveMQ特有的调优技术以便改善性能.首先可以使用嵌入式代理.嵌入式代理减少了ActiveMQ网络传输中需要序列化的数量,以至于消息看起来就相当于在同一个JVM中传输的. | ||||||||||||||||||||||||||||||
13.1.3 Embedding brokers |
13.1.3嵌入式代理 |
||||||||||||||||||||||||||||||
It’s often a requirement to co-locate applications with a broker, so that any servicethat’s dependent on a message broker will only be available at the same time as themessage broker, as shown in figure 13.2. Creating an embedded broker is straightforward,but one of the advantages of using the VM transport is that messages deliveredthrough a broker don’t incur the cost of being serialized on the wire to be transportedacross the network, making it ideal for applications that need to service lots ofresponses quickly. | 通常有的需求要求应用程序和代理在同一位置(译注:虚拟机)部署,因此所有依赖消息代理的服务只有在消息代理可用的时候才可用,如图13.2所示.创建一个嵌入式代理相当容易,并且使用虚拟机传输连接器的一个优势是通过嵌入式代理分发的消息不会因网络传输要求的序列化而产生性能损耗,这就使得嵌入式代理成为那些要求能对大量服务做出快速响应的程序的理想选择. | ||||||||||||||||||||||||||||||
You can create an embedded broker with a transport connector to listen to TCPconnections but still connect to it using the VM transport. By default, a brokeralways listens for transport connections on vm://<broker name>. The followinglisting is an example of setting up a service using an embedded broker to listenfor requests on a queue named service.queue. Listing 13.3 Creating a queue service |
你可以使用一个监听TCP连接的传输连接器来创建一个嵌入式代理,并且依然可以使用VM传输连接器来连接到这个代理.默认情况下,所有代理都监听使用vm://<broker name>的传输连接.下面的示例代码是一个示例,该示例中设置了一个使用嵌入式代理监听一个名称为service.queue的队列请求的服务. 代码清单13.3 创建一个队列服务 |
||||||||||||||||||||||||||||||
BrokerService broker = new BrokerService(); broker.setBrokerName("service"); broker.setPersistent(false); broker.addConnector("tcp://localhost:61616"); broker.start(); ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://service"); cf.setCopyMessageOnSend(false); Connection connection = cf.createConnection(); connection.start(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); final MessageProducer producer = session.createProducer(null); Queue queue = session.createQueue("service.queue"); MessageConsumer consumer = session.createConsumer(queue); consumer.setMessageListener( new MessageListener() { public void onMessage(Message msg) { try { TextMessage textMsg = (TextMessage)msg; String payload = "REPLY: " + textMsg.getText(); Destination replyTo = msg.getJMSReplyTo(); textMsg.clearBody(); textMsg.setText(payload); producer.send(replyTo, textMsg); } catch (JMSException e) { e.printStackTrace(); } } }); |
|||||||||||||||||||||||||||||||
You can test out this service with a javax.jms.QueueRequestor that connects to theservice’s embedded broker via the TCP transport connector, as shown in the followinglisting. Listing 13.4 Connecting a QueueRequestor |
你可以使用一个javax.jms.QueueRequestor使用TCP传输连接器来连接到上述嵌入式代理提供的服务,如下代码所示: 代码清单13.4 连接QueueRequestor |
||||||||||||||||||||||||||||||
ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("tcp://localhost:61616"); QueueConnection connection = cf.createQueueConnection(); connection.start(); QueueSession session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); Queue queue = session.createQueue("service.queue"); QueueRequestor requestor = new QueueRequestor(session,queue); for(int i =0; i < 10; i++) { TextMessage msg = session.createTextMessage("test msg: " + i); TextMessage result = (TextMessage)requestor.request(msg); System.err.println("Result = " + result.getText()); } |
|||||||||||||||||||||||||||||||
As an aside, ActiveMQ by default will always copy the real message sent by a messageproducer to insulate the producer from changes to the message as it passes throughthe broker and is consumed by the consumer, all in the same Java Virtual Machine. Ifyou intend to never reuse the sent message, you can reduce the overhead of this copyby setting the copyMessageOnSend property on the ActiveMQConnectionFactory tofalse, as shown next. Listing 13.5 Using the setCopyMessageOnSend method |
默认情况下,ActiveMQ总是复制消息发送者发送的真实消息以隔离消息在通过代理传输时可能发生的改变以及消息被代理处理后发生的改变,消息发送和消息拷贝在同一个Java虚拟机中完成.如果你不打算使用保留发送时状态的原始消息,你可以通过设置ActiveMQConnectionFactory的copyMessageOnSend属性为false来避免消息发送时复制消息的开销,示例代码如下所示: 代码清单13.5 使用setCopyMessageOnSend方法 |
||||||||||||||||||||||||||||||
ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(); cf.setCopyMessageOnSend(false); |
|||||||||||||||||||||||||||||||
We’ve looked at some relatively easy-to-implement techniques to improve messagingperformance. Using an embedded broker co-located with an application is a relativelytrivial change to make. The performance gains and atomicity of the service co-locatedwith its broker can be an attractive architectural change, too. | 我们已经了解了ActiveMQ的一些比较容易实现的提升性能的技术.使用一个和应用程序部署在一起的嵌入式代理是一种很微小的结构变化.获取的性能提升和与代理一起部署的服务的原子性也是这种架构变化有吸引力的原因. | ||||||||||||||||||||||||||||||
Having gone through some of the easier “quick wins,” we’re going to startmoving into some more difficult configuration areas. So the next section willtouch on the OpenWire protocol and list some parameters you can tune to boostthe performance of your messaging applications. These are dependent on both thehardware and the type of network you use. | 在了解一些相对容易的”快赢”优化配置后,我们将开始了解一些更困难的配置.因此,下一节中我们将着眼OpenWire协议,并列出一些可调整参数以便你提高消息程序的性能.这些优化调整依赖硬件和网络类型. | ||||||||||||||||||||||||||||||
13.1.4 Tuning the OpenWire |
13.1.4 优化OpenWire协议 |
||||||||||||||||||||||||||||||
It’s worth covering some of the options available on the OpenWire protocol. TheOpenWire protocol is the binary format used for transporting commands over a transport(such as TCP) to the broker. Commands include messages and message acknowledgements,as well as management and control of the broker. Table 13.1 shows someOpenWire wire format parameters that are relevant to performance. | OpenWire协议的一些选项参数值得关注.OpenWire协议是一些二进制格式规范,传输连接器(例如)使用这种格式的传输命令传输数据到代理.这些命令包含消息相关命令和消息确认相关命令,以及代理相关的管理和控制命令.表13.1展示了一些OpenWire协议与性能调整有关的包装格式参数. | ||||||||||||||||||||||||||||||
Table 13.1 OpenWire tuning parameters
表13.1 OpenWire 调优参数
|
|||||||||||||||||||||||||||||||
You can add these parameters to the URI used to connect to the broker in thefollowing way. The following listing demonstrates disabling tight encoding,using the tightEncodingEnabled parameter. Listing 13.6 Enabling tight encoding on the wire format |
你可以通过下面的方式,将上述参数附加到连接到代理的传输连接器的URI中.下面的示例代码中展示了如何使用tightEncodingEnabled参数禁用紧凑编码(tight encoding). 代码清单13.6 使用wire格式的紧凑编码 |
||||||||||||||||||||||||||||||
String uri = "failover://(tcp://localhost:61616?wireFormat.cacheEnabled=false&wireFormat. tightEncodingEnabled=false)"; ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(url); cf.setAlwaysSyncSend(true); |
|||||||||||||||||||||||||||||||
These parameters are dependent on the type of application, type of machine(s) usedto run the clients and the broker, and type of network used. Unfortunately this isn’t anexact science, so some experimentation is recommended. | 如何配置上述参数取决与应用程序的类型,运行客户端和代理的机器类型,以及使用的网络类型.不幸的是,不是所有的优化配置都有科学依据,因此一些优化经验值得推荐. | ||||||||||||||||||||||||||||||
As we’ve lightly introduced some of the tuning parameters available on theOpen-Wire protocol, in the next section we’ll look at some of the tuningparameters available on the TCP transport. | 至此,我们已经简要的介绍了一些OpenWire协议的优化参数.下一节中,我们将看到一些TCP传输连接器的优化配置参数. | ||||||||||||||||||||||||||||||
13.1.5 Tuning the TCP transport |
13.1.5 优化TCP传输连接器 |
||||||||||||||||||||||||||||||
The most commonly used transport for ActiveMQ is the TCP transport. Two parametersdirectly affect performance for this transport:
? socketBufferSize—The size of the buffers used to send and receive data overthe TCP transport. Usually the bigger the better (though this is operating systemdependent, so it’s worth testing!). The default value is 65536, which is thesize in bytes. ? tcpNoDelay—The default is false. Normally a TCP socket buffers up smallpieces of data before being sent. When you enable this option, messages will besent as soon as possible. Again, it’s worth testing this out, as whether this boostsperformance can be operating system dependent. |
ActiveMQ中使用最广泛的连接器是TCP传输连接器.有两个直接影响TCP传输连接器的性能,它们是: (1)socketBufferSize–TCP传输连接器用于发送和接收数据的缓冲区大小.通常该参数设置的越大越好(尽管这个最大值收到操作系统限制,但是可以去测试).默认值为65536,单位是byte. (2)tcpNoDelay–默认值为false.通常TCP套接字缓存即将被发送的小尺寸数据包.当启用这个参数时,消息会被尽快发送(译注:不缓冲).同样可以测试这个配置,因为修改这个参数是否能提升性能还和操作系统有关. |
||||||||||||||||||||||||||||||
Here’s an example transport URI where the tcpNoDelay property is enabled: Listing 13.7 Using the tcpNoDelay setting to tune the TCP transport |
下面是一个示例代码,演示了在传输连接器的URI中启用tcpNoDelay参数: 代码清单13.7 启用tcpNoDelay优化TCP传输连接器性能 |
||||||||||||||||||||||||||||||
String url = "failover://(tcp://localhost:61616?tcpNoDelay=true)"; ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(url); cf.setAlwaysSyncSend(true); |
|||||||||||||||||||||||||||||||
We’ve covered some general techniques to improve performance at the applicationlevel, and looked at tuning the wire protocol and the TCP transport. In the next twoparts of this chapter, we’ll look at tuning message producers and then message consumers. | 至此,我们已经了解了一些通用的应用程序级别的性能调优技术,并且了解了优化wire协议和TCP协议的相关技术.后面两个章节我们将了解消息生产者和消费者的优化. | ||||||||||||||||||||||||||||||
ActiveMQ is flexible in its configuration, and its producers can be configuredto optimize their message exchanges with the broker, which can boost throughputconsiderably. | ActiveMQ的配置非常灵活,并且其消息生产者可以被配置以优化其与代理之间的消息交换,这种优化可以显著提高吞吐量. |
微信赞赏
支付宝赞赏
本文固定链接: https://www.jack-yin.com/coding/translation/activemq-in-action/1789.html | 边城网事