# 消息丢失告警处理指南

消息丢失告警表示 EMQX Cloud 在消息传递过程中，由于客户端会话消息队列占满而丢弃了消息。

该情况通常意味着消息已路由到订阅者会话，但因客户端长时间离线或消息处理能力不足，导致会话消息队列达到上限，后续消息无法继续入队并被丢弃。

## 客户端长时间离线（Clean Session = False）

### 问题描述

当客户端离线且 **Clean Session = False** 时，EMQX Cloud 会将该客户端应接收的消息持续存入其会话消息队列（默认长度为 1000 条），等待客户端重连后投递。

如果客户端长时间未重连，导致会话过期被清理（MQTT v3 默认 2 小时，MQTT v5 由 `session_expiry_interval` 决定），或会话消息队列已满，则后续消息将被直接丢弃，从而触发消息丢失告警。

在**监控**页面中，若观察到客户端处于离线状态但会话仍然存在，且消息队列已达到上限，则通常符合此类情况。

### 常见原因

- 客户端离线时间过长，未及时重连。  
- 会话消息队列持续积压，达到最大长度限制。  
- 使用随机 `clientid` 且设置了 `Clean Session = False`，导致重连后会话发生变化。  

### 处理方法

- 若业务不需要在客户端离线期间接收消息，将 **Clean Session** 设置为 `True`，避免离线消息堆积导致丢弃。  
- 如必须使用 `Clean Session = False`，需确保客户端实现自动重连机制，并在断线后尽快重连。  
- 避免使用随机 `clientid` 搭配 `Clean Session = False`，以防止因 `clientid` 变化导致会话失效并产生消息丢弃。  

## 客户端消息处理能力不足

### 问题描述

同一客户端订阅多个主题时，这些主题共用一个固定长度的会话消息队列（默认 1000 条）。如果某些主题消息流量较大，而客户端消费速度不足，会导致消息队列快速积压并达到上限，后续消息将被丢弃。

在**监控**页面中，若客户端处于在线状态，且会话信息中显示**消息队列已满（1000 / 1000）**，则通常符合此类情况。

### 常见原因

- 客户端消息消费速度低于消息生产速度。  
- 单个客户端订阅了过多高流量主题。  

### 处理方法

- 优化客户端代码，提高消息处理和消费性能。  
- 使用共享订阅分摊消息负载，避免单一客户端承受过高的消息压力。相关说明可参考文档：[共享订阅](../../connect_to_deployments/shared_subscription.md)。  

## 排查步骤

1. 登录 EMQX Cloud 控制台。

2. 打开部署**日志**，将“错误类型”过滤为**消息**，查找类似如下的丢弃日志记录：

   ```text
   clientid: device001, peername: xx.xx.xx.xx:23853, username: test, topic: t/test, pid: <0.13552.0>, payload: 61616161616161616161, payload_encode: hex, queue: {"store_qos0":true,"max_len":1000,"len":1000,"dropped":91530}, msg: dropped_msg_due_to_mqueue_is_full

3. 从日志中获取 `clientid` 信息。

4. 打开**监控** -> **客户端**页面，搜索该 `clientid`，进入客户端详情并查看会话状态：

   - 若客户端离线但会话仍存在，则属于**客户端长时间离线**场景。

     ![message_loss_offline](./_assets/message_loss_offline.png)

   - 若客户端在线且会话消息队列已满，则属于**客户端消息处理能力不足**场景。

     ![message_loss_online](./_assets/message_loss_online.png)

5. 若在**监控** -> **客户端**页面中无法找到对应客户端会话，可结合客户端侧日志和 Clean Session（Clean Start）配置进一步判断：
   - 若设置为 `True` 且仍出现丢弃，通常属于客户端消息处理能力不足**。
   - 若设置为 `False`，则需结合客户端断连时的日志，进一步分析是否为长时间离线导致。

## 监控与统计

在 **EMQX Cloud 控制台** -> **指标** -> **时间轴** -> **丢弃消息** 中，可以查看基于时间轴的整体丢弃消息数量趋势，用于持续观察消息丢失情况是否得到缓解。

![message_loss_monitor](./_assets/message_loss_monitor.png)

## 消息丢弃事件追踪说明

- EMQX Cloud 不会存储历史客户端消息队列中的完整消息内容，也不会保存已丢弃消息的全部数据。

- 在日志中仅会记录部分关键信息（`payload` 可能被截断），包括 `clientid`、`peername`、`username`、`topic` 和 `payload` 等字段。

- 若需要长期追踪消息丢弃事件，可订阅事件主题 `$events/delivery_dropped`，并结合规则引擎将事件转发或存储。示例 SQL 如下：

  ```sql
  SELECT
      *
  FROM
      "$events/delivery_dropped"
  ```

- 可进一步添加条件过滤，例如 `clientid`、`topic` 等字段。相关字段说明可参考：[SQL 数据源和字段](../../rule_engine/rule_engine_events.md#消息在投递的过程中被丢弃事件-events-delivery-dropped)。