消息消费进度的更新

转载:https://blog.csdn.net/yankunhaha/article/details/100061337

 

如果消费进度保存在本地的话,那我们的docker环境怎么做到不重复消费

翻了下LocalFileOffsetStore其实也是先刷到内存的 如上。

那我看看下每5秒进行的持久话:

 

看下LocalFileOffsetStore的persistAll:

 

storePath的初始化:

 

格式是dir/clientId/group/offsets.json。dir如果没配置的话默认是home/.rocketmq_offsets/

这样的话,看下我本地的情况吧:

 

不错还真有

 那DefaultMQPushConsumerImpl里的offsetStore是什么时候指定的呢?

看下构造器:

 

 

并没有

看一下org.apache.rocketmq.client.impl.consumer.DefaultMQPushConsumerImpl#start方法:

 

可以看到如果是广播模式的话是用LocalFileOffsetStore的。那我们考虑的问题应该是客观存在的。

load是从文件读到内存的过程

我们观察一个广播消费的topic:

 

发现它的consumerClient是没有信息的,offset也怪怪得

 再看下消息拉取过程:

pullMessageService线程:

 广播模式会去读之前load到内存的offset。(对不起,这里我把集群模式看成了广播模式,所以下面的分析一直是对集群模式的分析- -)

还有一个比较关键的pullRequest.nextOffset,我们看看是怎么更新的,在callBack里:、

 

更新为拉取结果的nextBeginOffset了。

看看Broker拿这两个字段做了什么,查找消息的部分主要是下面这部分逻辑:

 

然后commitOffset是这么用的

注意到这里有个hasCommitOffsetFlag:

一共有四种状态是通过将16不断左移得到的。

 

 

 

 看下客户端怎么组装的:

 

从实现来看 sysFlag应该是4中状态的叠加态,当是广播模式时commitOffset是打开的状态。好先记住这一点,我们接着看客户端构造requestHeader的过程:

queueOffset实际上就是pullRequest的nextOffset。

 所以这个commitOffset到底是干什么用的,最后被刷到了一个topic@group为key的map里,但是如果是广播模式的话,每个group的每个成员都可以刷新这个值有什么意义呢(当然没有意义撒,这是集群模式才会有的逻辑,是你自己看错了呀!但是有个意外收获可以看到,不仅仅是每5秒的定时任务会将broker刷新到broker,集群模式下每次拉取消息也会更新master的offset且broker的更新实际上是以客户端内存的offset为准的。)好吧 广播模式offset的问题还是没弄清楚

另外可以看下

 

 

 看下rebalance:

 

 

 

主要是想看下一个新的pullRequest里面的nextOffset是怎么初始化的:

 

com.alibaba.rocketmq.client.impl.consumer.RebalancePushImpl#computePullFromWhere:

public long computePullFromWhere(MessageQueue mq) {
        long result = -1;
        final ConsumeFromWhere consumeFromWhere = this.defaultMQPushConsumerImpl.getDefaultMQPushConsumer().getConsumeFromWhere();
        final OffsetStore offsetStore = this.defaultMQPushConsumerImpl.getOffsetStore();
        switch (consumeFromWhere) {
            case CONSUME_FROM_LAST_OFFSET_AND_FROM_MIN_WHEN_BOOT_FIRST:
            case CONSUME_FROM_MIN_OFFSET:
            case CONSUME_FROM_MAX_OFFSET:
            case CONSUME_FROM_LAST_OFFSET: {
                long lastOffset = offsetStore.readOffset(mq, ReadOffsetType.READ_FROM_STORE);
                if (lastOffset >= 0) {
                    result = lastOffset;
                }
                // First start,no offset
                else if (-1 == lastOffset) {
                    if (mq.getTopic().startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) {
                        result = 0L;
                    } else {
                        try {
                            result = this.mQClientFactory.getMQAdminImpl().maxOffset(mq);
                        } catch (MQClientException e) {
                            result = -1;
                        }
                    }
                } else {
                    result = -1;
                }
                break;
            }
            case CONSUME_FROM_FIRST_OFFSET: {
                long lastOffset = offsetStore.readOffset(mq, ReadOffsetType.READ_FROM_STORE);
                if (lastOffset >= 0) {
                    result = lastOffset;
                } else if (-1 == lastOffset) {
                    result = 0L;
                } else {
                    result = -1;
                }
                break;
            }
            case CONSUME_FROM_TIMESTAMP: {
                long lastOffset = offsetStore.readOffset(mq, ReadOffsetType.READ_FROM_STORE);
                if (lastOffset >= 0) {
                    result = lastOffset;
                } else if (-1 == lastOffset) {
                    if (mq.getTopic().startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) {
                        try {
                            result = this.mQClientFactory.getMQAdminImpl().maxOffset(mq);
                        } catch (MQClientException e) {
                            result = -1;
                        }
                    } else {
                        try {
                            long timestamp = UtilAll.parseDate(this.defaultMQPushConsumerImpl.getDefaultMQPushConsumer().getConsumeTimestamp(),
                                UtilAll.YYYYMMDDHHMMSS).getTime();
                            result = this.mQClientFactory.getMQAdminImpl().searchOffset(mq, timestamp);
                        } catch (MQClientException e) {
                            result = -1;
                        }
                    }
                } else {
                    result = -1;
                }
                break;
            }

            default:
                break;
        }

        return result;
    }

可以看到有三种模式,最大,first和时间戳。具体的还是调用offsetStore。

但是注意这里: 

 

当指定了从last_offset消费的时候,如果readOffset没有会取broker上队列的最大偏移

posted @ 2020-09-21 11:54  l2c  阅读(231)  评论(0编辑  收藏  举报