架構設計:系統間通信(23)——提高ActiveMQ工作性能(中)


(接上文《架構設計:系統間通信(22)——提高ActiveMQ工作性能(上)》)

6、ActiveMQ處理規則和優化

在ActiveMQ單個服務節點的優化中,除了對ActiveMQ單個服務節點的網絡IO模型進行優化外,生產者發送消息的策略和消費者處理消息的策略也關乎整個消息隊列系統是否能夠高效工作。請看下圖所示的消息生產者和消息消費者的簡要工作原理圖:

這里寫圖片描述

  1. Producer既是消息生產者,作為一個發送消息的客戶端它既可以使用同步消息發送模式,也可以使用異步的消息發送模式。另外,消息生產者在ActiveMQ服務節點產生消息堆積的情況下,也不能一味的追求發送效率。還好,這種情況下消息生產者端有完整的保證機制——Slow Producer。另外,JMS提供事務功能,所以生產者是否開啟事務發送消息,將會影響消息發送性能。

  2. 在整個消息處理規則中,ActiveMQ服務節點最極端的情況就是產生消息堆積(消息的消費速度持續低於消息生成速度,就會出現消息堆積)。那么ActiveMQ服務節點處理網絡IO模型的優化外,最大的優化點就是:如何應對消息堆積。基本原則是:NON_PERSISTENT Message在內存堆積后,轉儲到Temp Store區域(當然也可以設置為不轉儲);PERSISTENT Meaage無論怎樣都會先使用持久化方案存儲到永久存儲區域,再視情況決定是否進行發送;在這些區域也產生堆積后,通知消息生產者使用Slow Producer機制

  3. ActiveMQ服務節點在成功完成PERSISTENT Meaage的持久存儲操作后,就會向消息生產者發送一個確認信息,表示該條消息已處理完成。如果ActiveMQ服務節點接受的是NON_PERSISTENT Message,那么生產者默認情況下不會等待服務節點的回執。我們后續會介紹PERSISTENT Meaage的發送也可以設置為不等待回執,這樣可以顯著提高生產端的消息發送效率。

  4. ActiveMQ服務節點會以一種設置好的策略將消息發送給消費者,這個策略的原則是ActiveMQ服務節點主動推送消息給某一個消費者(不是消費者主動拉取),這樣的方式很好便於ActiveMQ服務節點占據整個策略的領導地位。在這個策略中,最重要的屬性是prefetchSize:單次獲得的消息數量。除此以外,消費者端也是可以調整IO網絡模型。

  5. 消費者在獲得到消息后,就可以根據這條消息進行業務處理了。最后,消費者需要按照處理結果向ActiveMQ服務節點告知這條(或這些)消息是否處理成功——ACK應答。ActiveMQ中有多種ACK應答方式,它們對性能的影響也不相同。通過這些描述可以看出,消費者的處理性能更能直接影響整個ActiveMQ系統的性能。因為消費者不僅要接受消息、處理消息還要返回消息應答。所以如果您的業務有一定的復雜性,造成每一條消息的處理都會消耗相當的處理時間,那么最直接的性能改善方式就是采用多個消費者節點

6-1、生產者策略:Send

消息生產者發送的消息主要分為兩種類型:發送PERSISTENT Meaage和發送NON_PERSISTENT Message。

6-1-1、發送NON_PERSISTENT Message

默認情況下,ActiveMQ服務端認為生產者端發送的是PERSISTENT Message。所以如果要發送NON_PERSISTENT Message,那么生產者端就要明確指定。以下語句明確指定消息發送者將要發送NON_PERSISTENT Message:

......
// 設置發送者發送的是NON_PERSISTENT Message
MessageProducer sender = session.createProducer(sendQueue);
sender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
......

發送NON_PERSISTENT Message時,消息發送方默認使用異步方式:即是說消息發送后發送方不會等待NON_PERSISTENT Message在服務端的任何回執。那么問題來了:如果這時服務端已經出現了消息堆積,並且堆積程度已經達到“無法再接收新消息”的極限情況了,那么消息發送方如果知曉並采取相應的策略呢?

實際上所謂的異步發送也並非絕對的異步,消息發送者會在發送一定大小的消息后等待服務端進行回執(這個配置只是針對使用異步方式進行發送消息的情況):

