stomp進階說明-prefetchSize、ack header

上次在php使用stomp操作ActiveMQ提到,PHP採用預設值去連ActiveMQ,處理速度異常緩慢。解決之道,可以藉由更改activemq.prefetchSize的值而得到改善。不過…改變activemq.prefetchSize會不會有什麼問題?或影響?

首先,需要先提到redelivery這個名詞。可以先參考官方文件 Message Redelivery and DLQ Handling

在不修改預設值的情況下,當PHP(customer)使用STOMP和ActiveMQ取得一筆message後,該message id就會被標為redelivery(Redelivered=TRUE)。直到customer回覆ack(acknowledge)後,該message會轉成Messages Dequeued。如果customer沒有回覆ack呢?customer將會無法取得下一筆message…PHP(customer)就卡在哪了…

當我們修改activemq.prefetchSize後,會改變上述的行為模式。做個實驗…

假設,我們設定activemq.prefetchSize=100。此時,customer會由ActiveMQ一次取得100筆message回來。ActiveMQ會將這100筆message的redelivery改成true,其他的customer無法取得這100筆messgae。(除非,最後沒有其他message可以取得,才會讓其他customer取得。)

當customer在處理這100筆message時,故意都不做ack,唯獨第90筆message才做ack(也就是說,其他99筆資料都不做ack)。此時會發生什麼狀況?
  • 1-90筆message都視同做了ack。
  • 91-100筆message的redelivery狀況會被改成true。
  • customer會再度去要下90筆message,以湊足activemq.prefetchSize所設定的容量。
  • 最後,依舊卡住

這樣的行為模式,就有幾件事要注意了。首先,如果要處理的資料是有順序性(queue的特性 - FIFO)時,適不適合採用多個customer?另外,當處理時真的有問題不能ack時,又該如何?畢竟,沒ack,會卡住的!

後者的問題在JAVA中不存在。因為可以使用recover(),最後將某筆message丟到DLQ(Dead Letter Queue)(詳細請參閱Subscription Recovery Policy)。

在STOMP 1.0中無此類功能。需要思考個配套作法。到了STOMP 1.1的規格中,已經新增NACK指令,可將message放到DLQ。

上述提到關於ack的行為(回覆一個ack,之前的message也視同做了ack)是否能改變呢?先看STOMP 1.0中下面這段話
Any messages received on the subscription will henceforth be delivered as MESSAGE frames from the server to the client. The ack header is optional, and defaults to auto.

In this case the ack header is set to client which means that messages will only be considered delivered after the client specifically acknowledges them with an ACK frame. The valid values for ack are auto (the default if the header is not included) and client.
附註:雖然STOMP 1.0規格說預設是auto,但實際測試pecl-stomp結果,預設卻是client。

STOMP 1.0中提到ack header可以設定為auto、client來改變行為模式。到了STOMP 1.1,增加了client-individual。想要瞭解auto、client、client-individual的處理模式,請參考關於在STOMP 1.1中SUBSCRIBE_ack_Header中的說明。

另外,根據實際測試的結果。只出現在STOMP 1.1規格中的第三個設定值-client-individual居然可以用。設定方式,如同更改activemq.prefetchSize。範例如下…
  1. $stomp->subscribe($amq['queue'], array("ack"=> "client-individual""activemq.prefetchSize"
    =>1));  

最後還是要提醒一下,要先知道自己如何使用ActiveMQ,先規劃好再決定如何設定。如上所述prefetchSiz、ack header等等的參數,不同的參數設定,會影響ActiveMQ的處理模式!

參考資料

  1. ActiveMQ in Action所提到不同consumer的預設值
    • Queue consumer default prefetch size = 1000
    • Queue browser consumer default prefetch size = 500
    • Persistent topic consumer default prefetch size = 100
    • Nonpersistent topic consumer default prefetch size = 32766
  2. stomp 1.1和stomp 1.0的差異
  3. ActiveMQ參考書籍-ActiveMQ in Action
  4. php使用stomp操作ActiveMQ
  5. stomp進階說明-prefetchSize、ack header
  6. stomp failover作法

留言