RocketMQ DefaultMQPushConsumer vs DefaultLitePullConsumer

1. 核心架构差异

DefaultMQPushConsumer (推送模式)

java 复制代码
// 服务端主动推送消息到消费者
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("group");
consumer.subscribe("TopicTest", "*");
consumer.registerMessageListener(new MessageListenerConcurrently() {
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
        ConsumeConcurrentlyContext context) {
        // 服务端推送消息到这里
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
});

DefaultLitePullConsumer (拉取模式)

java 复制代码
// 客户端主动从服务端拉取消息
DefaultLitePullConsumer consumer = new DefaultLitePullConsumer("group");
consumer.subscribe("TopicTest", "*");
consumer.start();

// 手动控制拉取
List<MessageExt> messages = consumer.poll();
// 业务处理
consumer.commitSync(); // 手动提交

2. 消费重试机制对比

PushConsumer 重试机制

特点:支持重试,且是自动重试,支持到消息级别

java 复制代码
// 自动重试 - 消息级别
public class DefaultMQPushConsumer {
    // 最大重试次数,默认16次
    private int maxReconsumeTimes = 16;
    
    // 重试消息进入 %RETRY% 队列
    // 重试间隔:1s, 5s, 10s, 30s, 1m, 2m, 3m, 4m, 5m, 6m, 7m, 8m, 9m, 10m, 20m, 30m, 1h, 2h
}

// 消费失败处理
consumer.registerMessageListener(new MessageListenerConcurrently() {
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
        ConsumeConcurrentlyContext context) {
        try {
            // 业务处理
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        } catch (Exception e) {
            // 返回失败,自动进入重试队列
            return ConsumeConcurrentlyStatus.RECONSUME_LATER;
        }
    }
});

2.2 LitePullConsumer 重试机制

特点:没有内置的重试队列机制,不支持自动重试;要重试需要业务自己实现

java 复制代码
// 手动控制重试 - 需要业务代码实现
public class DefaultLitePullConsumer {
    // 没有内置的重试队列机制
    // 需要业务自己处理失败消息
}

// 手动重试示例
List<MessageExt> messages = consumer.poll(Duration.ofSeconds(10));
for (MessageExt message : messages) {
    try {
        processMessage(message);
        // 处理成功,记录偏移量
    } catch (Exception e) {
        // 处理失败,可以选择:
        // 1. 跳过此消息(可能丢失)
        // 2. 记录到死信队列手动处理
        // 3. 业务级重试逻辑
        log.error("Process message failed, msgId: {}", message.getMsgId(), e);
        
    }
}
// 批量提交,无法精确控制单条消息
consumer.commitSync();

3. 消费超时检查对比

PushConsumer 超时控制

特点:后台有消费超时检查,默认15min(从开始消费算起)。消费超时会将消息重发回broker(类似失败重试)。consumeTimeout可自行设置

java 复制代码
public class DefaultMQPushConsumer {
    // 消费超时时间,默认15分钟
    private long consumeTimeout = 15 * 60 * 1000;
    
    // 并发消费线程数控制
    private int consumeThreadMin = 20;
    private int consumeThreadMax = 64;
}

// 服务端会监控消费进度
// 如果消费线程卡住,Broker会重新投递消息

LitePullConsumer 超时控制

只有拉取超时,没有消费超时的检查

java 复制代码
public class DefaultLitePullConsumer {
    // 拉取超时控制
    private long pollTimeoutMillis = 10 * 1000;
    
    // 业务自己控制处理超时
    // 没有服务端超时检查
}

// 业务自己控制处理时间
List<MessageExt> messages = consumer.poll(Duration.ofSeconds(5));
long startTime = System.currentTimeMillis();
for (MessageExt message : messages) {
    // 业务需要自己控制单条消息处理超时
    if (System.currentTimeMillis() - startTime > 30000) {
        // 超时处理
        break;
    }
    processMessage(message);
}

4. 提交(Commit)机制对比

PushConsumer 提交机制

特点;仅可自动提交

java 复制代码
// 自动提交偏移量
consumer.registerMessageListener(new MessageListenerConcurrently() {
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
        ConsumeConcurrentlyContext context) {
        // 返回 CONSUME_SUCCESS 后自动提交偏移量
        // 提交的是这批消息的最大偏移量
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
});

