常用排查定位查询语句
本文介绍基于云消息队列 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****查询结果返回 2 条日志记录:一条 Action 为 SendMessage(Code: 200),一条 Action 为 PushMessage(Code: 200),表明消息发送和推送均成功。
客户端调用
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日志则是客户端成功消费消息的标记。查询结果返回3条日志记录,Action 分别为
DeleteMessage和BasicAck,Code 均为200,表明消息已被客户端成功消费。说明如果客户端调用
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)
在查询结果页面左侧快速分析面板中,查看 Action 字段的分布比例,示例中显示 BasicAck 25%、DeleteMessage 25%、PushMessage 25%、SendMessage 24%。
如果查询的日志出现以下几种情况,请根据可能的原因分析:
-
日志搜索结果中没有
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****查询结果返回2条日志记录,
Code字段值均为200,表示消息操作成功。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****查询结果显示日志总条数为 2,结果精确。第 1 条日志 Action 为
SendDlqMessage,Code 为 200,Queue 为 a;第 2 条日志 Action 为SendMessage,Code 为 200,Queue 为 b。左侧快速分析面板显示 Action 字段分布:SendMessage 50%、SendDlqMessage 50%。
-
-
调用
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日志表示消息被路由到死信队列中。
查询结果返回3条日志记录,Action分别为PushMessage(Code为200)、BasicReject(Code为200)和SendDlqMessage(Code为200)。