......
// 以下語句設置消息發送者在累計發送102400byte大小的消息后(可能是一條消息也可能是多條消息)
// 等待服務端進行回執,以便確定之前發送的消息是否被正確處理
// 確定服務器端是否產生了過量的消息堆積,需要減慢消息生產端的生產速度
connectionFactory.setProducerWindowSize(102400);
......

如果您使用的是異步發送方式,那么必須通過這個以上代碼指明回執點。例如發送NON_PERSISTENT Message時,這時消息發送者默認使用異步方式。那么如果您想在發送NON_PERSISTENT Message時,每次都等待消息回執,又該如何設置呢?您可以使用connectionFactory提供的“alwaysSyncSend”設置來指定每次都等待服務端的回執:

......
// 設置成:無論怎樣每次都等待服務器端的回執
// 但關鍵是您確定自己的業務需求真的需要這樣使用嗎?
connectionFactory.setAlwaysSyncSend(true);
......

6-1-2、發送PERSISTENT Message

如果您不特意指定消息的發送類型,那么消息生產者默認發送PERSISTENT Meaage。這樣的消息發送到ActiveMQ服務端后將被進行持久化存儲(持久化存儲方案將在后文進行詳細介紹),並且消息發送者默認等待ActiveMQ服務端對這條消息處理情況的回執。

以上這個過程非常耗時,ActiveMQ服務端不但要接受消息,在內存中完成存儲,並且按照ActiveMQ服務端設置的持久化存儲方案對消息進行存儲(主要的處理時間耗費在這里)。為了提高ActiveMQ在接受PERSISTENT Meaage時的性能,ActiveMQ允許開發人員遵從JMS API中的設置方式,為消息發送端在發送PERSISTENT Meaage時提供異步方式:

......
// 使用異步傳輸
// 上文已經說過,如果發送的是NON_PERSISTENT Message
// 那么默認就是異步方式
connectionFactory.setUseAsyncSend(true);
......

一旦您進行了這樣的設置,就需要設置回執窗口:

......
// 同樣設置消息發送者在累計發送102400byte大小的消息后
// 等待服務端進行回執,以便確定之前發送的消息是否被正確處理
// 確定服務器端是否產生了過量的消息堆積,需要減慢消息生產端的生產速度
connectionFactory.setProducerWindowSize(102400);
......

6-2、生產者策略:事務

JMS規范中支持帶事務的消息,也就是說您可以啟動一個事務(並由消息發送者的連接會話設置一個事務號Transaction ID),然后在事務中發送多條消息。這個事務提交前這些消息都不會進入隊列(無論是Queue還是Topic)。

不進入隊列,並不代表JMS不會在事務提交前將消息發送給ActiveMQ服務端。 實際上這些消息都會發送給服務端,服務端發現這是一條帶有Transaction ID的消息,就會將先把這條消息放置在“transaction store”區域中(並且帶有redo日志,這樣保證在收到rollback指令后能進行取消操作),等待這個Transaction ID被rollback或者commit。

一旦這個Transaction ID被commit,ActiveMQ才會依據自身設置的PERSISTENT Meaage處理規則或者NON_PERSISTENT Meaage處理規則,將Transaction ID對應的message進行入隊操作(無論是Queue還是Topic)。以下代碼示例了如何在生產者端使用事務發送消息:

......
//進行連接
connection = connectionFactory.createQueueConnection();
connection.start();

//建立會話(設置一個帶有事務特性的會話)
session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
//建立queue(當然如果有了就不會重復建立)
Queue sendQueue = session.createQueue("/test");
//建立消息發送者對象
MessageProducer sender = session.createProducer(sendQueue);

//發送(JMS是支持事務的)
for(int index = 0 ; index < 10 ; index++) {
TextMessage outMessage = session.createTextMessage();
outMessage.setText("這是發送的消息內容-------------------" + index);
// 無論是NON_PERSISTENT message還是PERSISTENT message
// 都要在commit后才能真正的入隊
if(index % 2 == 0) {
sender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
} else {
sender.setDeliveryMode(DeliveryMode.PERSISTENT);
}

// 沒有commit的消息,也是要先發送給服務端的
sender.send(outMessage);
}

session.commit();
......

以上代碼中,在“connection.createSession”這個方法中一共有兩個參數(這句代碼在上文中已經出現過多次)。第一個布爾型參數很好理解,就是標示這個連接會話是否啟動事務;第二個整型參數標示了消息消費者的“應答模型”,我們會在下文中進行詳細介紹。

6-3、生產者策略:ProducerFlowControl

