概述
前面提到了,RocketMQ没有真正实现push模式消费,而是通过pull来实现。为了提高性能,未拉取到消息时,并不会返回消息未找到,而是将拉取请求挂起,直到有消息到来被唤醒或者超时。
轮询分类
分为长轮询和短轮询。短轮询1s,长轮询push模式为15s,pull模式为20s。
轮询触发逻辑
在 PullMessageProcessor.processRequest() 中
case ResponseCode.PULL_NOT_FOUND:
// broker 允许挂起,拉取请求设置了挂起标记
if (brokerAllowSuspend && hasSuspendFlag) {
long pollingTimeMills = suspendTimeoutMillisLong;
if (!this.brokerController.getBrokerConfig().isLongPollingEnable()) {
// 短轮询
pollingTimeMills = this.brokerController.getBrokerConfig().getShortPollingTimeMills();
}
String topic = requestHeader.getTopic();
long offset = requestHeader.getQueueOffset();
int queueId = requestHeader.getQueueId();
PullRequest pullRequest = new PullRequest(request, channel, pollingTimeMills,
this.brokerController.getMessageStore().now(), offset, subscriptionData, messageFilter);
// 挂起请求
this.brokerController.getPullRequestHoldService().suspendPullRequest(topic, queueId, pullRequest);
response = null; // 设置response为null,不会返回数据
break;
}
PullRequestHoldService 关键类
PullRequestHoldService执行具体挂起逻辑,它继承自 ServiceThread。
先来看挂起拉取请求方法:
public void suspendPullRequest(final String topic, final int queueId, final PullRequest pullRequest) {
String key = this.buildKey(topic, queueId);
// 以 topic@queueId为key,保存拉取请求
ManyPullRequest mpr = this.pullRequestTable.get(key);
if (null == mpr) {
mpr = new ManyPullRequest();
ManyPullRequest prev = this.pullRequestTable.putIfAbsent(key, mpr);
if (prev != null) {