9)broker端处理拉取消息请求
9.1)broker接收请求网络层回顾
消费者客户端向broker端发送RemotingCommand,主要包括opaque,requestCode为PULL_MESSAGE,RPC_TYPE为REQUEST_COMMAND,header消息体等;
broker在启动阶段会向协议处理器映射表中注册键值对<code,pair>,pair对象中第一个value是处理器,第二个value是线程池;
9.1.1)broker端的netty框架处理
headContext——>handshakehandler——>nettyEncoder——>nettyDecoder——>idleStatehandler——>connectionManagerHandler ——>serverHandler
9.1.1.1)NettyServerHandler
根据requestCode在协议处理器映射表中,找到pair,将网络层的处理逻辑包装成requestTask,提交给线程池运行;
9.1.1.2)网络层处理逻辑包括:
9.1.1.2.1)构建RemotingResponselCallback实例
重写callback方法,其内部封装了发送结果的逻辑,判断若response不为null,则设置opaque,RPC_TYPE为RESPONSE_COMMAND,执行ChannelHandlerContext#writeAndFlush方法;若response为null,则啥也不做;
9.1.1.2.2)processor.processRequest
准备执行业务逻辑,调用RemotingResponselCallback#callback方法,将RemotingCommand类型的返回结果response作为其入参;
9.2)PullMessageProcessor#processRequest
代码接近400行,先抓重点分析;getMessage方法是broker端处理消息拉取的核心部分;
9.2.1)创建RemotingCommand类型的response
解析requestHead,赋值opaque
9.2.2)权限校验,为tag的hash过滤做准备
9.2.2.1)如请求的queueId小于0或者大于max-1,则返回SYSYTEM_ERROR等;
9.2.2.2)根据requestHeader中的消费者组,从broker端的ComsumerManager中的consumerTable中找到ComsumerGroupInfo实例,即消费者信息;再根据requestHeader中的topic,从ConsumerGroupInfo实例中的subscriptionTable中获取SubscriptionData实例,即订阅信息;将订阅信息等封装进MessageFilter对象;
9.2.3)DefultMessageStore#getMessage方法
broker端处理消息拉取请求,代码接近200行;先抽重点分析;由于已经获取到了分配给当前clientId的一组set,所以只要去broker上访问这些mq即可拿到消息;而PullRequest实例包含四个属性,消费者组,messageQueue,processQueue,nextOffset,所以通过messageQueue中的brokerName,topic和queueId可以定位到某台机器的某个ConsumerQueue实例,再通过nextOffset可以定位到cq实例中具体某个mappedFile;由于每次selectMappedBufferResult的范围是当前mappedFile的nextOffset到当前(mappedFile文件名+