生產流控制,是ActiveMQ消息生產者端最為重要的性能策略,它主要設定了在ActiveMQ服務節點在產生消息堆積,並超過限制大小的情況下,如何進行消息生產者端的限流。

具體來說,如果以上情況在ActiveMQ出現,那么當生產者端再次接受ActiveMQ的消息回執時,ActiveMQ就會讓消息生產者進入等待狀態或者在發送者端直接拋出JMSException。當然您也可以配置ActiveMQ不進行ProducerFlowControl,如果您對自己ActiveMQ服務端的底層性能和消費者端的性能足夠自信的話。

在ActiveMQ的主配置文件activemq.xml中,關於ProducerFlowControl策略的控制標簽是“destinationPolicy”和它的子標簽。請看如下配置示例:

......
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry topic=">" producerFlowControl="false"/>
</policyEntries>
</policyMap>
</destinationPolicy>
......

以上示例配合所有的Topic模式的隊列不進行producerFlowControl策略控制。當然還可以為隊列配置啟用producerFlowControl策略:

......
<policyEntry queue=">" producerFlowControl="true" memoryLimit="200mb">

</policyEntry>
......

以上配置項表示為ActiveMQ中的所有Queue模式的隊列啟用producerFlowControl策略,並且限制每個Queue信息的最大內存存儲限制(memoryLimit)為200MB;這是指的最多使用200MB的內存區域,而不是說Queue中消息的總大小為200MB。例如,在ActiveMQ 5.X+ 版本中NON_PERSISTENT Message會被轉出到 temp store區域,所以有可能您觀察到的現象是,無論怎樣堆積NON_PERSISTENT Message消息,Queue的使用內存始終無法達到200MB。

......
<policyEntry queue=">" producerFlowControl="true" memoryLimit="200mb">
<pendingQueuePolicy>
<vmQueueCursor/>
</pendingQueuePolicy>
</policyEntry>
......

以上配置表示只使用內存存儲Queue中的所有消息,特別是NON_PERSISTENT Message只存儲在內存中,不使用temp store區域進行轉儲。在官方文檔中,有關於policyEntry標簽的所有配置選項都有完整說明:http://activemq.apache.org/per-destination-policies.html

6-4、消費者策略:Dispatch Async

討論完了消息生產者的關鍵性能點,我們再將目光轉向消息消費者(接收者端);就像本小節開始時描述的那樣,比起消息生產者來說消息消費者的性能更能影響ActiveMQ系統的整體性能,因為要成功完成一條消息的處理,它的工作要遠遠多於消息生產者。

首先,在默認情況下ActiveMQ服務端采用異步方式向客戶端推送消息。也就是說ActiveMQ服務端在向某個消費者會話推送消息后,不會等待消費者的響應信息,直到消費者處理完消息后,主動向服務端返回處理結果。如果您對自己的消費者性能足夠滿意,也可以將這個過程設置為“同步”:

......
// 設置為同步
connectionFactory.setDispatchAsync(false);
......

6-5、消費者策略:Prefetch

消費者關鍵策略中,需要重點討論的是消費者“預取數量”——prefetchSize。可以想象,如果消費者端的工作策略是按照某個周期(例如1秒),主動到服務器端一條一條請求新的消息,那么消費者的工作效率一定是極低的;所以ActiveMQ系統中,默認的策略是ActiveMQ服務端一旦有消息,就主動按照設置的規則推送給當前活動的消費者。其中每次推送都有一定的數量限制,這個限制值就是prefetchSize。

針對Queue工作模型的隊列和Topic工作模型的隊列,ActiveMQ有不同的默認“預取數量”;針對NON_PERSISTENT Message和PERSISTENT Message,ActiveMQ也有不同的默認“預取數量”:

  • PERSISTENT Message—Queue:prefetchSize=1000
  • NON_PERSISTENT Message—Queue:prefetchSize=1000
  • PERSISTENT Message—Topic:prefetchSize=100
  • NON_PERSISTENT Message—Topic:prefetchSize=32766

ActiveMQ中設置的各種默認預取數量一般情況下不需要進行改變。如果您使用默認的異步方式從服務器端推送消息到消費者端,且您對消費者端的性能有足夠的信心,可以加大預取數量的限制。但是非必要情況下,請不要設置prefetchSize=1,因為這樣就是一條一條的取數據;也不要設置為prefetchSize=0,因為這將導致關閉服務器端的推送機制,改為客戶端主動請求

  • 可以通過ActiveMQPrefetchPolicy策略對象更改預取數量
