本文介紹基於雲訊息佇列 RabbitMQ 版當前日誌快速查詢和分析問題的方法。當您遇到訊息不符合預期、消費異常、訊息堆積時,通過該方法可以協助您高效識別出異常、保證業務正常運行。
前提條件
常用語句概覽
本文僅列舉常用SLS查詢語句,操作步驟和日誌格式說明,請參見日誌管理。
根據Exchange查詢發送IP列表
在記錄搜尋框中輸入以下查詢語句,查詢發送IP列表。
* and Action : SendMessage and Code : 200 |
select
split_part(ResourceName,',',2) as exchange_name,
split_part(ResourceName, ',', 3) as routing_key,
RemoteAddress as ip_port,
count(*) as total_send_num
group by
exchange_name, routing_key, ip_port
order by
total_send_num DESC
limit 1000000 查詢結果如下所示:
根據Queue查詢消費IP列表
在記錄搜尋框中輸入以下查詢語句,查詢消費IP列表。
* and Action : PushMessage and Code : 200 |
select
InstanceId as instance_id,
VHost as virtual_host,
Queue as queue_name,
RemoteAddress as ip_port,
count(*) as push_total_num
group by
instance_id,virtual_host, ip_port, queue_name
order by
push_total_num DESC
limit 10000000查詢結果如下所示:

查詢訊息軌跡
在記錄搜尋框中輸入查詢語句,查詢訊息軌跡。
通過Message ID查詢訊息軌跡
InstanceId:amqp-cn-i7m29o3s**** and VHost:cycle**** and ResourceName:msgId=27127757-44dc-4373-afc5-f8ea12f****查詢結果如下所示:

用戶端調用
BasicConsume訂閱,可以查詢到訊息的發送和服務端的推送軌跡,SendMessage對應用戶端調用BasicPublish、PushMessage對應服務端推送訊息給用戶端;如果用戶端採用BasicGet拉取訊息,則Action為BasicGet而不是PushMessage。說明如果日誌結果中
SendMessage只有一條,但是PushMessage(BasicGet)對應多條,可能是用戶端沒有在首條PushMessage(BasicGet)的消費逾時時間內調用BasicAck確認訊息,導致服務端以為用戶端沒有消費成功而重新推送該條訊息。消費逾時時間說明請參見執行個體重試策略參數說明。如果日誌結果中除了
SendMessage和PushMessage之外,還存在SendDlqMessage日誌,SendDlqMessage日誌表示當前訊息轉入死信。
查詢訊息是否被消費
InstanceId:amqp-cn-i7m29o3s**** and VHost:cycle**** and Queue:cycleCheckQueue**** and ConnectionId:00163efffe08281f-00004e11-0009732f-799c0af9bc4e4913-96b3**** and ChannelId:1 and (ResourceName:deliveryTag=90 or Property:deliveryTag=90) and RemoteAddress:"/192.168.XX.XX:XXXX"其中,ConnectionId、ChannelId、deliveryTag、RemoteAddress都是通過
PushMessage日誌擷取。RemoteAddress是用戶端的IP地址,ConnectionId是當前Connection的唯一標識,ChannelId是當前Channel的唯一標識,deliveryTag是服務端對當前訊息的唯一標識;DeleteMessage日誌則是用戶端成功消費訊息的標記。查詢結果如下所示:
說明如果用戶端調用
BasicConsume時設定autoAck=false,則需要用戶端調用BasicAck服務端才能確認訊息被用戶端正常消費並刪除,而且BasicAck必須在PushMessage時間戳記之後的消費逾時時間內調用,超過消費逾時時間服務端則認為用戶端消費失敗,並會重新推送該訊息到用戶端。具體請參見執行個體重試策略參數說明。用戶端已經調用
BasicAck,但是查詢訊息是否被消費時,發現日誌中並沒有DeleteMessage日誌,說明當前訊息並沒有成功消費,可以觀察PushMessage和BasicAck時間差,大於消費逾時時間則表示當前BasicAck是無效調用。如果只查詢到
PushMessage和DeleteMessage,沒有查到BasicAck,可能是BasicAck(deliveryTag, multiple=true)一次性Ack了deliveryTag之前的所有訊息。
查詢Queue的消費情況
在記錄搜尋框中輸入查詢語句,查詢SendMessage、PushMessage(BasicGet)、BasicAck、DeleteMessage。當四者的百分比相同的時候,表示用戶端的發送與消費速度基本持平,當前Queue無訊息堆積或是有極少訊息堆積。
InstanceId:amqp-cn-i7m29o3s**** and Vhost:cycle**** and Queue: cycleCheckQueue**** and (SendMessage or PushMessage or BasicAck or DeleteMessage)查詢結果如下所示:

如果查詢的日誌出現以下幾種情況,請根據可能的原因分析:
記錄搜尋結果中沒有
DeleteMessage,可能是由於用戶端在調用BasicConsume或BasicGet時,設定了autoAck=true,或者是用戶端所有的BasicAck請求時間已經超過了消費逾時時間,導致這些調用無效。消費逾時時間說明請參見執行個體重試策略參數說明。記錄搜尋結果中發現
PushMessage的百分比相比SendMessage較少,可能是用戶端的訂閱者過少,建議多開Connection並建立新的Consumer。記錄搜尋結果中發現
SendMessage和PushMessage的日誌百分比相當,但是DeleteMessage的百分比則相對較少,可能是用戶端存在大量BasicAck的請求時間已經超過了消費逾時時間,變成無效請求。消費逾時時間說明請參見執行個體重試策略參數說明。記錄搜尋結果中發現
SendMessage、PushMessage、DeleteMessage日誌百分比大致相同,但是BasicAck日誌相對較少,考慮是否在代碼中使用了BasicAck(multiple=true)。
死信訊息查詢
記錄搜尋框輸入查詢語句,查詢對應訊息。
訊息TTL到期進入無效信件佇列
InstanceId:amqp-cn-i7m29o3s**** and VHost:dlq**** and ResourceName:msgId=02a162ba-f842-440f-bfd4-2595dd19****查詢結果如下所示:

SendMessage對應您調用BasicPublish發送訊息,SendDlqMessage對應該訊息TTL到期後發送到對應的無效信件佇列中。說明僅當您配置了無效信件佇列才會有該條日誌。
Queue的TTL到期進入無效信件佇列
設定Queue的死信屬性以及TTL。
Map<String, Object> argument = new HashMap<>(); argument.put("x-dead-letter-exchange", [exchangeName]); argument.put("x-dead-letter-routing-key", [routingKey]); argument.put("x-message-ttl", [ttl]); channel.queueDeclare([queueName], true, false, false, argument);記錄搜尋框輸入如下,可以得到
SendMessage和SendDlqMessage日誌。InstanceId:amqp-cn-i7m29o3s**** and VHost:dlq**** and ResourceName:msgId=034a75c5-d957-422f-822e-72dfad2a****
調用
BasicReject、BasicNack時,requeue=falseInstanceId:amqp-cn-i7m29o3s**** and VHost:dlq**** and (ResourceName:msgId=034a75c5-d957-422f-822e-72dfad2a**** or ResourceName:deliveryTag=1)
其中
PushMessage日誌表示服務端推送訊息到用戶端,用戶端在收到訊息後調用BasicReject(requeue=false),對應SendDlqMessage日誌表示訊息被路由到無效信件佇列中。