1 DefaultMessageStore类
在上一篇文章中讲到PullMessageProcessor处理器在拉取消息的时候调用了defaultMessageStore.getMessage方法,本篇内容主要探究该方法的的DefaultMessageStore类和其主要方法
1.2 GetMessageResult类
查询消息是到ConsumerQueue中拿的数据ConsumerQueueData,每个ConsumerQueueData都是20个字节,ConsumerQueueData存了每个消息的物理offset(8字节)、消息的size(4字节)和tagCode(8字节),有了ConsumerQueueData之后就可以到CommiLog里通过getMessage获取一条消息,该消息由SelectMappedBufferResult封装(CommitLog里由MappedFileQueue管理内存映射文件,管理着MappedFile组成的List,消息的归属者就是MappedFile),SelectMappedBufferResult对象该消息归属的MappedFile是谁和byteBuffer。为什么要存该消息归属的MappedFile是谁呢?因为MappedFile对外提供一次查询后refcount会执行++操作,查询出来的结果最终会导入到Response事务body里,此时GetMessageResult会调用release方法,该方法调用会执行GetMessageResult对象里的messageMappedList方法的release方法,该方法会让MappedFile的refCount执行–操作,refcount归零后就说明该MappedFile没人用了,占用的MappedByteBuffer内存(堆外内存)就会释放
1.2 getMessage方法的流程
如下图,RunningFlag有好多位在下一篇看源码的时候再去探究。
获取到的ConsumerQueue从消费队列映射表里拿,ConsumerQueue里存的是MappedFileQueue,MappedFileQueue里有MappedFile组成的List,MappedFile大小是固定的,20*30w的大小,MappFile里存了ConsumerQueueData。
检查ConsumeQueue是否可满足本次pull请求的offset的offset是以消息为单位,不是ConsumerQueueData里的offset。检查通过才能继续往下走。
上图中的检查状态的状态码在前几篇内容里已经讲到了,这里再列出来,如下:
查询出来数据后就是处理数据的逻辑,在下图可以看出,出来数据是在一个循环里,当16000字节满了(处理800个ConsumerQueueData)之后跳出循环。返回true才跳出循环
为什么计算冷数据的逻辑是CommitLog的最大物理偏移量-offsetPy大于系统内存的40%呢?
当前正在顺序写的mappedFile是固定写死的1G,运行时间非常长,MQ发送的消息非常多时,当内存不够时,需要释放内存,其他模块占了0.8g,JVM有4g,CommitLog占了大约3.2g,3.2/8*100%=40%,当然这只是评估的规则不是准确情况。