......
// 預取策略對象
ActiveMQPrefetchPolicy prefetchPolicy = connectionFactory.getPrefetchPolicy();
// 設置Queue的預取數量為50
prefetchPolicy.setQueuePrefetch(50);
connectionFactory.setPrefetchPolicy(prefetchPolicy);
//進行連接
connection = connectionFactory.createQueueConnection();
connection.start();
......
  • 也可以通過Properties屬性更改(當然還可以加入其他屬性)預取數量:
......
Properties props = new Properties();
props.setProperty("prefetchPolicy.queuePrefetch", "1000");
props.setProperty("prefetchPolicy.topicPrefetch", "1000");
//設置屬性
connectionFactory.setProperties(props);
//進行連接
connection = connectionFactory.createQueueConnection();
connection.start();
......

6-5、消費者策略:事務和死信

6-5-1、消費者端事務

JMS規范除了為消息生產者端提供事務支持以外,還為消費服務端准備了事務的支持。您可以通過在消費者端操作事務的commit和rollback方法,向服務器告知一組消息是否處理完成。采用事務的意義在於,一組消息要么被全部處理並確認成功,要么全部被回滾並重新處理

......
//建立會話(采用commit方式確認一批消息處理完畢)
session = connection.createSession(true, Session.SESSION_TRANSACTED);
//建立Queue(當然如果有了就不會重復建立)
sendQueue = session.createQueue("/test");
//建立消息發送者對象
MessageConsumer consumer = session.createConsumer(sendQueue);
consumer.setMessageListener(new MyMessageListener(session));

......

class MyMessageListener implements MessageListener {
private int number = 0;

/**
* 會話
*/

private Session session;

public MyMessageListener(Session session) {
this.session = session;
}

@Override
public void onMessage(Message message) {
// 打印這條消息
System.out.println("Message = " + message);
// 如果條件成立,就向服務器確認這批消息處理成功
// 服務器將從隊列中刪除這些消息
if(number++ % 3 == 0) {
try {
this.session.commit();
} catch (JMSException e) {
e.printStackTrace(System.out);
}
}
}
}

以上代碼演示的是消費者通過事務commit的方式,向服務器確認一批消息正常處理完成的方式。請注意代碼示例中的“session = connection.createSession(true, Session.SESSION_TRANSACTED);”語句。第一個參數表示連接會話啟用事務支持;第二個參數表示使用commit或者rollback的方式進行向服務器應答。

這是調用commit的情況,那么如果調用rollback方法又會發生什么情況呢?調用rollback方法時,在rollback之前已處理過的消息(注意,並不是所有預取的消息)將重新發送一次到消費者端(發送給同一個連接會話)。並且消息中redeliveryCounter(重發計數器)屬性將會加1。請看如下所示的代碼片段和運行結果

@Override
public void onMessage(Message message) {
// 打印這條消息
System.out.println("Message = " + message);
// rollback這條消息
this.session.rollback();
}

以上代碼片段中,我們不停的回滾正在處理的這條消息,通過打印出來的信息可以看到,這條消息被不停的重發:

Message = ActiveMQTextMessage {...... redeliveryCounter = 0, text = 這是發送的消息內容-------------------20}
Message = ActiveMQTextMessage {...... redeliveryCounter = 1, text = 這是發送的消息內容-------------------20}
Message = ActiveMQTextMessage {...... redeliveryCounter = 2, text = 這是發送的消息內容-------------------20}
Message = ActiveMQTextMessage {...... redeliveryCounter = 3, text = 這是發送的消息內容-------------------20}
Message = ActiveMQTextMessage {...... redeliveryCounter = 4, text = 這是發送的消息內容-------------------20}

可以看到同一條記錄被重復的處理,並且其中的redeliveryCounter屬性不斷累加。

6-5-2、重發和死信隊列

但是消息處理失敗后,不斷的重發消息肯定不是一個最好的處理辦法:如果一條消息被不斷的處理失敗,那么最可能的情況就是這條消息承載的業務內容本身就有問題。那么無論重發多少次,這條消息還是會處理失敗。

為了解決這個問題,ActiveMQ中引入了“死信隊列”(Dead Letter Queue)的概念。即一條消息再被重發了多次后(默認為重發6次redeliveryCounter==6),將會被ActiveMQ移入“死信隊列”。開發人員可以在這個Queue中查看處理出錯的消息,進行人工干預。

