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 需要慎重,因为失去了很多内置的可靠性保障
相关推荐
漂洋过海的鱼儿1 天前
设计模式——EIT构型(三)
java·网络·设计模式
曹轲恒1 天前
@PropertySource、@ImportResource、@Bean
java·spring boot·mybatis
Anastasiozzzz1 天前
Redis的键过期是如何删除的?【面试高频】
java·数据库·redis·缓存·面试
老神在在0011 天前
Token身份验证完整流程
java·前端·后端·学习·java-ee
王九思1 天前
Java 内存分析工具 MAT
java·开发语言·安全
浅水壁虎1 天前
任务调度——XXLJOB2(调度中心)
java·spring boot·spring
青火coding1 天前
SOFAServerless架构的意义
java·运维·中间件·架构·serverless
夕除1 天前
java--2
java·开发语言
源码获取_wx:Fegn08951 天前
计算机毕业设计|基于springboot + vue景区管理系统(源码+数据库+文档)
java·vue.js·spring boot·后端·课程设计
李少兄1 天前
Git 忽略文件机制:.gitignore 与 .git/info/exclude
java·git·elasticsearch