// 异步提交,默认5秒提交一次
// 提交到 Broker 的消费进度管理

4.2 LitePullConsumer 提交机制

特点:默认自动提交,可手动提交

java 复制代码
// 手动提交,更灵活的控制
public class DefaultLitePullConsumer {
    // 提交方式
    public void commitSync();                    // 同步提交
    public void commitSync(Map<MessageQueue, Long> offsetTable); // 指定偏移量提交
    public void commitAsync();                   // 异步提交
    
}

// 使用示例
List<MessageExt> messages = consumer.poll();
if (!messages.isEmpty()) {
    // 处理消息
    boolean allSuccess = true;
    for (MessageExt message : messages) {
        if (!processMessage(message)) {
            allSuccess = false;
            break;
        }
    }
    
    if (allSuccess) {
        // 全部成功才提交
        consumer.commitSync();
    }
}

5. 使用场景推荐

DefaultMQPushConsumer 使用场景

适合场景
  1. 常规业务消息处理
  2. 需要严格不丢消息的场景
  3. 希望服务端管理消费状态,减少客户端复杂度
  4. 消费逻辑相对固定,不需要精细控制
优势
  • 自动重试机制完善
  • 服务端管理消费进度
  • 开发简单,专注业务逻辑
  • 消息可靠性高

DefaultLitePullConsumer 使用场景

适合场景
  1. 批处理任务
  2. 需要精细控制消费逻辑
  3. 消息处理时间不确定,需要自定义超时
  4. 需要实现复杂的分支逻辑
具体用例
java 复制代码
// 用例1:批处理控制
List<MessageExt> batch = consumer.poll();
if (batch.size() >= BATCH_SIZE) {
    processBatch(batch);
    consumer.commitSync();
}

// 用例2:条件消费
List<MessageExt> messages = consumer.poll();
for (MessageExt msg : messages) {
    if (meetsCondition(msg)) {
        processMessage(msg);
    }
    // 不满足条件的消息跳过,但偏移量会提交
    // 需要更精细的偏移量管理
}

// 用例3:自定义重试
Map<String, Integer> retryCountMap = new HashMap<>();
List<MessageExt> messages = consumer.poll();
for (MessageExt msg : messages) {
    String msgId = msg.getMsgId();
    int retryCount = retryCountMap.getOrDefault(msgId, 0);
    if (retryCount < MAX_RETRY) {
        if (processWithRetry(msg)) {
            retryCountMap.remove(msgId);
        } else {
            retryCountMap.put(msgId, retryCount + 1);
            // 不提交此消息偏移量
        }
    } else {
        // 超过重试次数,进入死信队列
        sendToDLQ(msg);
    }
}

6. 总结对比

选择建议

  • 大部分业务场景推荐使用 DefaultMQPushConsumer
  • 只有在需要精细控制消费逻辑时才使用 DefaultLitePullConsumer
  • 从 Push 切换到 Pull 需要慎重,因为失去了很多内置的可靠性保障
相关推荐
哈哈哈笑什么16 分钟前
SpringBoot 企业级接口加密【通用、可配置、解耦的组件】「开闭原则+模板方法+拦截器/中间件模式」
java·后端·安全
期待のcode17 分钟前
springboot依赖管理机制
java·spring boot·后端
WX-bisheyuange24 分钟前
基于Spring Boot的智慧校园管理系统设计与实现
java·大数据·数据库·毕业设计
深紫色的三北六号1 小时前
大疆不同任务类型执行逻辑,上云API源码分析
java·无人机·springboot·大疆·上云api
BD_Marathon1 小时前
【JavaWeb】IDEA运行并部署JavaWeb项目原理
java·ide·intellij-idea
7ioik1 小时前
什么是类加载机制?
java
洛阳泰山1 小时前
Java实现周易六爻自动排盘:根据起卦的公历时间换算农和干支时间,推算日柱空亡(旬空)
java·开发语言·周易·六爻·算卦
一只游鱼1 小时前
我的第一个微服务项目cy-fang1.0
java·后端·spring cloud
缘来是庄1 小时前
invalid comparison
java·spring boot·mybatis
哈哈哈笑什么1 小时前
3 次生产系统崩溃复盘:Java 后端从踩坑到封神的排查优化之路
java·后端·性能优化