這里寫圖片描述

默認情況下“死信隊列”只接受PERSISTENT Message,如果NON_PERSISTENT Message超過了重發上限,將直接被刪除。以下配置信息可以讓NON_PERSISTENT Message在超過重發上限后,也移入“死信隊列”:

<policyEntry queue=">">  
<deadLetterStrategy>
<sharedDeadLetterStrategy processNonPersistent="true" />
</deadLetterStrategy>
</policyEntry>

另外,上文提到的默認重發次數redeliveryCounter的上限也是可以進行設置的,為了保證消息異常情況下盡可能小的影響消費者端的處理效率,實際工作中建議將這個上限值設置為3。原因上文已經說過,如果消息本身的業務內容就存在問題,那么重發多少次也沒有用。

RedeliveryPolicy redeliveryPolicy = connectionFactory.getRedeliveryPolicy();
// 設置最大重發次數
redeliveryPolicy.setMaximumRedeliveries(3);

實際上ActiveMQ的重發機制還有包括以上提到的rollback方式在內的多種方式:

  • 在支持事務的消費者連接會話中調用rollback方法。

  • 在支持事務的消費者連接會話中,使用commit方法明確告知服務器端消息已處理成功前,會話連接就終止了(最可能是異常終止)

  • 在需要使用ACK模式的會話中,使用消息的acknowledge方式明確告知服務器端消息已處理成功前,會話連接就終止了(最可能是異常終止)

但是以上幾種重發機制有一些小小的差異,主要體現在redeliveryCounter屬性的作用區域。簡而言之,第一種方法redeliveryCounter屬性的作用區域是本次連接會話,而后兩種redeliveryCounter屬性的作用區域是在整個ActiveMQ系統范圍。

6-6、消費者策略:ACK

消費者端,除了可以使用事務方式來告知ActiveMQ服務端一批消息已經成功處理外,還可以通過JMS規范中定義的acknowledge模式來實現同樣功能。事實上acknowledge模式更為常用

6-6-1、基本使用

如果選擇使用acknowledge模式,那么你至少有4種方式使用它,且這四種方式的性能區別很大:

  • AUTO_ACKNOWLEDGE方式:這種方式下,當消費者端通過receive方法或者MessageListener監聽方式從服務端得到消息后(無論是pul方式還是push方式),消費者連接會話會自動認為消費者端對消息的處理是成功的。但請注意,這種方式下消費者端不一定是向服務端一條一條ACK消息

  • CLIENT_ACKNOWLEDGE方式:這種方式下,當消費者端通過receive方法或者MessageListener監聽方式從服務端得到消息后(無論是pul方式還是push方式),必須顯示調用消息中的acknowledge方法。如果不這樣做,ActiveMQ服務器端將不會認為這條消息處理成功:

public void onMessage(Message message) {
//====================
//這里進行您的業務處理
//====================
try {
// 顯示調用ack方法
message.acknowledge();
} catch (JMSException e) {
e.printStackTrace();
}
}
  • DUPS_OK_ACKNOWLEDGE方式:批量確認方式。消費者端會按照一定的策略向服務器端間隔發送一個ack標示,表示某一批消息已經處理完成。DUPS_OK_ACKNOWLEDGE方式 和 AUTO_ACKNOWLEDGE方式在某些情況下是一致的,這個在后文會講到。

  • INDIVIDUAL_ACKNOWLEDGE方式:單條確認方式。這種方式是ActiveMQ單獨提供的一種方式,其常量定義的位置都不在javax.jms.Session規范接口中,而是在org.apache.activemq.ActiveMQSession這個類中。這種方式消費者端將會逐條向ActiveMQ服務端發送ACK信息。所以這種ACK方式的性能很差,除非您有特別的業務要求,否則不建議使用

6-6-2、工作方式和性能

筆者建議首先考慮使用AUTO_ACKNOWLEDGE方式確認消息,如果您這樣做,那么一定請使用optimizeACK優化選項,並且重新設置prefetchSize數量為一個較小值(因為1000條的默認值在這樣的情況下就顯得比較大了):

......

//ack優化選項(實際上默認情況下是開啟的)
connectionFactory.setOptimizeAcknowledge(true);
//ack信息最大發送周期(毫秒)
connectionFactory.setOptimizeAcknowledgeTimeOut(5000);
connection = connectionFactory.createQueueConnection();
connection.start();
......

