閱讀須知
- 文章中使用/* */註釋的方法會做深入分析
正文
Producer 的停止同樣可以依託於 Spring bean 的生命週期,在 Spring bean 銷燬時調用 DefaultMQProducer 的 shutdown 方法:
public void shutdown() {
/* 停止 Producer */
this.defaultMQProducerImpl.shutdown();
if (null != traceDispatcher) {
traceDispatcher.shutdown();
}
}
DefaultMQProducerImpl:
public void shutdown() {
this.shutdown(true);
}
DefaultMQProducerImpl:
public void shutdown(final boolean shutdownFactory) {
switch (this.serviceState) {
case CREATE_JUST:
break;
case RUNNING:
/* 註銷 Producer */
this.mQClientFactory.unregisterProducer(this.defaultMQProducer.getProducerGroup());
// 停止異步發送線程池
this.defaultAsyncSenderExecutor.shutdown();
if (shutdownFactory) {
/* 停止 MQ 客戶端實例 */
this.mQClientFactory.shutdown();
}
log.info("the producer [{}] shutdown OK", this.defaultMQProducer.getProducerGroup());
// 將狀態置爲已停止
this.serviceState = ServiceState.SHUTDOWN_ALREADY;
break;
case SHUTDOWN_ALREADY:
break;
default:
break;
}
}
MQClientInstance:
public void unregisterProducer(final String group) {
this.producerTable.remove(group);
/* 從 Broker 註銷 Producer */
this.unregisterClientWithLock(group, null);
}
MQClientInstance:
private void unregisterClientWithLock(final String producerGroup, final String consumerGroup) {
try {
if (this.lockHeartbeat.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
try {
/* 註銷 Producer 和 Consumer */
this.unregisterClient(producerGroup, consumerGroup);
} catch (Exception e) {
log.error("unregisterClient exception", e);
} finally {
this.lockHeartbeat.unlock();
}
} else {
log.warn("lock heartBeat, but failed.");
}
} catch (InterruptedException e) {
log.warn("unregisterClientWithLock exception", e);
}
}
這裏我們看到雖然 consumerGroup 傳入的值爲 null,但是 Consumer 停止同樣會複用這個流程。
MQClientInstance:
private void unregisterClient(final String producerGroup, final String consumerGroup) {
// 遍歷 Broker 地址
Iterator<Entry<String, HashMap<Long, String>>> it = this.brokerAddrTable.entrySet().iterator();
while (it.hasNext()) {
Entry<String, HashMap<Long, String>> entry = it.next();
String brokerName = entry.getKey();
HashMap<Long, String> oneTable = entry.getValue();
if (oneTable != null) {
for (Map.Entry<Long, String> entry1 : oneTable.entrySet()) {
String addr = entry1.getValue();
if (addr != null) {
try {
/* 從 Broker 註銷 Producer 和 Consumer */
this.mQClientAPIImpl.unregisterClient(addr, this.clientId, producerGroup, consumerGroup, 3000);
log.info("unregister client[Producer: {} Consumer: {}] from broker[{} {} {}] success", producerGroup, consumerGroup, brokerName, entry1.getKey(), addr);
} catch (RemotingException e) {
log.error("unregister client exception from broker: " + addr, e);
} catch (InterruptedException e) {
log.error("unregister client exception from broker: " + addr, e);
} catch (MQBrokerException e) {
log.error("unregister client exception from broker: " + addr, e);
}
}
}
}
}
}
MQClientAPIImpl:
public void unregisterClient(
final String addr,
final String clientID,
final String producerGroup,
final String consumerGroup,
final long timeoutMillis
) throws RemotingException, MQBrokerException, InterruptedException {
final UnregisterClientRequestHeader requestHeader = new UnregisterClientRequestHeader();
requestHeader.setClientID(clientID);
requestHeader.setProducerGroup(producerGroup);
requestHeader.setConsumerGroup(consumerGroup);
// 向 Broker 發送 UNREGISTER_CLIENT 命令
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.UNREGISTER_CLIENT, requestHeader);
RemotingCommand response = this.remotingClient.invokeSync(addr, request, timeoutMillis);
assert response != null;
switch (response.getCode()) {
case ResponseCode.SUCCESS: {
return;
}
default:
break;
}
throw new MQBrokerException(response.getCode(), response.getRemark());
}
這裏 Broker 對應 UNREGISTER_CLIENT 命令的處理器爲 ClientManageProcessor。從 Broker 註銷 Producer 完成之後,最後就是停止客戶端實例:
MQClientInstance:
public void shutdown() {
if (!this.consumerTable.isEmpty())
return;
if (!this.adminExtTable.isEmpty())
return;
if (this.producerTable.size() > 1)
return;
synchronized (this) {
switch (this.serviceState) {
case CREATE_JUST:
break;
case RUNNING:
this.defaultMQProducer.getDefaultMQProducerImpl().shutdown(false);
this.serviceState = ServiceState.SHUTDOWN_ALREADY;
// 停止拉取消息服務
this.pullMessageService.shutdown(true);
// 停止定時任務線程池
this.scheduledExecutorService.shutdown();
/* 停止遠程調用客戶端 */
this.mQClientAPIImpl.shutdown();
// 停止重新平衡服務
this.rebalanceService.shutdown();
if (this.datagramSocket != null) {
this.datagramSocket.close();
this.datagramSocket = null;
}
MQClientManager.getInstance().removeClientFactory(this.clientId);
log.info("the client factory [{}] shutdown OK", this.clientId);
break;
case SHUTDOWN_ALREADY:
break;
default:
break;
}
}
}
MQClientAPIImpl:
public void shutdown() {
this.remotingClient.shutdown();
}
NettyRemotingClient:
public void shutdown() {
try {
// 取消掃描和終止已棄用請求的定時任務
this.timer.cancel();
// 關閉所有遠程調用的 channel
for (ChannelWrapper cw : this.channelTables.values()) {
this.closeChannel(null, cw.getChannel());
}
this.channelTables.clear();
// 關閉 netty 內部處理事件的線程組
this.eventLoopGroupWorker.shutdownGracefully();
// 關閉處理 netty 用戶自定義事件的線程
if (this.nettyEventExecutor != null) {
this.nettyEventExecutor.shutdown();
}
// 關閉用於處理請求、響應、鏈接建立、斷開等事件的線程池
if (this.defaultEventExecutorGroup != null) {
this.defaultEventExecutorGroup.shutdownGracefully();
}
} catch (Exception e) {
log.error("NettyRemotingClient shutdown exception, ", e);
}
// 關閉供處理器處理器請求的線程池
if (this.publicExecutor != null) {
try {
this.publicExecutor.shutdown();
} catch (Exception e) {
log.error("NettyRemotingServer shutdown exception, ", e);
}
}
}