每日5亿量级下使用@JmsListener消费出现事件丢失,求排查经验
@JmsListener队列消费丢消息的排查经验分享
结合日处理5亿条消息的高并发场景实践,分享几个常见的丢消息排查方向:
事务配置校验
多数丢消息案例都和事务未正确绑定有关。要确认监听器方法的@Transactional配置是否覆盖所有异常场景(比如rollbackFor = Exception.class),同时检查JMS容器工厂是否开启会话事务:@Bean public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(ConnectionFactory connectionFactory) { DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); factory.setConnectionFactory(connectionFactory); factory.setSessionTransacted(true); // 开启会话事务 return factory; }如果事务未正确提交,或异常时未触发回滚,会导致消息被"吞掉"却未实际处理。
消息确认模式检查
不同确认模式对应不同的消息生命周期:AUTO_ACKNOWLEDGE:容器在方法正常返回时自动确认,异常时通常触发重试,但如果容器配置了"异常即丢弃"的错误逻辑,可能丢消息;CLIENT_ACKNOWLEDGE:必须手动调用message.acknowledge(),遗漏会导致消息重复,但不会丢失;DUPS_OK_ACKNOWLEDGE:适合高并发场景,允许重复但不会丢消息。
高并发下优先采用事务+SESSION_TRANSACTED模式,避免确认模式配置错误导致的丢失。
死信队列(DLQ)排查
很多时候"丢消息"其实是消息进入死信队列却未被监控。要检查Broker的死信策略:比如ActiveMQ是否配置了DeadLetterStrategy,将重试失败的消息转发到指定DLQ而非直接丢弃,同时定期监控DLQ的消息堆积情况。Broker端资源与配置检查
高消息量级下,Broker的资源瓶颈会直接导致消息丢失:- 检查Broker磁盘是否已满,部分Broker在磁盘满时会直接丢弃新消息;
- 确认消息是否设置为持久化模式(
deliveryMode=2),非持久化消息在Broker重启或崩溃时会丢失; - 检查队列最大长度配置,是否因队列溢出导致消息被丢弃。
消费端日志与监控
必须在监听器关键节点打日志:消息ID、开始处理、处理完成/失败,示例代码如下:@JmsListener(destination = "biz_queue", containerFactory = "jmsContainerFactory") @Transactional public void processMessage(TextMessage message) throws JMSException { String msgId = message.getJMSMessageID(); log.info("[JMS消费] 开始处理消息: {}", msgId); try { // 业务逻辑处理 log.info("[JMS消费] 消息处理成功: {}", msgId); } catch (Exception e) { log.error("[JMS消费] 消息处理失败: {}", msgId, e); throw new RuntimeException("处理失败触发回滚", e); } }同时监控Broker的入队/出队/丢弃指标,通过指标变化定位是否有消息在Broker端丢失。
并发消费配置校验
高并发场景下,concurrency和maxConcurrency配置过高可能导致线程池耗尽,或消息被容器提前确认。要确保并发数与Broker的消费者上限匹配,避免因资源不足导致消息处理超时被丢弃。
内容的提问来源于stack exchange,提问作者Sindhu M
相关产品推荐
相关产品推荐