AUTO_ACKNOWLEDGE方式的根本意義是“延遲確認”,消費者端在處理消息后暫時不會發送ACK標示,而是把它緩存在連接會話的一個pending 區域,等到這些消息的條數達到一定的值(或者等待時間超過設置的值),再通過一個ACK指令告知服務端這一批消息已經處理完成;而optimizeACK選項(指明AUTO_ACKNOWLEDGE采用“延遲確認”方式)只有當消費者端使用AUTO_ACKNOWLEDGE方式時才會起效

“延遲確認”的數量閥值:prefetch * 0.65
“延遲確認”的時間閥值:> optimizeAcknowledgeTimeOut

DUPS_OK_ACKNOWLEDGE方式也是一種“延遲確認”策略,如果目標隊列是Queue模式,那么它的工作策略與AUTO_ACKNOWLEDGE方式是一樣的。也就是說,如果這時prefetchSize =1 或者沒有開啟optimizeACK,也會逐條消息發送ACK標示;如果目標隊列是Topic模式,那么無論optimizeACK是否開啟,都會在消費的消息個數>=prefetch * 0.5時,批量確認這些消息。

6-7、消費者和生產者性能總結

本小節我們介紹了基於ActiveMQ構建的消息隊列系統中,生產者和消費者需要關注的重要性能點。但是整個ActiveMQ中的性能還需要各位讀者在實際工作中,一點一點的去挖掘。這里我們根據已經介紹過的性能關注點進行總結:

  • 發送NON_PERSISTENT Message和發送PERSISTENT Message是有性能差異的。引起這種差異的原因是前者不需要進行持久化存儲;但是這樣的性能差異在某些情況下會縮小,例如發送NON_PERSISTENT Message時,由於消費者性能不夠導致消息堆積,這時NON_PERSISTENT Message會被轉儲到物理磁盤上的“temp store”區域。

  • 發送帶有事務的消息和發送不帶有事務的消息,在服務器端的處理性能也是有顯著區別的。引起這種差異的原因是帶有事務的消息會首先記錄在服務器端的“transaction store”區域,並且服務器端會帶有redo日志,這樣保證發送者端在發送commit指令或者rollback指令時,服務器會完整相應的處理。

  • ActiveMQ中,為消息生產者所設定的ProducerFlowControl策略非常重要,它確定消息在ActiveMQ服務端產生大量堆積的情況下,ActiveMQ將減緩接收消息,保證了ActiveMQ能夠穩定的工作。您可以通過配置文件設置ProducerFlowControl策略的生效閥值,甚至可以關閉ProducerFlowControl策略(當然不建議這樣做)。

  • 消息生產者端和消息消費者端都可以通過“異步”方式和服務器進行通訊(但是意義不一樣)。在生產者端發送異步消息,一定要和ProducerWindowSize(回執窗口期)的設置共同使用;在消費者異步接受消息時,要記住有Prefetch這個關鍵的預取數值,並且PrefetchSize在非必要情況下不要設置為1。很顯然適合的PrefetchSize將改善服務端和消費者端的性能。

  • JMS規范中,消息消費者端也是支持事務的。所謂消費者端的事務是指:一組消息要么全部被commit(這時消費者會向服務端發送ACK表示),要么全部被rollback(這時同一個消費者端會向自己重發這些消息,並且這些消息的redeliveryCounter屬性+1);進行消息的重發是非常消耗消費者端性能的一件事情,這是因為在這個連接會話中,被Prefetch但是還沒有被處理的消息將一直等待重發的消息最終被確認。

  • 為了避免帶有錯誤業務信息的消息被無止境的重發,從而影響整個消息系統的性能。在ActiveMQ中為超過MaximumRedeliveries閥值(默認值為6,但是很明顯默認值太高了,建議設置為3)的消息准備了“死信隊列”。

  • 只有服務器收到了一條或者一組消息的ACK標示,才會認為這條或者這組消息被成功過的處理了。在消費者端有4種ACK工作模式,建議優先選擇AUTO_ACKNOWLEDGE。如果您這樣做了,那么請一定重新改小預取數量、設置OptimizeAcknowledge為true、重設OptimizeAcknowledgeTimeOut時間。這樣才能保證AUTO_ACKNOWLEDGE方式工作在“延遲確認”模式下,以便優化ACK性能。

(接下文:我們將開始介紹ActiveMQ的持久化存儲方案和高可用方案)


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com