From cff264916b3e1b76c3bb786b7cebe5d6f6b9bdb5 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Mon, 18 Sep 2023 20:16:50 +0800 Subject: [PATCH 01/18] =?UTF-8?q?=E5=AE=8C=E5=96=84RocketMQ=20NameServer?= =?UTF-8?q?=E8=B7=AF=E7=94=B1=E5=8A=9F=E8=83=BD=E3=80=81=E8=B7=AF=E7=94=B1?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E3=80=81=E8=B7=AF=E7=94=B1=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E4=B8=8E=E5=8F=91=E7=8E=B0=E6=9C=BA=E5=88=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rocketmq/broker/BrokerController.java | 8 ++++ .../rocketmq/broker/out/BrokerOuterAPI.java | 5 +++ .../common/protocol/route/BrokerData.java | 1 + .../common/protocol/route/TopicRouteData.java | 13 +++++++ .../rocketmq/example/quickstart/Consumer.java | 2 +- .../rocketmq/example/quickstart/Producer.java | 1 + .../rocketmq/namesrv/NamesrvController.java | 4 ++ .../rocketmq/namesrv/NamesrvStartup.java | 4 ++ .../processor/DefaultRequestProcessor.java | 4 ++ .../namesrv/routeinfo/RouteInfoManager.java | 37 +++++++++++++++++++ .../remoting/netty/NettyServerConfig.java | 23 ++++++++++++ 11 files changed, 101 insertions(+), 1 deletion(-) diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java index 85009d620f5..c4a326f04a3 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java @@ -887,6 +887,8 @@ public void start() throws Exception { this.registerBrokerAll(true, false, true); } + // 定时任务,每30秒向所有NameServer发送心跳,NameServer中会记录每一个Broker最近心跳时间, + // NameServer每10秒会扫描所有Broker的心跳时间,如果NameServer超过120秒未收到心跳,则会将Broker剔除。 this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override @@ -928,6 +930,12 @@ public synchronized void registerIncrementBrokerData(TopicConfig topicConfig, Da doRegisterBrokerAll(true, false, topicConfigSerializeWrapper); } + /** + * 该方法遍历NameServer列表,Broker消息服务器依次向NameServer发送心跳包,如代码清单2-9所示 + * @param checkOrderConfig + * @param oneway + * @param forceRegister + */ public synchronized void registerBrokerAll(final boolean checkOrderConfig, boolean oneway, boolean forceRegister) { TopicConfigSerializeWrapper topicConfigWrapper = this.getTopicConfigManager().buildTopicConfigSerializeWrapper(); diff --git a/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java b/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java index 6caa2358e32..c95f861e635 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java @@ -129,14 +129,17 @@ public List registerBrokerAll( final RegisterBrokerRequestHeader requestHeader = new RegisterBrokerRequestHeader(); requestHeader.setBrokerAddr(brokerAddr); + // brokerId=0 代表Master Broker,brokerId>0代表Slave Broker requestHeader.setBrokerId(brokerId); requestHeader.setBrokerName(brokerName); requestHeader.setClusterName(clusterName); + // 主节点地址,初次请求时为空,从节点向NameServer注册后返回 requestHeader.setHaServerAddr(haServerAddr); requestHeader.setCompressed(compressed); RegisterBrokerBody requestBody = new RegisterBrokerBody(); requestBody.setTopicConfigSerializeWrapper(topicConfigWrapper); + // 消息过滤服务器列表 requestBody.setFilterServerList(filterServerList); final byte[] body = requestBody.encode(compressed); final int bodyCrc32 = UtilAll.crc32(body); @@ -147,6 +150,7 @@ public List registerBrokerAll( @Override public void run() { try { + // 向NameServer注册 RegisterBrokerResult result = registerBroker(namesrvAddr,oneway, timeoutMills,requestHeader,body); if (result != null) { registerBrokerResultList.add(result); @@ -179,6 +183,7 @@ private RegisterBrokerResult registerBroker( final byte[] body ) throws RemotingCommandException, MQBrokerException, RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, InterruptedException { + // RequestCode.REGISTER_BROKER 代表发送的是一个Broker注册请求 RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.REGISTER_BROKER, requestHeader); request.setBody(body); diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/route/BrokerData.java b/common/src/main/java/org/apache/rocketmq/common/protocol/route/BrokerData.java index 36599fbc874..68be0ab76ab 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/route/BrokerData.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/route/BrokerData.java @@ -26,6 +26,7 @@ public class BrokerData implements Comparable { private String cluster; private String brokerName; + // brokerId=0代表主Master,大于0表示从Slave private HashMap brokerAddrs; private final Random random = new Random(); diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/route/TopicRouteData.java b/common/src/main/java/org/apache/rocketmq/common/protocol/route/TopicRouteData.java index e8f54b8d73e..32b6940ef09 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/route/TopicRouteData.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/route/TopicRouteData.java @@ -26,9 +26,22 @@ import org.apache.rocketmq.remoting.protocol.RemotingSerializable; public class TopicRouteData extends RemotingSerializable { + + /** + * 顺序消息的配置内容,来自kvConfig + */ private String orderTopicConf; + /** + * topic队列元数据 + */ private List queueDatas; + /** + * topic分布的broker元数据 + */ private List brokerDatas; + /** + * Broker上过滤服务器的地址列表 + */ private HashMap/* Filter Server */> filterServerTable; public TopicRouteData cloneTopicRouteData() { diff --git a/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java b/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java index 6d3b936507e..9eba15934da 100644 --- a/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java +++ b/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java @@ -48,7 +48,7 @@ public static void main(String[] args) throws InterruptedException, MQClientExce * } * */ - + consumer.setNamesrvAddr("127.0.0.1:9876"); /* * Specify where to start in case the specified consumer group is a brand new one. */ diff --git a/example/src/main/java/org/apache/rocketmq/example/quickstart/Producer.java b/example/src/main/java/org/apache/rocketmq/example/quickstart/Producer.java index 53a1d4dd64a..eebfd0da1ae 100644 --- a/example/src/main/java/org/apache/rocketmq/example/quickstart/Producer.java +++ b/example/src/main/java/org/apache/rocketmq/example/quickstart/Producer.java @@ -44,6 +44,7 @@ public static void main(String[] args) throws MQClientException, InterruptedExce * } * */ + producer.setNamesrvAddr("127.0.0.1:9876"); /* * Launch the instance. diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java index a6654f271c3..fadf123a8c9 100644 --- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java +++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java @@ -77,6 +77,7 @@ public boolean initialize() { this.kvConfigManager.load(); + // 初始化Netty信息,会在后序流程启动Netty this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.brokerHousekeepingService); this.remotingExecutor = @@ -84,6 +85,8 @@ public boolean initialize() { this.registerProcessor(); + // 定时任务,每隔10s会扫描一次brokerLiveTable(存放心跳包的时间戳信息),如果在120s内没有收到心跳包, + // 则认为Broker失效,更新topic的路由信息,将失效的Broker信息移除 this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override @@ -92,6 +95,7 @@ public void run() { } }, 5, 10, TimeUnit.SECONDS); + // 每隔10s打印一次KV配置 this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvStartup.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvStartup.java index 9b49567f322..ae5e253cdd7 100644 --- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvStartup.java +++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvStartup.java @@ -83,6 +83,8 @@ public static NamesrvController createNamesrvController(String[] args) throws IO final NettyServerConfig nettyServerConfig = new NettyServerConfig(); nettyServerConfig.setListenPort(9876); if (commandLine.hasOption('c')) { + // 判断是否有 -c 启动参数,指定配置文件位置 + // 获取配置的文件地址 String file = commandLine.getOptionValue('c'); if (file != null) { InputStream in = new BufferedInputStream(new FileInputStream(file)); @@ -143,9 +145,11 @@ public static NamesrvController start(final NamesrvController controller) throws System.exit(-3); } + // 注册 JVM钩子函数,在JVM进程关闭之前,会执行钩子函数 Runtime.getRuntime().addShutdownHook(new ShutdownHookThread(log, new Callable() { @Override public Void call() throws Exception { + // 关闭线程池、Netty服务等 controller.shutdown(); return null; } diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java index 467078c44f8..becf75dc104 100644 --- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java +++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java @@ -88,6 +88,7 @@ public RemotingCommand processRequest(ChannelHandlerContext ctx, case RequestCode.QUERY_DATA_VERSION: return queryBrokerTopicConfig(ctx, request); case RequestCode.REGISTER_BROKER: + // Broker注册心跳 Version brokerVersion = MQVersion.value2Version(request.getVersion()); if (brokerVersion.ordinal() >= MQVersion.Version.V3_0_11.ordinal()) { return this.registerBrokerWithFilterServer(ctx, request); @@ -216,6 +217,7 @@ public RemotingCommand registerBrokerWithFilterServer(ChannelHandlerContext ctx, registerBrokerBody.getTopicConfigSerializeWrapper().getDataVersion().setTimestamp(0); } + // 注册Broker信息 RegisterBrokerResult result = this.namesrvController.getRouteInfoManager().registerBroker( requestHeader.getClusterName(), requestHeader.getBrokerAddr(), @@ -340,10 +342,12 @@ public RemotingCommand getRouteInfoByTopic(ChannelHandlerContext ctx, final GetRouteInfoRequestHeader requestHeader = (GetRouteInfoRequestHeader) request.decodeCommandCustomHeader(GetRouteInfoRequestHeader.class); + // 获取topic的路由信息 TopicRouteData topicRouteData = this.namesrvController.getRouteInfoManager().pickupTopicRouteData(requestHeader.getTopic()); if (topicRouteData != null) { if (this.namesrvController.getNamesrvConfig().isOrderMessageEnable()) { + // 如果开启了顺序消息,则从kvConfig获取顺序消息配置 String orderTopicConf = this.namesrvController.getKvConfigManager().getKVConfig(NamesrvUtil.NAMESPACE_ORDER_TOPIC_CONFIG, requestHeader.getTopic()); diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java index ecd057a29ac..3c3f15cf41b 100644 --- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java +++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java @@ -49,10 +49,25 @@ public class RouteInfoManager { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME); private final static long BROKER_CHANNEL_EXPIRED_TIME = 1000 * 60 * 2; private final ReadWriteLock lock = new ReentrantReadWriteLock(); + /** + * topic消息队列的路由信息,消息发送时根据路由表进行负载均衡 + */ private final HashMap> topicQueueTable; + /** + * Broker基础信息,包含brokerName、所属集群名称、主备Broker地址。 + */ private final HashMap brokerAddrTable; + /** + * Broker集群信息,存储集群中所有Broker的名称 + */ private final HashMap> clusterAddrTable; + /** + * Broker状态信息,NameServer每次收到心跳包时会替换该信息 + */ private final HashMap brokerLiveTable; + /** + * Broker上的FilterServer列表,用于类模式消息过滤。类模式过滤机制在4.4及以后版本被废弃。 + */ private final HashMap/* Filter Server */> filterServerTable; public RouteInfoManager() { @@ -111,26 +126,35 @@ public RegisterBrokerResult registerBroker( RegisterBrokerResult result = new RegisterBrokerResult(); try { try { + // 注册操作加锁,防止并发修改RouteInfoManager中的路由表 this.lock.writeLock().lockInterruptibly(); Set brokerNames = this.clusterAddrTable.get(clusterName); + // 判断所属集群是否存在 if (null == brokerNames) { brokerNames = new HashSet(); + // 如果不存在,则创建集群 this.clusterAddrTable.put(clusterName, brokerNames); } + // 将broker名称加入集群的broker集合 brokerNames.add(brokerName); boolean registerFirst = false; + // 维护 brokerData信息 BrokerData brokerData = this.brokerAddrTable.get(brokerName); if (null == brokerData) { + // 该broker是否是新注册的 registerFirst = true; + // 如果该broker是新注册的,NameServer内存中不会存在broker信息,则新创建一个 brokerData = new BrokerData(clusterName, brokerName, new HashMap()); this.brokerAddrTable.put(brokerName, brokerData); } Map brokerAddrsMap = brokerData.getBrokerAddrs(); //Switch slave to master: first remove <1, IP:PORT> in namesrv, then add <0, IP:PORT> //The same IP:PORT must only have one record in brokerAddrTable + // brokerId=0代表 Master broker, brokerId>0代表Slave broker + // 如果brokerId发生变更,则更新内存中的Broker信息 Iterator> it = brokerAddrsMap.entrySet().iterator(); while (it.hasNext()) { Entry item = it.next(); @@ -146,16 +170,20 @@ public RegisterBrokerResult registerBroker( && MixAll.MASTER_ID == brokerId) { if (this.isBrokerTopicConfigChanged(brokerAddr, topicConfigWrapper.getDataVersion()) || registerFirst) { + // 如果Broker为主节点,并且Broker的topic配置信息发生变化或者是初次注册, + // 则需要创建或更新topic路由元数据,并填充topicQueueTable, ConcurrentMap tcTable = topicConfigWrapper.getTopicConfigTable(); if (tcTable != null) { for (Map.Entry entry : tcTable.entrySet()) { + // 创建或更新topic路由元数据,并填充topicQueueTable, this.createAndUpdateQueueData(brokerName, entry.getValue()); } } } } + // 更新BrokerLiveInfo,存储状态正常的Broker信息表,BrokeLiveInfo是执行路由删除操作的重要依据 BrokerLiveInfo prevBrokerLiveInfo = this.brokerLiveTable.put(brokerAddr, new BrokerLiveInfo( System.currentTimeMillis(), @@ -179,6 +207,7 @@ public RegisterBrokerResult registerBroker( if (masterAddr != null) { BrokerLiveInfo brokerLiveInfo = this.brokerLiveTable.get(masterAddr); if (brokerLiveInfo != null) { + // 主节点地址,初次请求时为空,从节点向NameServer注册后返回 result.setHaServerAddr(brokerLiveInfo.getHaServerAddr()); result.setMasterAddr(masterAddr); } @@ -371,6 +400,11 @@ private void removeTopicByBrokerName(final String brokerName) { } } + /** + * 根据已缓存的broker信息,组装Topic路由所需的信息并返回 + * @param topic + * @return + */ public TopicRouteData pickupTopicRouteData(final String topic) { TopicRouteData topicRouteData = new TopicRouteData(); boolean foundQueueData = false; @@ -473,6 +507,7 @@ public void onChannelDestroy(String remoteAddr, Channel channel) { try { try { + // 注册的Broker信息变更,需要加互斥锁 this.lock.writeLock().lockInterruptibly(); this.brokerLiveTable.remove(brokerAddrFound); this.filterServerTable.remove(brokerAddrFound); @@ -505,6 +540,7 @@ public void onChannelDestroy(String remoteAddr, Channel channel) { } } + // 删除集群信息中的 broker if (brokerNameFound != null && removeBrokerName) { Iterator>> it = this.clusterAddrTable.entrySet().iterator(); while (it.hasNext()) { @@ -527,6 +563,7 @@ public void onChannelDestroy(String remoteAddr, Channel channel) { } } + // 删除topic信息中的broker if (removeBrokerName) { Iterator>> itTopicQueueTable = this.topicQueueTable.entrySet().iterator(); diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyServerConfig.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyServerConfig.java index a5e2a232dd5..a631e764087 100644 --- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyServerConfig.java +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyServerConfig.java @@ -18,14 +18,36 @@ public class NettyServerConfig implements Cloneable { private int listenPort = 8888; + /** + * 业务线程数 + */ private int serverWorkerThreads = 8; private int serverCallbackExecutorThreads = 0; + /** + * NIO线程池线程个数,这类线程主要用于处理网络请求,先解析请求包,然后转发到各个业务线程池完成具体的业务操作,最后将结果返回给调用方。 + */ private int serverSelectorThreads = 3; + /** + * send oneway消息请求的并发度(Broker端参数) + */ private int serverOnewaySemaphoreValue = 256; + /** + * 异步消息发送的最大并发度(Broker端参数) + */ private int serverAsyncSemaphoreValue = 64; + /** + * 网络连接最大空闲时间,默认为120s。如果连接空闲时间超过该参数设置的值,连接将被关闭。 + * 正常情况下,客户端连接会通过心跳保持连接,如果客户端长时间未发送心跳,则认为已断开连接,服务端将关闭连接。 + */ private int serverChannelMaxIdleTimeSeconds = 120; + /** + * 网络socket发送缓存区大小,默认为64KB。 + */ private int serverSocketSndBufSize = NettySystemConfig.socketSndbufSize; + /** + * 网络socket接收缓存区大小,默认为64KB。 + */ private int serverSocketRcvBufSize = NettySystemConfig.socketRcvbufSize; private boolean serverPooledByteBufAllocatorEnable = true; @@ -36,6 +58,7 @@ public class NettyServerConfig implements Cloneable { * ../glibc-2.10.1/configure \ --prefix=/usr \ --with-headers=/usr/include \ * --host=x86_64-linux-gnu \ --build=x86_64-pc-linux-gnu \ --without-gd */ + // 是否启用Epoll I/O模型,Linux环境下建议开启。 private boolean useEpollNativeSelector = false; public int getListenPort() { From b5d5b0da4c17577740a4ccfcf2bd404bd5f225b2 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sun, 8 Oct 2023 16:53:47 +0800 Subject: [PATCH 02/18] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E5=8F=91=E9=80=81=E6=B5=81=E7=A8=8B=E4=BB=A3=E7=A0=81=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AbstractSendMessageProcessor.java | 3 + .../apache/rocketmq/client/ClientConfig.java | 13 ++ .../org/apache/rocketmq/client/MQAdmin.java | 7 + .../apache/rocketmq/client/Validators.java | 4 + .../rocketmq/client/impl/MQClientAPIImpl.java | 6 + .../rocketmq/client/impl/MQClientManager.java | 7 + .../client/impl/factory/MQClientInstance.java | 12 +- .../impl/producer/DefaultMQProducerImpl.java | 47 ++++- .../impl/producer/TopicPublishInfo.java | 24 +++ .../client/latency/LatencyFaultTolerance.java | 13 ++ .../latency/LatencyFaultToleranceImpl.java | 17 ++ .../client/latency/MQFaultStrategy.java | 18 +- .../client/producer/DefaultMQProducer.java | 8 + .../rocketmq/client/producer/MQProducer.java | 160 ++++++++++++++++++ .../rocketmq/common/message/Message.java | 19 +++ 15 files changed, 355 insertions(+), 3 deletions(-) diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java index b0668d49f87..08769e52c9c 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java @@ -164,6 +164,7 @@ protected RemotingCommand msgContentCheck(final ChannelHandlerContext ctx, protected RemotingCommand msgCheck(final ChannelHandlerContext ctx, final SendMessageRequestHeader requestHeader, final RemotingCommand response) { + // 检查broker是否有写权限 if (!PermName.isWriteable(this.brokerController.getBrokerConfig().getBrokerPermission()) && this.brokerController.getTopicConfigManager().isOrderTopic(requestHeader.getTopic())) { response.setCode(ResponseCode.NO_PERMISSION); @@ -171,6 +172,7 @@ protected RemotingCommand msgCheck(final ChannelHandlerContext ctx, + "] sending message is forbidden"); return response; } + // 检查topic是否可以进行消息发送。主要针对默认主题,默认主题不能发送消息,仅供路由查找。 if (!this.brokerController.getTopicConfigManager().isTopicCanSendMessage(requestHeader.getTopic())) { String errorMsg = "the topic[" + requestHeader.getTopic() + "] is conflict with system reserved words."; log.warn(errorMsg); @@ -215,6 +217,7 @@ protected RemotingCommand msgCheck(final ChannelHandlerContext ctx, } } + // 校验队列ID是否合法 int queueIdInt = requestHeader.getQueueId(); int idValid = Math.max(topicConfig.getWriteQueueNums(), topicConfig.getReadQueueNums()); if (queueIdInt >= idValid) { diff --git a/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java b/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java index d0ae5e1b831..d7edd6fd353 100644 --- a/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java +++ b/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java @@ -62,6 +62,18 @@ public class ClientConfig { private LanguageCode language = LanguageCode.JAVA; + /** + * clientId为客户端IP+instance+unitname(可选),如果在同一 + * 台物理服务器部署两个应用程序,应用程序的clientId岂不是相同, + * 这样是不是会造成混乱? + * + * 为了避免出现这个问题,如果instance为默认值DEFAULT, + * RocketMQ会自动将instance设置为进程ID,这样就避免了不同进程相 + * 互影响,但同一个JVM中相同clientId的消费者和生产者在启动时获取 + * 的MQClientInstane实例都是同一个。 + * + * @return + */ public String buildMQClientId() { StringBuilder sb = new StringBuilder(); sb.append(this.getClientIP()); @@ -94,6 +106,7 @@ public void setInstanceName(String instanceName) { public void changeInstanceNameToPID() { if (this.instanceName.equals("DEFAULT")) { + // 如果 instanceName为 DEFAULT, 则将其设置为PID this.instanceName = String.valueOf(UtilAll.getPid()); } } diff --git a/client/src/main/java/org/apache/rocketmq/client/MQAdmin.java b/client/src/main/java/org/apache/rocketmq/client/MQAdmin.java index 63b2d14531d..1e011d78be1 100644 --- a/client/src/main/java/org/apache/rocketmq/client/MQAdmin.java +++ b/client/src/main/java/org/apache/rocketmq/client/MQAdmin.java @@ -27,6 +27,7 @@ */ public interface MQAdmin { /** + * 创建主题 * Creates an topic * * @param key accesskey @@ -48,6 +49,7 @@ void createTopic(String key, String newTopic, int queueNum, int topicSysFlag) throws MQClientException; /** + * 根据时间戳从队列中查找其偏移量 * Gets the message queue offset according to some time in milliseconds
* be cautious to call because of more IO overhead * @@ -58,6 +60,7 @@ void createTopic(String key, String newTopic, int queueNum, int topicSysFlag) long searchOffset(final MessageQueue mq, final long timestamp) throws MQClientException; /** + * 查找该消息队列中最大的物理偏移量 * Gets the max offset * * @param mq Instance of MessageQueue @@ -66,6 +69,7 @@ void createTopic(String key, String newTopic, int queueNum, int topicSysFlag) long maxOffset(final MessageQueue mq) throws MQClientException; /** + * 查找该消息队列中的最小物理偏移量。 * Gets the minimum offset * * @param mq Instance of MessageQueue @@ -82,6 +86,7 @@ void createTopic(String key, String newTopic, int queueNum, int topicSysFlag) long earliestMsgStoreTime(final MessageQueue mq) throws MQClientException; /** + * 根据消息偏移量查找消息。 * Query message according to message id * * @param offsetMsgId message id @@ -91,6 +96,7 @@ MessageExt viewMessage(final String offsetMsgId) throws RemotingException, MQBro InterruptedException, MQClientException; /** + * 根据条件查询消息 * Query messages * * @param topic message topic @@ -104,6 +110,7 @@ QueryResult queryMessage(final String topic, final String key, final int maxNum, final long end) throws MQClientException, InterruptedException; /** + * 根据主题与消息ID查找消息。 * @return The {@code MessageExt} of given msgId */ MessageExt viewMessage(String topic, diff --git a/client/src/main/java/org/apache/rocketmq/client/Validators.java b/client/src/main/java/org/apache/rocketmq/client/Validators.java index 1b96cd058ff..63e063a4ef8 100644 --- a/client/src/main/java/org/apache/rocketmq/client/Validators.java +++ b/client/src/main/java/org/apache/rocketmq/client/Validators.java @@ -78,6 +78,8 @@ public static boolean regularExpressionMatcher(String origin, Pattern pattern) { } /** + * 验证消息是否符合相应的规范。具体的规范要求是主题名称、消息体不能为空, + * 消息长度不能等于0且默认不能超过允许发送消息的最大长度4MB(maxMessageSize=1024×1024×4) * Validate message */ public static void checkMessage(Message msg, DefaultMQProducer defaultMQProducer) @@ -89,10 +91,12 @@ public static void checkMessage(Message msg, DefaultMQProducer defaultMQProducer Validators.checkTopic(msg.getTopic()); // body + // 消息不能为空 if (null == msg.getBody()) { throw new MQClientException(ResponseCode.MESSAGE_ILLEGAL, "the message body is null"); } + // 校验消息长度 if (0 == msg.getBody().length) { throw new MQClientException(ResponseCode.MESSAGE_ILLEGAL, "the message body length is zero"); } diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java index 1ad5fbfe6fd..116bc4d5610 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java @@ -461,6 +461,7 @@ public SendResult sendMessage( SendMessageRequestHeaderV2 requestHeaderV2 = SendMessageRequestHeaderV2.createSendMessageRequestHeaderV2(requestHeader); request = RemotingCommand.createRequestCommand(msg instanceof MessageBatch ? RequestCode.SEND_BATCH_MESSAGE : RequestCode.SEND_MESSAGE_V2, requestHeaderV2); } else { + // 构建远程调用命令, SEND_MESSAGE代表单条消息发送 request = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader); } } @@ -476,6 +477,7 @@ public SendResult sendMessage( if (timeoutMillis < costTimeAsync) { throw new RemotingTooMuchRequestException("sendMessage call timeout"); } + // 使用Netty API,发送异步请求 this.sendMessageAsync(addr, brokerName, msg, timeoutMillis - costTimeAsync, request, sendCallback, topicPublishInfo, instance, retryTimesWhenSendFailed, times, context, producer); return null; @@ -484,6 +486,7 @@ public SendResult sendMessage( if (timeoutMillis < costTimeSync) { throw new RemotingTooMuchRequestException("sendMessage call timeout"); } + // 使用Netty API,发送同步请求 return this.sendMessageSync(addr, brokerName, msg, timeoutMillis - costTimeSync, request); default: assert false; @@ -1364,8 +1367,11 @@ public TopicRouteData getTopicRouteInfoFromNameServer(final String topic, final GetRouteInfoRequestHeader requestHeader = new GetRouteInfoRequestHeader(); requestHeader.setTopic(topic); + // 创建与NameServer通讯的 消息内容,GET_ROUTEINTO_BY_TOPIC 代表查询 TOPIC 路由信息, + // NameServer中 org.apache.rocketmq.namesrv.processor.DefaultRequestProcessor.processRequest 会处理该请求 RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ROUTEINTO_BY_TOPIC, requestHeader); + // 底层使用 netty连接NameServer,并发送查询请求 RemotingCommand response = this.remotingClient.invokeSync(null, request, timeoutMillis); assert response != null; switch (response.getCode()) { diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientManager.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientManager.java index 053c049c9cd..4046e6c954b 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientManager.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientManager.java @@ -44,7 +44,14 @@ public MQClientInstance getOrCreateMQClientInstance(final ClientConfig clientCon return getOrCreateMQClientInstance(clientConfig, null); } + /** + * 创建MQClientInstance实例。同一个clientId只会创建一个MQClientInstance实例 + * @param clientConfig + * @param rpcHook + * @return + */ public MQClientInstance getOrCreateMQClientInstance(final ClientConfig clientConfig, RPCHook rpcHook) { + // 生成clientId String clientId = clientConfig.buildMQClientId(); MQClientInstance instance = this.factoryTable.get(clientId); if (null == instance) { diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java index bbd2eecb1c3..0089df09382 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java @@ -85,6 +85,9 @@ import org.apache.rocketmq.remoting.netty.NettyClientConfig; import org.apache.rocketmq.remoting.protocol.RemotingCommand; +/** + * MQClientInstance封装了RocketMQ的网络处理API,是消息生产者、消息消费者与NameServer、Broker打交道的网络通道。 + */ public class MQClientInstance { private final static long LOCK_TIMEOUT_MILLIS = 3000; private final InternalLogger log = ClientLogger.getLog(); @@ -611,6 +614,7 @@ public boolean updateTopicRouteInfoFromNameServer(final String topic, boolean is try { TopicRouteData topicRouteData; if (isDefault && defaultMQProducer != null) { + // 封装网络请求,连接NameServer查询 默认TOPIC 对应的路由信息 topicRouteData = this.mQClientAPIImpl.getDefaultTopicRouteInfoFromNameServer(defaultMQProducer.getCreateTopicKey(), 1000 * 3); if (topicRouteData != null) { @@ -621,6 +625,7 @@ public boolean updateTopicRouteInfoFromNameServer(final String topic, boolean is } } } else { + // 封装网络请求,连接NameServer查询 TOPIC 对应的路由信息 topicRouteData = this.mQClientAPIImpl.getTopicRouteInfoFromNameServer(topic, 1000 * 3); } if (topicRouteData != null) { @@ -633,14 +638,18 @@ public boolean updateTopicRouteInfoFromNameServer(final String topic, boolean is } if (changed) { - TopicRouteData cloneTopicRouteData = topicRouteData.cloneTopicRouteData(); + // 如果topic路由信息发生变更 + TopicRouteData cloneTopicRouteData = topicRouteData.cloneTopicRouteData(); for (BrokerData bd : topicRouteData.getBrokerDatas()) { + // 更新Broker地址缓存表 this.brokerAddrTable.put(bd.getBrokerName(), bd.getBrokerAddrs()); } // Update Pub info + // 更新生产端缓存 { + // 将topicRouteData中的List 转换成 topicPublishInfo的List 列表 TopicPublishInfo publishInfo = topicRouteData2TopicPublishInfo(topic, topicRouteData); publishInfo.setHaveTopicRouterInfo(true); Iterator> it = this.producerTable.entrySet().iterator(); @@ -654,6 +663,7 @@ public boolean updateTopicRouteInfoFromNameServer(final String topic, boolean is } // Update sub info + // 更新消费端缓存 { Set subscribeInfo = topicRouteData2TopicSubscribeInfo(topic, topicRouteData); Iterator> it = this.consumerTable.entrySet().iterator(); diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java index fca50cc565c..1bdb535b7e2 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java @@ -183,11 +183,14 @@ public void start(final boolean startFactory) throws MQClientException { this.checkConfig(); if (!this.defaultMQProducer.getProducerGroup().equals(MixAll.CLIENT_INNER_PRODUCER_GROUP)) { + // 检查producerGroup是否符合要求,改变生产者的instanceName为进程ID this.defaultMQProducer.changeInstanceNameToPID(); } + // 生成或者获取 MQClientInstance 实例,它是RocketMQ的网络处理API,是消息生产者、消息消费者与NameServer、Broker打交道的网络通道 this.mQClientFactory = MQClientManager.getInstance().getOrCreateMQClientInstance(this.defaultMQProducer, rpcHook); + // 向MQClientInstance注册服务,将当前生产者加入MQClientInstance管理,方便后续调用网络请求、进行心跳检测等。 boolean registerOK = mQClientFactory.registerProducer(this.defaultMQProducer.getProducerGroup(), this); if (!registerOK) { this.serviceState = ServiceState.CREATE_JUST; @@ -199,6 +202,7 @@ public void start(final boolean startFactory) throws MQClientException { this.topicPublishInfoTable.put(this.defaultMQProducer.getCreateTopicKey(), new TopicPublishInfo()); if (startFactory) { + // 启动MQClientInstance,如果MQClientInstance已经启动,则本次启动不会真正执行。 mQClientFactory.start(); } @@ -553,6 +557,7 @@ private SendResult sendDefaultImpl( long beginTimestampFirst = System.currentTimeMillis(); long beginTimestampPrev = beginTimestampFirst; long endTimestamp = beginTimestampFirst; + // 查询topic对应的路由信息 TopicPublishInfo topicPublishInfo = this.tryToFindTopicPublishInfo(msg.getTopic()); if (topicPublishInfo != null && topicPublishInfo.ok()) { boolean callTimeout = false; @@ -564,6 +569,7 @@ private SendResult sendDefaultImpl( String[] brokersSent = new String[timesTotal]; for (; times < timesTotal; times++) { String lastBrokerName = null == mq ? null : mq.getBrokerName(); + // 选择一个消息队列 MessageQueue mqSelected = this.selectOneMessageQueue(topicPublishInfo, lastBrokerName); if (mqSelected != null) { mq = mqSelected; @@ -579,9 +585,10 @@ private SendResult sendDefaultImpl( callTimeout = true; break; } - + // 发送消息 sendResult = this.sendKernelImpl(msg, mq, communicationMode, sendCallback, topicPublishInfo, timeout - costTime); endTimestamp = System.currentTimeMillis(); + // 使用本次消息发送延迟时间来计算Broker故障规避时长 this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false); switch (communicationMode) { case ASYNC: @@ -601,6 +608,7 @@ private SendResult sendDefaultImpl( } } catch (RemotingException e) { endTimestamp = System.currentTimeMillis(); + // 若消息发送失败,则更新失败条目,使用默认时长30s来计算Broker故障规避时长 this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true); log.warn(String.format("sendKernelImpl exception, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e); log.warn(msg.toString()); @@ -685,10 +693,20 @@ private SendResult sendDefaultImpl( null).setResponseCode(ClientErrorCode.NOT_FOUND_TOPIC_EXCEPTION); } + /** + * 如果生产者中缓存了topic的路由信息,且该路由信息包含消息队列,则直 + * 接返回该路由信息。如果没有缓存或没有包含消息队列,则向 + * NameServer查询该topic的路由信息。如果最终未找到路由信息,则抛 + * 出异常,表示无法找到主题相关路由信息异常。 + * @param topic + * @return + */ private TopicPublishInfo tryToFindTopicPublishInfo(final String topic) { + // 先查本地缓存 TopicPublishInfo topicPublishInfo = this.topicPublishInfoTable.get(topic); if (null == topicPublishInfo || !topicPublishInfo.ok()) { this.topicPublishInfoTable.putIfAbsent(topic, new TopicPublishInfo()); + // 如果本地缓存没有该topic路由信息,则查询NameServer并更新本地缓存 this.mQClientFactory.updateTopicRouteInfoFromNameServer(topic); topicPublishInfo = this.topicPublishInfoTable.get(topic); } @@ -696,12 +714,27 @@ private TopicPublishInfo tryToFindTopicPublishInfo(final String topic) { if (topicPublishInfo.isHaveTopicRouterInfo() || topicPublishInfo.ok()) { return topicPublishInfo; } else { + // 如果是新创建的 Topic,NameServer中不会有Topic信息,则会加载 默认的Topic路由信息 this.mQClientFactory.updateTopicRouteInfoFromNameServer(topic, true, this.defaultMQProducer); topicPublishInfo = this.topicPublishInfoTable.get(topic); return topicPublishInfo; } } + /** + * + * @param msg 待发送消息 + * @param mq 消息将发送到该消息队列上 + * @param communicationMode 消息发送模式,包括SYNC、ASYNC、ONEWAY + * @param sendCallback 异步消息回调函数 + * @param topicPublishInfo 主题路由信息 + * @param timeout 消息发送超时时间 + * @return + * @throws MQClientException + * @throws RemotingException + * @throws MQBrokerException + * @throws InterruptedException + */ private SendResult sendKernelImpl(final Message msg, final MessageQueue mq, final CommunicationMode communicationMode, @@ -709,8 +742,11 @@ private SendResult sendKernelImpl(final Message msg, final TopicPublishInfo topicPublishInfo, final long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { long beginStartTime = System.currentTimeMillis(); + + // 从本地缓存中,获取broker的网络地址 String brokerAddr = this.mQClientFactory.findBrokerAddressInPublish(mq.getBrokerName()); if (null == brokerAddr) { + // 去NameServer中加载Topic路由信息,然后获取broker网络地址 tryToFindTopicPublishInfo(mq.getTopic()); brokerAddr = this.mQClientFactory.findBrokerAddressInPublish(mq.getBrokerName()); } @@ -722,6 +758,7 @@ private SendResult sendKernelImpl(final Message msg, byte[] prevBody = msg.getBody(); try { //for MessageBatch,ID has been set in the generating process + // 为消息分配全局唯一ID if (!(msg instanceof MessageBatch)) { MessageClientIDSetter.setUniqID(msg); } @@ -734,6 +771,7 @@ private SendResult sendKernelImpl(final Message msg, int sysFlag = 0; boolean msgBodyCompressed = false; + // 如果消息体默认超过4KB(compressMsgBody-OverHowmuch),则对消息体采用zip压缩,并置消息的系统标记为MessageSysFlag.COMPRESSED_FLAG。 if (this.tryToCompressMessage(msg)) { sysFlag |= MessageSysFlag.COMPRESSED_FLAG; msgBodyCompressed = true; @@ -757,6 +795,8 @@ private SendResult sendKernelImpl(final Message msg, } if (this.hasSendMessageHook()) { + // 如果注册了消息发送钩子函数,则执行消息发送之前的增强逻辑 + // 通过DefaultMQProducerImpl#registerSendMessageHook注册钩子处理类,并且可以注册多个 context = new SendMessageContext(); context.setProducer(this); context.setProducerGroup(this.defaultMQProducer.getProducerGroup()); @@ -777,11 +817,14 @@ private SendResult sendKernelImpl(final Message msg, this.executeSendMessageHookBefore(context); } + /**构建消息发送请求包**/ SendMessageRequestHeader requestHeader = new SendMessageRequestHeader(); + // 生成者组 requestHeader.setProducerGroup(this.defaultMQProducer.getProducerGroup()); requestHeader.setTopic(msg.getTopic()); requestHeader.setDefaultTopic(this.defaultMQProducer.getCreateTopicKey()); requestHeader.setDefaultTopicQueueNums(this.defaultMQProducer.getDefaultTopicQueueNums()); + // 队列ID requestHeader.setQueueId(mq.getQueueId()); requestHeader.setSysFlag(sysFlag); requestHeader.setBornTimestamp(System.currentTimeMillis()); @@ -850,6 +893,7 @@ private SendResult sendKernelImpl(final Message msg, if (timeout < costTimeSync) { throw new RemotingTooMuchRequestException("sendKernelImpl call timeout"); } + // 发送消息 sendResult = this.mQClientFactory.getMQClientAPIImpl().sendMessage( brokerAddr, mq.getBrokerName(), @@ -866,6 +910,7 @@ private SendResult sendKernelImpl(final Message msg, } if (this.hasSendMessageHook()) { + // 如果注册消息发送钩子函数,则在发送完毕后,执行后置操作 context.setSendResult(sendResult); this.executeSendMessageHookAfter(context); } diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/producer/TopicPublishInfo.java b/client/src/main/java/org/apache/rocketmq/client/impl/producer/TopicPublishInfo.java index deb02cff285..94f0d5ebc51 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/producer/TopicPublishInfo.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/producer/TopicPublishInfo.java @@ -24,10 +24,23 @@ import org.apache.rocketmq.common.protocol.route.TopicRouteData; public class TopicPublishInfo { + + /** + * 是否是顺序消息 + */ private boolean orderTopic = false; private boolean haveTopicRouterInfo = false; + /** + * 该Topic的队列信息 + */ private List messageQueueList = new ArrayList(); + /** + * 每选择一次消息队列,该值会自增1,如果超过Integer.MAX_VALUE,则重置为0,用于选择消息队列。 + */ private volatile ThreadLocalIndex sendWhichQueue = new ThreadLocalIndex(); + /** + * Topic路由相关信息 + */ private TopicRouteData topicRouteData; public boolean isOrderTopic() { @@ -68,8 +81,14 @@ public void setHaveTopicRouterInfo(boolean haveTopicRouterInfo) { public MessageQueue selectOneMessageQueue(final String lastBrokerName) { if (lastBrokerName == null) { + // 在消息发送过程中,可能会多次执行选择消息队列这个方法, + //lastBrokerName就是上一次选择的执行发送消息失败的Broker。第一 + //次执行消息队列选择时,lastBrokerName为null,此时直接用 + //sendWhichQueue自增再获取值,与当前路由表中消息队列的个数取 + //模,返回该位置的MessageQueue(selectOneMessageQueue()方法 return selectOneMessageQueue(); } else { + //如果消息发送失败,下次进行消息队列选择时规避上次MesageQueue所在的Broker,否则有可能再次失败。 int index = this.sendWhichQueue.getAndIncrement(); for (int i = 0; i < this.messageQueueList.size(); i++) { int pos = Math.abs(index++) % this.messageQueueList.size(); @@ -80,10 +99,15 @@ public MessageQueue selectOneMessageQueue(final String lastBrokerName) { return mq; } } + // 如果没有找到其它broker上的队列,则降级为默认逻辑,轮询获取下一个队列信息。 return selectOneMessageQueue(); } } + /** + * 轮询选择消息队列 + * @return + */ public MessageQueue selectOneMessageQueue() { int index = this.sendWhichQueue.getAndIncrement(); int pos = Math.abs(index) % this.messageQueueList.size(); diff --git a/client/src/main/java/org/apache/rocketmq/client/latency/LatencyFaultTolerance.java b/client/src/main/java/org/apache/rocketmq/client/latency/LatencyFaultTolerance.java index 09a8aa46189..53275a1ff88 100644 --- a/client/src/main/java/org/apache/rocketmq/client/latency/LatencyFaultTolerance.java +++ b/client/src/main/java/org/apache/rocketmq/client/latency/LatencyFaultTolerance.java @@ -20,9 +20,22 @@ public interface LatencyFaultTolerance { void updateFaultItem(final T name, final long currentLatency, final long notAvailableDuration); + /** + * 判断Broker是否可用 + * @param name + * @return + */ boolean isAvailable(final T name); + /** + * 移除失败条目,意味着Broker重新参与路由计算 + * @param name + */ void remove(final T name); + /** + * 尝试从规避的Broker中选择一个可用的Broker,如果没有找到,则返回null。 + * @return + */ T pickOneAtLeast(); } diff --git a/client/src/main/java/org/apache/rocketmq/client/latency/LatencyFaultToleranceImpl.java b/client/src/main/java/org/apache/rocketmq/client/latency/LatencyFaultToleranceImpl.java index 72d43476f83..d95a42c4bac 100644 --- a/client/src/main/java/org/apache/rocketmq/client/latency/LatencyFaultToleranceImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/latency/LatencyFaultToleranceImpl.java @@ -25,6 +25,10 @@ import org.apache.rocketmq.client.common.ThreadLocalIndex; public class LatencyFaultToleranceImpl implements LatencyFaultTolerance { + + /** + * 失败条目(规避规则条目) + */ private final ConcurrentHashMap faultItemTable = new ConcurrentHashMap(16); private final ThreadLocalIndex whichItemWorst = new ThreadLocalIndex(); @@ -96,9 +100,22 @@ public String toString() { '}'; } + /** + * 失败条目(规避规则条目) + */ class FaultItem implements Comparable { + + /** + * 条目唯一键,这里为brokerName + */ private final String name; + /** + * 本次消息发送的延迟时间 + */ private volatile long currentLatency; + /** + * 故障恢复的开始时间 + */ private volatile long startTimestamp; public FaultItem(final String name) { diff --git a/client/src/main/java/org/apache/rocketmq/client/latency/MQFaultStrategy.java b/client/src/main/java/org/apache/rocketmq/client/latency/MQFaultStrategy.java index 7854fcb7d10..f397118b03a 100644 --- a/client/src/main/java/org/apache/rocketmq/client/latency/MQFaultStrategy.java +++ b/client/src/main/java/org/apache/rocketmq/client/latency/MQFaultStrategy.java @@ -26,6 +26,18 @@ public class MQFaultStrategy { private final static InternalLogger log = ClientLogger.getLog(); private final LatencyFaultTolerance latencyFaultTolerance = new LatencyFaultToleranceImpl(); + /** + * 是否启用Broker故障延迟机制 + * 开启与不开启sendLatencyFaultEnable机制在消息发送时都能规避故 + * 障的Broker,那么这两种机制有何区别呢? + * + * 开启所谓的故障延迟机制,即设置sendLatencyFaultEnable为ture, + * 其实是一种较为悲观的做法。当消息发送者遇到一次消息发送失败 + * 后,就会悲观地认为Broker不可用,在接下来的一段时间内就不再向 + * 其发送消息,直接避开该Broker。而不开启延迟规避机制,就只会在 + * 本次消息发送的重试过程中规避该Broker,下一次消息发送还是会继 + * 续尝试。 + */ private boolean sendLatencyFaultEnable = false; private long[] latencyMax = {50L, 100L, 550L, 1000L, 2000L, 3000L, 15000L}; @@ -57,13 +69,16 @@ public void setSendLatencyFaultEnable(final boolean sendLatencyFaultEnable) { public MessageQueue selectOneMessageQueue(final TopicPublishInfo tpInfo, final String lastBrokerName) { if (this.sendLatencyFaultEnable) { + // 如果开启了故障延迟机制 try { int index = tpInfo.getSendWhichQueue().getAndIncrement(); for (int i = 0; i < tpInfo.getMessageQueueList().size(); i++) { int pos = Math.abs(index++) % tpInfo.getMessageQueueList().size(); if (pos < 0) pos = 0; + // 获取一个消息队列 MessageQueue mq = tpInfo.getMessageQueueList().get(pos); + // 验证该消息队列是否可用 if (latencyFaultTolerance.isAvailable(mq.getBrokerName())) { if (null == lastBrokerName || mq.getBrokerName().equals(lastBrokerName)) return mq; @@ -80,6 +95,7 @@ public MessageQueue selectOneMessageQueue(final TopicPublishInfo tpInfo, final S } return mq; } else { + // 移除失败条目,意味着Broker重新参与路由计算 latencyFaultTolerance.remove(notBestBroker); } } catch (Exception e) { @@ -88,7 +104,7 @@ public MessageQueue selectOneMessageQueue(final TopicPublishInfo tpInfo, final S return tpInfo.selectOneMessageQueue(); } - + // 未开启故障延迟机制 return tpInfo.selectOneMessageQueue(lastBrokerName); } diff --git a/client/src/main/java/org/apache/rocketmq/client/producer/DefaultMQProducer.java b/client/src/main/java/org/apache/rocketmq/client/producer/DefaultMQProducer.java index faa79f54c93..62ca705d2ea 100644 --- a/client/src/main/java/org/apache/rocketmq/client/producer/DefaultMQProducer.java +++ b/client/src/main/java/org/apache/rocketmq/client/producer/DefaultMQProducer.java @@ -62,6 +62,7 @@ public class DefaultMQProducer extends ClientConfig implements MQProducer { protected final transient DefaultMQProducerImpl defaultMQProducerImpl; private final InternalLogger log = ClientLogger.getLog(); /** + * 生产者所属的组 * Producer group conceptually aggregates all producer instances of exactly same role, which is particularly * important when transactional messages are involved.

* @@ -77,21 +78,25 @@ public class DefaultMQProducer extends ClientConfig implements MQProducer { private String createTopicKey = MixAll.AUTO_CREATE_TOPIC_KEY_TOPIC; /** + * 默认主题在每一个Broker队列的数量。 * Number of queues to create per default topic. */ private volatile int defaultTopicQueueNums = 4; /** + * 发送消息的超时时间,默认为3s。 * Timeout for sending messages. */ private int sendMsgTimeout = 3000; /** + * 消息体超过该值则启用压缩,默认为4KB。 * Compress message body threshold, namely, message body larger than 4k will be compressed on default. */ private int compressMsgBodyOverHowmuch = 1024 * 4; /** + * 同步方式发送消息重试次数,默认为2,总共执行3次。 * Maximum number of retry to perform internally before claiming sending failure in synchronous mode.

* * This may potentially cause message duplication which is up to application developers to resolve. @@ -99,6 +104,7 @@ public class DefaultMQProducer extends ClientConfig implements MQProducer { private int retryTimesWhenSendFailed = 2; /** + * 异步方式发送消息的重试次数,默认为2。 * Maximum number of retry to perform internally before claiming sending failure in asynchronous mode.

* * This may potentially cause message duplication which is up to application developers to resolve. @@ -106,11 +112,13 @@ public class DefaultMQProducer extends ClientConfig implements MQProducer { private int retryTimesWhenSendAsyncFailed = 2; /** + * 消息重试时选择另外一个Broker,是否不等待存储结果就返回,默认为false。 * Indicate whether to retry another broker on sending failure internally. */ private boolean retryAnotherBrokerWhenNotStoreOK = false; /** + * 允许发送的最大消息长度,默认为4MB,最大值为2^32-1。 * Maximum allowed message size in bytes. */ private int maxMessageSize = 1024 * 1024 * 4; // 4M diff --git a/client/src/main/java/org/apache/rocketmq/client/producer/MQProducer.java b/client/src/main/java/org/apache/rocketmq/client/producer/MQProducer.java index c6cf4c93596..70222b243b4 100644 --- a/client/src/main/java/org/apache/rocketmq/client/producer/MQProducer.java +++ b/client/src/main/java/org/apache/rocketmq/client/producer/MQProducer.java @@ -31,53 +31,204 @@ public interface MQProducer extends MQAdmin { void shutdown(); + /** + * 查找该主题下所有的消息队列。 + * @param topic + * @return + * @throws MQClientException + */ List fetchPublishMessageQueues(final String topic) throws MQClientException; + + /** + * 同步发送消息,具体发送到主题中的哪个消息队列由负载算法决定 + * @param msg + * @return + * @throws MQClientException + * @throws RemotingException + * @throws MQBrokerException + * @throws InterruptedException + */ SendResult send(final Message msg) throws MQClientException, RemotingException, MQBrokerException, InterruptedException; + /** + * 同步发送消息,如果发送超过timeout则抛出超时异常。 + * @param msg + * @param timeout + * @return + * @throws MQClientException + * @throws RemotingException + * @throws MQBrokerException + * @throws InterruptedException + */ SendResult send(final Message msg, final long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException; + /** + * 异步发送消息,sendCallback参数是消息发送成功后的回调方法。 + * @param msg + * @param sendCallback + * @throws MQClientException + * @throws RemotingException + * @throws InterruptedException + */ void send(final Message msg, final SendCallback sendCallback) throws MQClientException, RemotingException, InterruptedException; + /** + * 异步发送消息,如果发送超过timeout则抛出超时异常。 + * @param msg + * @param sendCallback + * @param timeout + * @throws MQClientException + * @throws RemotingException + * @throws InterruptedException + */ void send(final Message msg, final SendCallback sendCallback, final long timeout) throws MQClientException, RemotingException, InterruptedException; + /** + * 单向消息发送,即不在乎发送结果,消息发送出去后该方法立即返回。 + * @param msg + * @throws MQClientException + * @throws RemotingException + * @throws InterruptedException + */ void sendOneway(final Message msg) throws MQClientException, RemotingException, InterruptedException; + /** + * 同步方式发送消息,且发送到指定的消息队列。 + * @param msg + * @param mq + * @return + * @throws MQClientException + * @throws RemotingException + * @throws MQBrokerException + * @throws InterruptedException + */ SendResult send(final Message msg, final MessageQueue mq) throws MQClientException, RemotingException, MQBrokerException, InterruptedException; + /** + * 同步方式发送消息,且发送到指定的消息队列,超时抛异常。 + * @param msg + * @param mq + * @param timeout + * @return + * @throws MQClientException + * @throws RemotingException + * @throws MQBrokerException + * @throws InterruptedException + */ SendResult send(final Message msg, final MessageQueue mq, final long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException; + /** + * 异步方式发送消息,且发送到指定的消息队列。 + * @param msg + * @param mq + * @param sendCallback + * @throws MQClientException + * @throws RemotingException + * @throws InterruptedException + */ void send(final Message msg, final MessageQueue mq, final SendCallback sendCallback) throws MQClientException, RemotingException, InterruptedException; + /** + * 异步方式发送消息,且发送到指定的消息队列,超时抛异常。 + * @param msg + * @param mq + * @param sendCallback + * @param timeout + * @throws MQClientException + * @throws RemotingException + * @throws InterruptedException + */ void send(final Message msg, final MessageQueue mq, final SendCallback sendCallback, long timeout) throws MQClientException, RemotingException, InterruptedException; + /** + * 单向方式发送消息,且发送到指定的消息队列。 + * @param msg + * @param mq + * @throws MQClientException + * @throws RemotingException + * @throws InterruptedException + */ void sendOneway(final Message msg, final MessageQueue mq) throws MQClientException, RemotingException, InterruptedException; + /** + * 同步消息发送,指定消息选择算法,覆盖消息生产者默认的消息队列负载。 + * @param msg + * @param selector + * @param arg + * @return + * @throws MQClientException + * @throws RemotingException + * @throws MQBrokerException + * @throws InterruptedException + */ SendResult send(final Message msg, final MessageQueueSelector selector, final Object arg) throws MQClientException, RemotingException, MQBrokerException, InterruptedException; + /** + * 同步消息发送,指定消息选择算法,覆盖消息生产者默认的消息队列负载,超时抛出异常。 + * @param msg + * @param selector + * @param arg + * @param timeout + * @return + * @throws MQClientException + * @throws RemotingException + * @throws MQBrokerException + * @throws InterruptedException + */ SendResult send(final Message msg, final MessageQueueSelector selector, final Object arg, final long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException; + /** + * 异步消息发送,指定消息选择算法,覆盖消息生产者默认的消息队列负载。 + * @param msg + * @param selector + * @param arg + * @param sendCallback + * @throws MQClientException + * @throws RemotingException + * @throws InterruptedException + */ void send(final Message msg, final MessageQueueSelector selector, final Object arg, final SendCallback sendCallback) throws MQClientException, RemotingException, InterruptedException; + /** + * 异步消息发送,指定消息选择算法,覆盖消息生产者默认的消息队列负载,超时抛出异常。 + * @param msg + * @param selector + * @param arg + * @param sendCallback + * @param timeout + * @throws MQClientException + * @throws RemotingException + * @throws InterruptedException + */ void send(final Message msg, final MessageQueueSelector selector, final Object arg, final SendCallback sendCallback, final long timeout) throws MQClientException, RemotingException, InterruptedException; + /** + * 同步单向方式发送消息,指定消息选择算法。 + * @param msg + * @param selector + * @param arg + * @throws MQClientException + * @throws RemotingException + * @throws InterruptedException + */ void sendOneway(final Message msg, final MessageQueueSelector selector, final Object arg) throws MQClientException, RemotingException, InterruptedException; @@ -88,6 +239,15 @@ TransactionSendResult sendMessageInTransaction(final Message msg, final Object arg) throws MQClientException; //for batch + /** + * 同步批量发送消息 + * @param msgs + * @return + * @throws MQClientException + * @throws RemotingException + * @throws MQBrokerException + * @throws InterruptedException + */ SendResult send(final Collection msgs) throws MQClientException, RemotingException, MQBrokerException, InterruptedException; diff --git a/common/src/main/java/org/apache/rocketmq/common/message/Message.java b/common/src/main/java/org/apache/rocketmq/common/message/Message.java index c9a133b4d0c..19b8b212608 100644 --- a/common/src/main/java/org/apache/rocketmq/common/message/Message.java +++ b/common/src/main/java/org/apache/rocketmq/common/message/Message.java @@ -22,13 +22,29 @@ import java.util.HashMap; import java.util.Map; +/** + * RocketMQ消息封装类 + */ public class Message implements Serializable { private static final long serialVersionUID = 8445773977080406428L; private String topic; + /** + * 消息标记(RocketMQ不做处理) + */ private int flag; + /** + * 消息扩展信息 + * 消息tag、消息检索key都存在该字段里 + */ private Map properties; + /** + * 消息体 + */ private byte[] body; + /** + * 事务ID + */ private String transactionId; public Message() { @@ -43,12 +59,15 @@ public Message(String topic, String tags, String keys, int flag, byte[] body, bo this.flag = flag; this.body = body; + // 消息tag,用于消息过滤 if (tags != null && tags.length() > 0) this.setTags(tags); + // 消息索引键,用空格隔开,RocketMQ可以根据这些 key 快速检索消息 if (keys != null && keys.length() > 0) this.setKeys(keys); + // 消息发送时是否等消息存储完成后再返回 this.setWaitStoreMsgOK(waitStoreMsgOK); } From 1942f2f2c9c58753d0cc1998c674dab52436e8be Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Tue, 10 Oct 2023 19:48:08 +0800 Subject: [PATCH 03/18] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E5=AD=98=E5=82=A8=E6=B5=81=E7=A8=8B=E4=BB=A3=E7=A0=81=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../namesrv/routeinfo/RouteInfoManager.java | 4 + .../rocketmq/store/AppendMessageResult.java | 23 ++- .../org/apache/rocketmq/store/CommitLog.java | 102 +++++++++--- .../apache/rocketmq/store/ConsumeQueue.java | 45 +++++- .../rocketmq/store/DefaultMessageStore.java | 148 ++++++++++++++++++ .../rocketmq/store/DispatchRequest.java | 44 ++++++ .../org/apache/rocketmq/store/MappedFile.java | 86 +++++++++- .../rocketmq/store/MappedFileQueue.java | 78 ++++++++- .../rocketmq/store/StoreCheckpoint.java | 14 ++ .../rocketmq/store/TransientStorePool.java | 17 ++ .../store/config/MessageStoreConfig.java | 3 + .../rocketmq/store/index/IndexFile.java | 70 ++++++++- .../rocketmq/store/index/IndexHeader.java | 19 ++- .../rocketmq/store/index/IndexService.java | 12 ++ 14 files changed, 633 insertions(+), 32 deletions(-) diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java index 3c3f15cf41b..6e021ce8e7e 100644 --- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java +++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java @@ -790,6 +790,10 @@ public byte[] getHasUnitSubUnUnitTopicList() { } class BrokerLiveInfo { + + /** + * 最近一次心跳上报的时间 + */ private long lastUpdateTimestamp; private DataVersion dataVersion; private Channel channel; diff --git a/store/src/main/java/org/apache/rocketmq/store/AppendMessageResult.java b/store/src/main/java/org/apache/rocketmq/store/AppendMessageResult.java index d6d1aa6a31c..00c78a12a82 100644 --- a/store/src/main/java/org/apache/rocketmq/store/AppendMessageResult.java +++ b/store/src/main/java/org/apache/rocketmq/store/AppendMessageResult.java @@ -21,19 +21,40 @@ */ public class AppendMessageResult { // Return code + /** + * 消息追加结果。取值为PUT_OK则代表追加成功、 + * END_OF_FILE则代表超过文件大小、 + * MESSAGE_SIZE_EXCEEDED则代表消息长度超过最大允许长度、 + * PROPERTIES_SIZE_EXCEEDED则代表消息属性超过最大允许长度、 + * UNKNOWN_ERROR则代表未知异常。 + */ private AppendMessageStatus status; // Where to start writing + /** + * 消息的物理偏移量。 + */ private long wroteOffset; // Write Bytes private int wroteBytes; // Message ID private String msgId; // Message storage timestamp + /** + * 消息存储时间戳 + */ private long storeTimestamp; // Consume queue's offset(step by one) + /** + * 消息消费队列的逻辑偏移量,类似于数组下标 + */ private long logicsOffset; + /** + * 写入页缓存的响应时间 + */ private long pagecacheRT = 0; - + /** + * 批量发送消息时的消息条数 + */ private int msgNum = 1; public AppendMessageResult(AppendMessageStatus status) { diff --git a/store/src/main/java/org/apache/rocketmq/store/CommitLog.java b/store/src/main/java/org/apache/rocketmq/store/CommitLog.java index 3d89fe4c519..581ff40afa7 100644 --- a/store/src/main/java/org/apache/rocketmq/store/CommitLog.java +++ b/store/src/main/java/org/apache/rocketmq/store/CommitLog.java @@ -159,31 +159,40 @@ public SelectMappedBufferResult getData(final long offset, final boolean returnF /** * When the normal exit, data recovery, all memory data have been flush + * */ public void recoverNormally(long maxPhyOffsetOfConsumeQueue) { + // checkCRCOnRecover参数用于在进行文件恢复时查找消息是否验证CRC boolean checkCRCOnRecover = this.defaultMessageStore.getMessageStoreConfig().isCheckCRCOnRecover(); final List mappedFiles = this.mappedFileQueue.getMappedFiles(); if (!mappedFiles.isEmpty()) { // Began to recover from the last third file + // Broker正常停止再重启时,从倒数第3个文件开始恢复,如果不足3个文件,则从第一个文件开始恢复 int index = mappedFiles.size() - 3; if (index < 0) index = 0; MappedFile mappedFile = mappedFiles.get(index); ByteBuffer byteBuffer = mappedFile.sliceByteBuffer(); + // processOffset为CommitLog文件已确认的物理偏移量,等于mappedFile.getFileFromOffset加上mappedFileOffset long processOffset = mappedFile.getFileFromOffset(); + // mappedFileOffset为当前文件已校验通过的物理偏移量 long mappedFileOffset = 0; + // 遍历CommitLog文件,每次取出一条信息 while (true) { DispatchRequest dispatchRequest = this.checkMessageAndReturnSize(byteBuffer, checkCRCOnRecover); int size = dispatchRequest.getMsgSize(); // Normal data if (dispatchRequest.isSuccess() && size > 0) { + // 如果查找结果为true并且消息的长度大于0,表示消息正确,mappedFileOffset指针向前移动本条消息的长度 mappedFileOffset += size; } // Come the end of the file, switch to the next file Since the // return 0 representatives met last hole, // this can not be included in truncate offset else if (dispatchRequest.isSuccess() && size == 0) { + //如果查找结果为true并且消息的长度等于0,表示已到该文件的末尾,如果还有下一个文件,则重置 + //processOffset、mappedFileOffset并重复上述步骤,否则跳出循环 index++; if (index >= mappedFiles.size()) { // Current branch can not happen @@ -199,11 +208,13 @@ else if (dispatchRequest.isSuccess() && size == 0) { } // Intermediate file read error else if (!dispatchRequest.isSuccess()) { + // 如果查找结果为false,表明该文件未填满所有消息,则跳出循环 log.info("recover physics file end, " + mappedFile.getFileName()); break; } } + processOffset += mappedFileOffset; this.mappedFileQueue.setFlushedWhere(processOffset); this.mappedFileQueue.setCommittedWhere(processOffset); @@ -384,26 +395,34 @@ public DispatchRequest checkMessageAndReturnSize(java.nio.ByteBuffer byteBuffer, return new DispatchRequest(-1, false /* success */); } + /** + * CommitLog条目是不定长的,每一个条目的长度存储在前4个字节中。 + * @param sysFlag + * @param bodyLength 消息body长度 + * @param topicLength topic长度 + * @param propertiesLength properties长度 + * @return + */ protected static int calMsgLength(int sysFlag, int bodyLength, int topicLength, int propertiesLength) { int bornhostLength = (sysFlag & MessageSysFlag.BORNHOST_V6_FLAG) == 0 ? 8 : 20; int storehostAddressLength = (sysFlag & MessageSysFlag.STOREHOSTADDRESS_V6_FLAG) == 0 ? 8 : 20; - final int msgLen = 4 //TOTALSIZE + final int msgLen = 4 //TOTALSIZE 消息头部4字节,记录消息条目总长度 + 4 //MAGICCODE - + 4 //BODYCRC - + 4 //QUEUEID - + 4 //FLAG - + 8 //QUEUEOFFSET - + 8 //PHYSICALOFFSET - + 4 //SYSFLAG - + 8 //BORNTIMESTAMP - + bornhostLength //BORNHOST - + 8 //STORETIMESTAMP - + storehostAddressLength //STOREHOSTADDRESS - + 4 //RECONSUMETIMES - + 8 //Prepared Transaction Offset - + 4 + (bodyLength > 0 ? bodyLength : 0) //BODY - + 1 + topicLength //TOPIC - + 2 + (propertiesLength > 0 ? propertiesLength : 0) //propertiesLength + + 4 //BODYCRC 消息体的crc校验码 + + 4 //QUEUEID 消息消费队列ID + + 4 //FLAG 消息标记,RocketMQ对其不做处理,供应用程序使用, 默认4字节。 + + 8 //QUEUEOFFSET 消息在ConsumeQuene文件中的物理偏移量,8字节 + + 8 //PHYSICALOFFSET 消息在CommitLog文件中的物理偏移量,8字 节。 + + 4 //SYSFLAG 消息系统标记,例如是否压缩、是否是事务消息 等,4字节。 + + 8 //BORNTIMESTAMP 消息生产者调用消息发送API的时间戳,8字 节。 + + bornhostLength //BORNHOST 消息发送者IP、端口号,8字节。 + + 8 //STORETIMESTAMP 消息存储时间戳,8字节。 + + storehostAddressLength //STOREHOSTADDRESS Broker服务器IP+端口号,8字节。 + + 4 //RECONSUMETIMES 消息重试次数,4字节。 + + 8 //Prepared Transaction Offset 事务消息的物理偏移量,8字节 + + 4 + (bodyLength > 0 ? bodyLength : 0) //BODY 消息体长度,4字节 + 消息体内容,长度为bodyLenth中存储的值。 + + 1 + topicLength //TOPIC 主题存储长度,1字节,表示主题名称不能超 过255个字符 + Topic内容,长度为 topicLength + + 2 + (propertiesLength > 0 ? propertiesLength : 0) //propertiesLength 消息属性长度,2字节,表示消息属性长度不能超过65536个字符 + 消息属性内容 + 0; return msgLen; } @@ -552,6 +571,7 @@ public long getBeginTimeInLock() { public PutMessageResult putMessage(final MessageExtBrokerInner msg) { // Set the storage time + // 记录消息写入时间 msg.setStoreTimestamp(System.currentTimeMillis()); // Set the message body BODY CRC (consider the most appropriate setting // on the client) @@ -573,10 +593,13 @@ public PutMessageResult putMessage(final MessageExtBrokerInner msg) { msg.setDelayTimeLevel(this.defaultMessageStore.getScheduleMessageService().getMaxDelayLevel()); } + topic = ScheduleMessageService.SCHEDULE_TOPIC; queueId = ScheduleMessageService.delayLevel2QueueId(msg.getDelayTimeLevel()); // Backup real topic, queueId + // 如果消息的延迟级别大于0,将消息的原主题名称与原消息队列ID存入消息属性中,用延迟消息主题SCHEDULE_TOPIC_XXXX、消 + //息队列ID更新原先消息的主题与队列,这是并发消息重试关键的异步 MessageAccessor.putProperty(msg, MessageConst.PROPERTY_REAL_TOPIC, msg.getTopic()); MessageAccessor.putProperty(msg, MessageConst.PROPERTY_REAL_QUEUE_ID, String.valueOf(msg.getQueueId())); msg.setPropertiesString(MessageDecoder.messageProperties2String(msg.getProperties())); @@ -599,8 +622,9 @@ public PutMessageResult putMessage(final MessageExtBrokerInner msg) { long eclipsedTimeInLock = 0; MappedFile unlockMappedFile = null; + // 获取当前可以写入的CommitLog文件,对应 ${ROCKET_HOME}/store/commitlog 文件夹下的文件 MappedFile mappedFile = this.mappedFileQueue.getLastMappedFile(); - + // 在将消息写入CommitLog之前,先申请putMessageLock putMessageLock.lock(); //spin or ReentrantLock ,depending on store config try { long beginLockTimestamp = this.defaultMessageStore.getSystemClock().now(); @@ -611,19 +635,24 @@ public PutMessageResult putMessage(final MessageExtBrokerInner msg) { msg.setStoreTimestamp(beginLockTimestamp); if (null == mappedFile || mappedFile.isFull()) { + //如果mappedFile为空,表明 ${ROCKET_HOME}/store/commitlog目录下不存在任何文件,说明本次 + //消息是第一次发送,用偏移量0创建第一个CommitLog文件,文件名为00000000000000000000, mappedFile = this.mappedFileQueue.getLastMappedFile(0); // Mark: NewFile may be cause noise } if (null == mappedFile) { log.error("create mapped file1 error, topic: " + msg.getTopic() + " clientAddr: " + msg.getBornHostString()); beginTimeInLock = 0; + // 如果文件创建失败,抛出CREATE_MAPEDFILE_FAILED,这很有可能是磁盘空间不足或权限不够导致的, return new PutMessageResult(PutMessageStatus.CREATE_MAPEDFILE_FAILED, null); } + // 将消息追加到 CommitLog 中 result = mappedFile.appendMessage(msg, this.appendMessageCallback); switch (result.getStatus()) { case PUT_OK: break; case END_OF_FILE: + // 当前CommitLog文件不够写入此条消息 (CommitLog定长1GB) unlockMappedFile = mappedFile; // Create a new file, re-write the message mappedFile = this.mappedFileQueue.getLastMappedFile(0); @@ -650,6 +679,7 @@ public PutMessageResult putMessage(final MessageExtBrokerInner msg) { eclipsedTimeInLock = this.defaultMessageStore.getSystemClock().now() - beginLockTimestamp; beginTimeInLock = 0; } finally { + // 追加完毕,释放锁 putMessageLock.unlock(); } @@ -667,7 +697,9 @@ public PutMessageResult putMessage(final MessageExtBrokerInner msg) { storeStatsService.getSinglePutMessageTopicTimesTotal(msg.getTopic()).incrementAndGet(); storeStatsService.getSinglePutMessageTopicSizeTotal(topic).addAndGet(result.getWroteBytes()); + // appendMessage只是将消息追加到内存中,需要根据采取的是同步刷盘方式还是异步刷盘方式,将内存中的数据持久化到磁盘中。 handleDiskFlush(result, putMessageResult, msg); + // HA主从同步复制 handleHA(result, putMessageResult, msg); return putMessageResult; @@ -855,9 +887,16 @@ public long pickupStoreTimestamp(final long offset, final int size) { return -1; } + /** + * 获取当前CommitLog目录的最小偏移量 + * 由于RocketMQ会定时删除commitLog,所以CommitLog目录的最小偏移量并不一定是0,而是需要拿到第一个文件,获取该文件的起始偏移量 + * @return + */ public long getMinOffset() { + // 获取第一个 CommitLog 文件 MappedFile mappedFile = this.mappedFileQueue.getFirstMappedFile(); if (mappedFile != null) { + // 如果该文件可用,则返回该文件的起始偏移量,否则返回下一个文件的起始偏移量 if (mappedFile.isAvailable()) { return mappedFile.getFileFromOffset(); } else { @@ -868,6 +907,16 @@ public long getMinOffset() { return -1; } + /** + * 根据偏移量与消息长度查找消息。首先根据偏移找到文件所在的 + * 物理偏移量,然后用offset与文件长度取余,得到在文件内的偏移 + * 量,从该偏移量读取size长度的内容并返回。如果只根据消息偏移量 + * 查找消息,则首先找到文件内的偏移量,然后尝试读取4字节,获取消 + * 息的实际长度,最后读取指定字节。 + * @param offset + * @param size + * @return + */ public SelectMappedBufferResult getMessage(final long offset, final int size) { int mappedFileSize = this.defaultMessageStore.getMessageStoreConfig().getMappedFileSizeCommitLog(); MappedFile mappedFile = this.mappedFileQueue.findMappedFileByOffset(offset, offset == 0); @@ -878,6 +927,13 @@ public SelectMappedBufferResult getMessage(final long offset, final int size) { return null; } + /** + * 根据offset返回下一个文件的起始偏移量。获取一个文件的大 + * 小,减去offset % mapped-FileSize,回到下一文件的起始偏移量, + * 如代码清单4-32所示。 + * @param offset + * @return + */ public long rollNextFile(final long offset) { int mappedFileSize = this.defaultMessageStore.getMessageStoreConfig().getMappedFileSizeCommitLog(); return offset + mappedFileSize - offset % mappedFileSize; @@ -1209,6 +1265,9 @@ public long getJointime() { class DefaultAppendMessageCallback implements AppendMessageCallback { // File at the end of the minimum fixed length empty + /** + * 每个CommitLog文件最少空闲8字节,高4字节存储当前文件的剩余空间,低4字节存储魔数 CommitLog.BLANK_MAGIC_CODE + */ private static final int END_FILE_MIN_BLANK_LENGTH = 4 + 4; private final ByteBuffer msgIdMemory; private final ByteBuffer msgIdV6Memory; @@ -1248,6 +1307,7 @@ public AppendMessageResult doAppend(final long fileFromOffset, final ByteBuffer this.resetByteBuffer(storeHostHolder, storeHostLength); String msgId; + // 创建全局唯一的消息ID if ((sysflag & MessageSysFlag.STOREHOSTADDRESS_V6_FLAG) == 0) { msgId = MessageDecoder.createMessageId(this.msgIdMemory, msgInner.getStoreHostBytes(storeHostHolder), wroteOffset); } else { @@ -1255,6 +1315,7 @@ public AppendMessageResult doAppend(final long fileFromOffset, final ByteBuffer } // Record ConsumeQueue information + // 获取该消息在消息队列的物理偏移量。CommitLog中保存了当前所有消息队列的待写入物理偏移量 keyBuilder.setLength(0); keyBuilder.append(msgInner.getTopic()); keyBuilder.append('-'); @@ -1286,7 +1347,7 @@ public AppendMessageResult doAppend(final long fileFromOffset, final ByteBuffer */ final byte[] propertiesData = msgInner.getPropertiesString() == null ? null : msgInner.getPropertiesString().getBytes(MessageDecoder.CHARSET_UTF8); - + // properties 长度 final int propertiesLength = propertiesData == null ? 0 : propertiesData.length; if (propertiesLength > Short.MAX_VALUE) { @@ -1299,6 +1360,7 @@ public AppendMessageResult doAppend(final long fileFromOffset, final ByteBuffer final int bodyLength = msgInner.getBody() == null ? 0 : msgInner.getBody().length; + // 计算消息长度 final int msgLen = calMsgLength(msgInner.getSysFlag(), bodyLength, topicLength, propertiesLength); // Exceeds the maximum message @@ -1309,6 +1371,8 @@ public AppendMessageResult doAppend(final long fileFromOffset, final ByteBuffer } // Determines whether there is sufficient free space + // 如果消息长度+END_FILE_MIN_BLANK_LENGTH大于CommitLog文件的空闲空间, + // 则返回AppendMessageStatus.END_OF_FILE,Broker会创建一个新的CommitLog文件来存储该消息。 if ((msgLen + END_FILE_MIN_BLANK_LENGTH) > maxBlank) { this.resetByteBuffer(this.msgStoreItemMemory, maxBlank); // 1 TOTALSIZE @@ -1369,6 +1433,7 @@ public AppendMessageResult doAppend(final long fileFromOffset, final ByteBuffer final long beginTimeMills = CommitLog.this.defaultMessageStore.now(); // Write messages to the queue buffer + // 将消息内容存储到ByteBuffer中,然后创建AppendMessageResult。这里只是将消息存储在MappedFile对应的内存映射Buffer中,并没有写入磁盘 byteBuffer.put(this.msgStoreItemMemory.array(), 0, msgLen); AppendMessageResult result = new AppendMessageResult(AppendMessageStatus.PUT_OK, wroteOffset, msgLen, msgId, @@ -1381,6 +1446,7 @@ public AppendMessageResult doAppend(final long fileFromOffset, final ByteBuffer case MessageSysFlag.TRANSACTION_NOT_TYPE: case MessageSysFlag.TRANSACTION_COMMIT_TYPE: // The next update ConsumeQueue information + // 更新消息队列的逻辑偏移量 CommitLog.this.topicQueueTable.put(key, ++queueOffset); break; default: diff --git a/store/src/main/java/org/apache/rocketmq/store/ConsumeQueue.java b/store/src/main/java/org/apache/rocketmq/store/ConsumeQueue.java index 87ff0a096cf..214f36f4343 100644 --- a/store/src/main/java/org/apache/rocketmq/store/ConsumeQueue.java +++ b/store/src/main/java/org/apache/rocketmq/store/ConsumeQueue.java @@ -25,9 +25,28 @@ import org.apache.rocketmq.store.config.BrokerRole; import org.apache.rocketmq.store.config.StorePathConfigHelper; +/** + * RocketMQ基于主题订阅模式实现消息消费,消费者关心的是一个 + * 主题下的所有消息,但同一主题的消息是不连续地存储在CommitLog文 + * 件中的。如果消息消费者直接从消息存储文件中遍历查找订阅主题下 + * 的消息,效率将极其低下。RocketMQ为了适应消息消费的检索需求, + * 设计了ConsumeQueue文件,该文件可以看作CommitLog关于消息消费的 + * “索引”文件,ConsumeQueue的第一级目录为消息主题,第二级目录 + * 为主题的消息队列。 + * $HOME/store/consumequeue/{topic}/{queueId}/{fileName} + * + * ConsumeQueue 的设计极具技巧,每个条目长度固定(8字节CommitLog物理偏移量、 + * 4字节消息长度、8字节tag哈希码)。这里不是存储tag的原始字符串,而是存储哈希码, + * 目的是确保每个条目的长度固定,可以使用访问类似数组下标的方式快速定位条目, + * 极大地提高了ConsumeQueue文件的读取性能。 + */ public class ConsumeQueue { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.STORE_LOGGER_NAME); + /** + * ConsumeQueue文件中每一个条目是固定长度 20字节 + * 8字节 CommitLog偏移量 + 4字节消息长度 + 8字节 Tag Hash码 + */ public static final int CQ_STORE_UNIT_SIZE = 20; private static final InternalLogger LOG_ERROR = InternalLoggerFactory.getLogger(LoggerName.STORE_ERROR_LOGGER_NAME); @@ -152,6 +171,11 @@ public void recover() { } } + /** + * 根据消息存储时间来查找具体消息的下标 + * @param timestamp + * @return + */ public long getOffsetInQueueByTime(final long timestamp) { MappedFile mappedFile = this.mappedFileQueue.getMappedFileByTime(timestamp); if (mappedFile != null) { @@ -376,6 +400,10 @@ public long getMinOffsetInQueue() { return this.minLogicOffset / CQ_STORE_UNIT_SIZE; } + /** + * 将 CommitLog 分发存储到 ConsumeQueue中,只有执行该方法后,才会将CommitLog索引信息存到ConsumeQueue中,这样消费者才能消费到这条消息 + * @param request + */ public void putMessagePositionInfoWrapper(DispatchRequest request) { final int maxRetries = 30; boolean canWrite = this.defaultMessageStore.getRunningFlags().isCQWriteable(); @@ -395,6 +423,7 @@ public void putMessagePositionInfoWrapper(DispatchRequest request) { topic, queueId, request.getCommitLogOffset()); } } + // 执行分发操作 boolean result = this.putMessagePositionInfo(request.getCommitLogOffset(), request.getMsgSize(), tagsCode, request.getConsumeQueueOffset()); if (result) { @@ -429,11 +458,14 @@ private boolean putMessagePositionInfo(final long offset, final int size, final log.warn("Maybe try to build consume queue repeatedly maxPhysicOffset={} phyOffset={}", maxPhysicOffset, offset); return true; } - + // 切换读写模式 this.byteBufferIndex.flip(); this.byteBufferIndex.limit(CQ_STORE_UNIT_SIZE); + // 设置消息在CommitLog中的物理偏移量 this.byteBufferIndex.putLong(offset); + // 设置消息长度 this.byteBufferIndex.putInt(size); + // 设置消息 Tag Hash码 this.byteBufferIndex.putLong(tagsCode); final long expectLogicOffset = cqOffset * CQ_STORE_UNIT_SIZE; @@ -471,6 +503,7 @@ private boolean putMessagePositionInfo(final long offset, final int size, final } } this.maxPhysicOffset = offset + size; + // 追加到 ConsumeQueue 文件 return mappedFile.appendMessage(this.byteBufferIndex.array()); } return false; @@ -488,6 +521,16 @@ private void fillPreBlank(final MappedFile mappedFile, final long untilWhere) { } } + /** + * 根据startIndex获取消息消费队列条目。通过startIndex×20得 + * 到在ConsumeQueue文件的物理偏移量,如果该偏移量小于 + * minLogicOffset,则返回null,说明该消息已被删除,如果大于 + * minLogicOffset,则根据偏移量定位到具体的物理文件。通过将该偏 + * 移量与物理文件的大小取模获取在该文件的偏移量,从偏移量开始连 + * 续读取20个字节即可。 + * @param startIndex + * @return + */ public SelectMappedBufferResult getIndexBuffer(final long startIndex) { int mappedFileSize = this.mappedFileSize; long offset = startIndex * CQ_STORE_UNIT_SIZE; diff --git a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java index d5ba5692a92..8992df9a80d 100644 --- a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java +++ b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java @@ -61,33 +61,70 @@ import org.apache.rocketmq.store.schedule.ScheduleMessageService; import org.apache.rocketmq.store.stats.BrokerStatsManager; +/** + * 消息存储实现类org.apache.rocketmq.store.DefaultMessageStore是存储模块里面最重要的一个类, + * 包含了很多对存储文件进行操作的API,其他模块对消息实体的操作都是通过DefaultMessageStore进行的 + */ public class DefaultMessageStore implements MessageStore { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.STORE_LOGGER_NAME); + /** + * 消息存储配置属性 + */ private final MessageStoreConfig messageStoreConfig; + /** + * CommitLog文件的存储实现类 + */ // CommitLog private final CommitLog commitLog; + /** + * 消息队列存储缓存表,按消息主题分组 + */ private final ConcurrentMap> consumeQueueTable; + /** + * ConsumeQueue文件刷盘线程 + */ private final FlushConsumeQueueService flushConsumeQueueService; + /** + * 清除CommitLog文件服务 + */ private final CleanCommitLogService cleanCommitLogService; + /** + * 清除ConsumeQueue文件服务 + */ private final CleanConsumeQueueService cleanConsumeQueueService; + /** + * Index文件实现类 + */ private final IndexService indexService; + /** + * MappedFile分配服务 + */ private final AllocateMappedFileService allocateMappedFileService; + /** + * CommitLog消息分发,根据CommitLog文件构建ConsumeQueue、Index文件。 + */ private final ReputMessageService reputMessageService; + /** + * 存储高可用机制 + */ private final HAService haService; private final ScheduleMessageService scheduleMessageService; private final StoreStatsService storeStatsService; + /** + * 消息堆内存缓存 + */ private final TransientStorePool transientStorePool; private final RunningFlags runningFlags = new RunningFlags(); @@ -97,14 +134,23 @@ public class DefaultMessageStore implements MessageStore { Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl("StoreScheduledThread")); private final BrokerStatsManager brokerStatsManager; private final MessageArrivingListener messageArrivingListener; + /** + * Broker配置属性 + */ private final BrokerConfig brokerConfig; private volatile boolean shutdown = true; + /** + * 文件刷盘检测点 + */ private StoreCheckpoint storeCheckpoint; private AtomicLong printTimes = new AtomicLong(0); + /** + * CommitLog文件转发请求 + */ private final LinkedList dispatcherList; private RandomAccessFile lockFile; @@ -177,6 +223,7 @@ public boolean load() { boolean result = true; try { + // 判断上次broker停止是否是正常停止 boolean lastExitOK = !this.isTempFileExist(); log.info("last shutdown {}", lastExitOK ? "normally" : "abnormally"); @@ -185,17 +232,24 @@ public boolean load() { } // load Commit Log + // 加载CommitLog文件,加载 ${ROCKET_HOME}/store/commitlog 目录下所有文件并按照文件名进行 + // 排序。如果文件与配置文件的单个文件大小不一致,将忽略该目录下的所有文件,然后创建MappedFile对象。注意load()方法将 + //wrotePosition、flushedPosition、committedPosition三个指针都设置为文件大小。 result = result && this.commitLog.load(); // load Consume Queue + // 加载 ConsumeQueue result = result && this.loadConsumeQueue(); if (result) { + // 加载并存储checkpoint文件,主要用于记录CommitLog文件、ConsumeQueue文件、Inde文件的刷盘点 this.storeCheckpoint = new StoreCheckpoint(StorePathConfigHelper.getStoreCheckpoint(this.messageStoreConfig.getStorePathRootDir())); + // 加载Index文件,如果上次异常退出,而且Index文件刷盘时间小于该文件最大的消息时间戳,则该文件将立即销毁 this.indexService.load(lastExitOK); + // 根据Broker是否为正常停止,执行不同的恢复策略 this.recover(lastExitOK); log.info("load over, and the max phy offset = {}", this.getMaxPhyOffset()); @@ -232,6 +286,7 @@ public void start() throws Exception { * 4. Make sure the fall-behind messages to be dispatched before starting the commitlog, especially when the broker role are automatically changed. */ long maxPhysicalPosInLogicQueue = commitLog.getMinOffset(); + // 将ConsumeQueue中最大CommitLog物理偏移量,设置成ReputMessage线程重放的起点 for (ConcurrentMap maps : this.consumeQueueTable.values()) { for (ConsumeQueue logic : maps.values()) { if (logic.getMaxPhysicOffset() > maxPhysicalPosInLogicQueue) { @@ -270,6 +325,8 @@ public void start() throws Exception { Thread.sleep(1000); log.info("Try to finish doing reput the messages fall behind during the starting, reputOffset={} maxOffset={} behind={}", this.reputMessageService.getReputFromOffset(), this.getMaxPhyOffset(), this.dispatchBehindBytes()); } + // 恢复ConsumeQueue文件后,将在CommitLog实例中保存每个消息消费队列当前的存储逻辑偏移量,这也是消息中不仅存储主 + // 题、消息队列ID还存储了消息队列偏移量的关键所在。 this.recoverTopicQueueTable(); } @@ -352,11 +409,13 @@ public void destroyLogics() { } public PutMessageResult putMessage(MessageExtBrokerInner msg) { + // 如果当前broker停止工作或当前不支持写入,则拒绝消息写入。 if (this.shutdown) { log.warn("message store has shutdown, so putMessage is forbidden"); return new PutMessageResult(PutMessageStatus.SERVICE_NOT_AVAILABLE, null); } + // 如果当前broker是从节点,则拒绝写入消息 if (BrokerRole.SLAVE == this.messageStoreConfig.getBrokerRole()) { long value = this.printTimes.getAndIncrement(); if ((value % 50000) == 0) { @@ -366,6 +425,7 @@ public PutMessageResult putMessage(MessageExtBrokerInner msg) { return new PutMessageResult(PutMessageStatus.SERVICE_NOT_AVAILABLE, null); } + // 判断当前broker是否能够写入 if (!this.runningFlags.isWriteable()) { long value = this.printTimes.getAndIncrement(); if ((value % 50000) == 0) { @@ -377,21 +437,26 @@ public PutMessageResult putMessage(MessageExtBrokerInner msg) { this.printTimes.set(0); } + // topic长度大于127字符,则报错 if (msg.getTopic().length() > Byte.MAX_VALUE) { log.warn("putMessage message topic length too long " + msg.getTopic().length()); return new PutMessageResult(PutMessageStatus.MESSAGE_ILLEGAL, null); } + // 消息属性长度大于 32767,则报错 if (msg.getPropertiesString() != null && msg.getPropertiesString().length() > Short.MAX_VALUE) { log.warn("putMessage message properties length too long " + msg.getPropertiesString().length()); return new PutMessageResult(PutMessageStatus.PROPERTIES_SIZE_EXCEEDED, null); } + // OSPageCacheBusy通常是出现在操作系统在试图缓存太多页面时。当物理内存充满了,操作系统可能试图清除一些页面来为新的页面腾出空间。 + // 如果这个过程中所有的页面都在使用(即“繁忙”),那么就会报告OSPageCacheBusy。 if (this.isOSPageCacheBusy()) { return new PutMessageResult(PutMessageStatus.OS_PAGECACHE_BUSY, null); } long beginTime = this.getSystemClock().now(); + // 写入CommitLog PutMessageResult result = this.commitLog.putMessage(msg); long elapsedTime = this.getSystemClock().now() - beginTime; @@ -1128,6 +1193,15 @@ public MessageExt lookMessageByOffset(long commitLogOffset, int size) { return null; } + /** + * 根据消息主题与队列ID,先获取对应的ConsumeQueue文 + * 件,其逻辑比较简单,因为每一个消息主题对应一个ConsumeQueue目 + * 录,主题下每一个消息队列对应一个文件夹,所以取出该文件夹最后 + * 的ConsumeQueue文件即可 + * @param topic + * @param queueId + * @return + */ public ConsumeQueue findConsumeQueue(String topic, int queueId) { ConcurrentMap map = consumeQueueTable.get(topic); if (null == map) { @@ -1284,12 +1358,28 @@ private void checkSelf() { } } + /** + * 判断 broker存储目录下,是否有abort文件(${ROCKET_HOME}/store/abort),有则代表上一次broker是非正常停止。 + * + * 其实现机制是Broker在启动时创建${ROCKET_HOME}/store/abort文件,在退出时通过注册JVM钩子 + * 函数删除abort文件。如果下一次启动时存在abort文件 + * + * @return + */ private boolean isTempFileExist() { String fileName = StorePathConfigHelper.getAbortFile(this.messageStoreConfig.getStorePathRootDir()); File file = new File(fileName); return file.exists(); } + /** + * 加载ConsumeQueue文件 + * 遍历消息消费队列根目录,获取该Broker存储的所有主题,然后 + * 遍历每个主题目录,获取该主题下的所有消息消费队列,最后分别加 + * 载每个消息消费队列下的文件,构建ConsumeQueue对象,主要初始化 + * ConsumeQueue的topic、queueId、storePath、mappedFileSize属性 + * @return + */ private boolean loadConsumeQueue() { File dirLogic = new File(StorePathConfigHelper.getStorePathConsumeQueue(this.messageStoreConfig.getStorePathRootDir())); File[] fileTopicList = dirLogic.listFiles(); @@ -1327,12 +1417,28 @@ private boolean loadConsumeQueue() { return true; } + /** + * 根据Broker上一次停止是否为正常停止,执行不同的恢复策略 + * + * 存储启动时所谓的文件恢复主要完成flushedPosition、 + * committedWhere指针的设置、将消息消费队列最大偏移量加载到内 + * 存,并删除flushedPosition之后所有的文件。如果Broker异常停止, + * 在文件恢复过程中,RocketMQ会将最后一个有效文件中的所有消息重 + * 新转发到ConsumeQueue和Index文件中,确保不丢失消息,但同时会带 + * 来消息重复的问题。纵观RocktMQ的整体设计思想,RocketMQ保证消息 + * 不丢失但不保证消息不会重复消费,故消息消费业务方需要实现消息 + * 消费的幂等设计 + * + * @param lastExitOK + */ private void recover(final boolean lastExitOK) { long maxPhyOffsetOfConsumeQueue = this.recoverConsumeQueue(); if (lastExitOK) { + // 正常停止 this.commitLog.recoverNormally(maxPhyOffsetOfConsumeQueue); } else { + // 异常停止 this.commitLog.recoverAbnormally(maxPhyOffsetOfConsumeQueue); } @@ -1372,6 +1478,10 @@ private long recoverConsumeQueue() { return maxPhysicOffset; } + /** + * 恢复ConsumeQueue文件后,将在CommitLog实例中保存每个消息消费队列当前的存储逻辑偏移量,这也是消息中不仅存储主 + * 题、消息队列ID还存储了消息队列偏移量的关键所在。 + */ public void recoverTopicQueueTable() { HashMap table = new HashMap(1024); long minPhyOffset = this.commitLog.getMinOffset(); @@ -1419,12 +1529,16 @@ public RunningFlags getRunningFlags() { } public void doDispatch(DispatchRequest req) { + // 不同的文件有不同的转发实现 + // ConsumeQueue 对应 org.apache.rocketmq.store.DefaultMessageStore.CommitLogDispatcherBuildConsumeQueue + // Index 对应 org.apache.rocketmq.store.DefaultMessageStore.CommitLogDispatcherBuildIndex for (CommitLogDispatcher dispatcher : this.dispatcherList) { dispatcher.dispatch(req); } } public void putMessagePositionInfo(DispatchRequest dispatchRequest) { + // 根据 topic 和 队列ID,获取对应ConsumeQueue ConsumeQueue cq = this.findConsumeQueue(dispatchRequest.getTopic(), dispatchRequest.getQueueId()); cq.putMessagePositionInfoWrapper(dispatchRequest); } @@ -1478,6 +1592,9 @@ public void run() { }, 6, TimeUnit.SECONDS); } + /** + * CommitLog向 ConsumeQueue文件分发实现 + */ class CommitLogDispatcherBuildConsumeQueue implements CommitLogDispatcher { @Override @@ -1486,8 +1603,10 @@ public void dispatch(DispatchRequest request) { switch (tranType) { case MessageSysFlag.TRANSACTION_NOT_TYPE: case MessageSysFlag.TRANSACTION_COMMIT_TYPE: + // 将CommitLog分发至ConsumeQueue DefaultMessageStore.this.putMessagePositionInfo(request); break; + // 事务消息,在未提交,以及回滚操作下,不会将CommitLog中的消息分发到ConsumeQueue case MessageSysFlag.TRANSACTION_PREPARED_TYPE: case MessageSysFlag.TRANSACTION_ROLLBACK_TYPE: break; @@ -1495,11 +1614,15 @@ public void dispatch(DispatchRequest request) { } } + /** + * CommitLog向Index文件分发的实现 + */ class CommitLogDispatcherBuildIndex implements CommitLogDispatcher { @Override public void dispatch(DispatchRequest request) { if (DefaultMessageStore.this.messageStoreConfig.isMessageIndexEnable()) { + // 只有开启了消息索引开关,才会执行消息索引,默认是开启状态 DefaultMessageStore.this.indexService.buildIndex(request); } } @@ -1774,6 +1897,22 @@ public long getJointime() { } } + /** + * 因为ConsumeQueue文件、Index文件都是基于CommitLog文件构建 + * 的,所以当消息生产者提交的消息存储到CommitLog文件中时, + * ConsumeQueue文件、Index文件需要及时更新,否则消息无法及时被消 + * 费,根据消息属性查找消息也会出现较大延迟。RocketMQ通过开启一 + * 个线程ReputMessageServcie来准实时转发CommitLog文件的更新事 + * 件,相应的任务处理器根据转发的消息及时更新ConsumeQueue文件、 + * Index文件。 + * + * Broker服务器在启动时会启动ReputMessageService线程,并初始 + * 化一个非常关键的参数reputFromOffset,该参数的含义是 + * ReputMessageService从哪个物理偏移量开始转发消息给ConsumeQueue + * 和Index文件。如果允许重复转发,将reputFromOffset设置为 + * CommitLog文件的提交指针。如果不允许重复转发,将 + * reputFromOffset设置为CommitLog文件的内存中最大偏移量 + */ class ReputMessageService extends ServiceThread { private volatile long reputFromOffset = 0; @@ -1811,6 +1950,11 @@ private boolean isCommitLogAvailable() { return this.reputFromOffset < DefaultMessageStore.this.commitLog.getMaxOffset(); } + /** + * ReputMessageService线程每执行一次任务推送,休息1ms后继续 + * 尝试推送消息到Consume Queue和Index文件中,消息消费转发由 + * doReput()方法实现 + */ private void doReput() { if (this.reputFromOffset < DefaultMessageStore.this.commitLog.getMinOffset()) { log.warn("The reputFromOffset={} is smaller than minPyOffset={}, this usually indicate that the dispatch behind too much and the commitlog has expired.", @@ -1824,18 +1968,21 @@ private void doReput() { break; } + // 返回reputFromOffset偏移量开始的全部有效数据(CommitLog文件)。然后循环读取每一条消息 SelectMappedBufferResult result = DefaultMessageStore.this.commitLog.getData(reputFromOffset); if (result != null) { try { this.reputFromOffset = result.getStartOffset(); for (int readSize = 0; readSize < result.getSize() && doNext; ) { + // 从result返回的ByteBuffer中循环读取消息,一次读取一条,创建Dispatch Request对象 DispatchRequest dispatchRequest = DefaultMessageStore.this.commitLog.checkMessageAndReturnSize(result.getByteBuffer(), false, false); int size = dispatchRequest.getBufferSize() == -1 ? dispatchRequest.getMsgSize() : dispatchRequest.getBufferSize(); if (dispatchRequest.isSuccess()) { if (size > 0) { + // 执行CommitLog转发 DefaultMessageStore.this.doDispatch(dispatchRequest); if (BrokerRole.SLAVE != DefaultMessageStore.this.getMessageStoreConfig().getBrokerRole() @@ -1893,6 +2040,7 @@ public void run() { while (!this.isStopped()) { try { Thread.sleep(1); + // 每休息1ms就执行一次消息转发 this.doReput(); } catch (Exception e) { DefaultMessageStore.log.warn(this.getServiceName() + " service has exception. ", e); diff --git a/store/src/main/java/org/apache/rocketmq/store/DispatchRequest.java b/store/src/main/java/org/apache/rocketmq/store/DispatchRequest.java index 89d47ced5ba..21ae8e803e2 100644 --- a/store/src/main/java/org/apache/rocketmq/store/DispatchRequest.java +++ b/store/src/main/java/org/apache/rocketmq/store/DispatchRequest.java @@ -19,20 +19,64 @@ import java.util.Map; public class DispatchRequest { + + /** + * 消息主题名称 + */ private final String topic; + /** + * 队列ID + */ private final int queueId; + /** + * 消息物理偏移量 + */ private final long commitLogOffset; + /** + * 消息长度 + */ private int msgSize; + /** + * 消息过滤tag哈希码 + */ private final long tagsCode; + /** + * 消息存储时间戳 + */ private final long storeTimestamp; + /** + * 消息队列偏移量 + */ private final long consumeQueueOffset; + /** + * 消息索引key。多个索引key用空格隔开,例如 + * key1 key2 + */ private final String keys; + /** + * 是否成功解析到完整的消息 + */ private final boolean success; + /** + * 消息唯一键 + */ private final String uniqKey; + /** + * 消息系统标记 + */ private final int sysFlag; + /** + * 消息预处理事务偏移量 + */ private final long preparedTransactionOffset; + /** + * 消息属性 + */ private final Map propertiesMap; + /** + * 位图 + */ private byte[] bitMap; private int bufferSize = -1;//the buffer size maybe larger than the msg size if the message is wrapped by something diff --git a/store/src/main/java/org/apache/rocketmq/store/MappedFile.java b/store/src/main/java/org/apache/rocketmq/store/MappedFile.java index 9185d21d874..f5765ad22c5 100644 --- a/store/src/main/java/org/apache/rocketmq/store/MappedFile.java +++ b/store/src/main/java/org/apache/rocketmq/store/MappedFile.java @@ -42,27 +42,73 @@ import sun.nio.ch.DirectBuffer; public class MappedFile extends ReferenceResource { + + /** + * 操作系统页大小 + */ public static final int OS_PAGE_SIZE = 1024 * 4; protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.STORE_LOGGER_NAME); - + /** + * 当前JVM实例中MappedFile的虚拟内存。 + */ private static final AtomicLong TOTAL_MAPPED_VIRTUAL_MEMORY = new AtomicLong(0); - + /** + * 当前JVM实例中MappedFile对象个数。 + */ private static final AtomicInteger TOTAL_MAPPED_FILES = new AtomicInteger(0); + /** + * 当前文件的写指针,从0开始(内存映射文件中的写指针)。 + */ protected final AtomicInteger wrotePosition = new AtomicInteger(0); + /** + * 当前文件的提交指针,如果开启transientStore-PoolEnable,则数据会存储在 + * TransientStorePool中,然后提交到内存映射ByteBuffer中,再写入磁盘。 + */ protected final AtomicInteger committedPosition = new AtomicInteger(0); + /** + * 将该指针之前的数据持久化存储到磁盘中。 + */ private final AtomicInteger flushedPosition = new AtomicInteger(0); protected int fileSize; + /** + * 文件通道 + */ protected FileChannel fileChannel; /** * Message will put to here first, and then reput to FileChannel if writeBuffer is not null. */ + /** + * 堆外内存ByteBuffer,如果不为空,数据首先将存储在该Buffer中,然后提交到MappedFile创建的 + * FileChannel中。transientStorePoolEnable为true时不为空。 + */ protected ByteBuffer writeBuffer = null; + /** + * 堆外内存池,该内存池中的内存会提供内存锁机制。transientStorePoolEnable为true时启用。 + */ protected TransientStorePool transientStorePool = null; + /** + * 文件名称 + */ private String fileName; + /** + * 该文件的初始偏移量 + */ private long fileFromOffset; + /** + * 物理文件 + */ private File file; + /** + * 物理文件对应的内存映射Buffer。 + */ private MappedByteBuffer mappedByteBuffer; + /** + * 文件最后一次写入内容的时间 + */ private volatile long storeTimestamp = 0; + /** + * 是否是MappedFileQueue队列中第一个文件。 + */ private boolean firstCreateInQueue = false; public MappedFile() { @@ -159,6 +205,7 @@ private void init(final String fileName, final int fileSize) throws IOException try { this.fileChannel = new RandomAccessFile(this.file, "rw").getChannel(); + // 创建内存映射 MappedByteBuffer this.mappedByteBuffer = this.fileChannel.map(MapMode.READ_WRITE, 0, fileSize); TOTAL_MAPPED_VIRTUAL_MEMORY.addAndGet(fileSize); TOTAL_MAPPED_FILES.incrementAndGet(); @@ -200,12 +247,16 @@ public AppendMessageResult appendMessagesInner(final MessageExt messageExt, fina assert messageExt != null; assert cb != null; + // 首先获取MappedFile当前的写指针,如果currentPos大于或等于文件大小,表明文件已写满 int currentPos = this.wrotePosition.get(); if (currentPos < this.fileSize) { + // 通过slice()方法创建一个与原ByteBuffer共享的内存区,且拥有独立的position、limit、capacity等指针(零拷贝) ByteBuffer byteBuffer = writeBuffer != null ? writeBuffer.slice() : this.mappedByteBuffer.slice(); + // 并设置position为当前指针 byteBuffer.position(currentPos); AppendMessageResult result; + // 执行写入操作,将消息内容存储到ByteBuffer中,这里只是将消息存储在MappedFile对应的内存映射Buffer中,并没有写入磁盘 if (messageExt instanceof MessageExtBrokerInner) { result = cb.doAppend(this.getFileFromOffset(), byteBuffer, this.fileSize - currentPos, (MessageExtBrokerInner) messageExt); } else if (messageExt instanceof MessageExtBatch) { @@ -278,6 +329,8 @@ public int flush(final int flushLeastPages) { if (writeBuffer != null || this.fileChannel.position() != 0) { this.fileChannel.force(false); } else { + // 直接调用mappedByteBuffer或fileChannel的force()方法将数据 + // 写入磁盘,将内存中的数据持久化到磁盘中, this.mappedByteBuffer.force(); } } catch (Throwable e) { @@ -294,6 +347,11 @@ public int flush(final int flushLeastPages) { return this.getFlushedPosition(); } + /** + * 内存映射文件的提交动作由MappedFile的commit()方法实现 + * @param commitLeastPages 本次提交的最小页数,如果待提交数据不满足commitLeastPages,则不执行本次提交操作,等待下次提交 + * @return + */ public int commit(final int commitLeastPages) { if (writeBuffer == null) { //no need to commit data to file channel, so just regard wrotePosition as committedPosition. @@ -350,6 +408,15 @@ private boolean isAbleToFlush(final int flushLeastPages) { return write > flush; } + /** + * 判断是否执行commit操作。如果文件已满,返回true。如果 + * commitLeastPages大于0,则计算wrotePosition(当前writeBuffe的 + * 写指针)与上一次提交的指针(committedPosition)的差值,将其除 + * 以OS_PAGE_SIZE得到当前脏页的数量,如果大于commitLeastPages, + * 则返回true。如果commitLeastPages小于0,表示只要存在脏页就提交 + * @param commitLeastPages + * @return + */ protected boolean isAbleToCommit(final int commitLeastPages) { int flush = this.committedPosition.get(); int write = this.wrotePosition.get(); @@ -398,14 +465,29 @@ public SelectMappedBufferResult selectMappedBuffer(int pos, int size) { return null; } + /** + * 首先查找pos到当前最大可读指针之间的数据,因为在整个写入期 + * 间都未曾改变MappedByteBuffer的指针,所以 + * mappedByteBuffer.slice()方法返回的共享缓存区空间为整个 + * MappedFile。然后通过设置byteBuffer的position为待查找的值,读 + * 取字节为当前可读字节长度,最终返回的ByteBuffer的limit(可读最 + * 大长度)为size。整个共享缓存区的容量为 + * MappedFile#fileSizepos,故在操作SelectMappedBufferResult时不 + * 能对包含在里面的ByteBuffer调用flip()方法。 + * + * @param pos + * @return + */ public SelectMappedBufferResult selectMappedBuffer(int pos) { int readPosition = getReadPosition(); if (pos < readPosition && pos >= 0) { if (this.hold()) { ByteBuffer byteBuffer = this.mappedByteBuffer.slice(); + // 设置读起始指针 byteBuffer.position(pos); int size = readPosition - pos; ByteBuffer byteBufferNew = byteBuffer.slice(); + // 设置读结束指针 byteBufferNew.limit(size); return new SelectMappedBufferResult(this.fileFromOffset + pos, byteBufferNew, size, this); } diff --git a/store/src/main/java/org/apache/rocketmq/store/MappedFileQueue.java b/store/src/main/java/org/apache/rocketmq/store/MappedFileQueue.java index cc145921cef..1210bb0f064 100644 --- a/store/src/main/java/org/apache/rocketmq/store/MappedFileQueue.java +++ b/store/src/main/java/org/apache/rocketmq/store/MappedFileQueue.java @@ -29,21 +29,47 @@ import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; +/** + * RocketMQ通过使用内存映射文件来提高I/O访问性能,无论是 + * CommitLog、Consume-Queue还是Index,单个文件都被设计为固定长 + * 度,一个文件写满以后再创建新文件,文件名就为该文件第一条消息 + * 对应的全局物理偏移量。 + * RocketMQ使用MappedFile、MappedFileQueue来封装存储文件。 + * + * MappedFileQueue是MappedFile的管理容器,MappedFileQueue对 + * 存储目录进行封装, + * + * 例如CommitLog文件的存储场景下,存储路径为${ROCKET_HOME}/store/commitlog/, + * 该目录下会存在多个内存映射文件MappedFile + */ public class MappedFileQueue { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.STORE_LOGGER_NAME); private static final InternalLogger LOG_ERROR = InternalLoggerFactory.getLogger(LoggerName.STORE_ERROR_LOGGER_NAME); private static final int DELETE_FILES_BATCH_MAX = 10; - + /** + * 存储目录 + */ private final String storePath; - + /** + * 单个文件的存储大小 + */ private final int mappedFileSize; - + /** + * MappedFile集合 + */ private final CopyOnWriteArrayList mappedFiles = new CopyOnWriteArrayList(); - + /** + * 创建MappedFile服务类 + */ private final AllocateMappedFileService allocateMappedFileService; - + /** + * 当前刷盘指针,表示该指针之前的所有数据全部持久化到磁盘 + */ private long flushedWhere = 0; + /** + * 当前数据提交指针,内存中ByteBuffer当前的写指针,该值大于、等于flushedWhere + */ private long committedWhere = 0; private volatile long storeTimestamp = 0; @@ -74,6 +100,13 @@ public void checkSelf() { } } + /** + * 根据消息存储时间戳查找MappdFile。从MappedFile列表中第一个 + * 文件开始查找,找到第一个最后一次更新时间大于待查找时间戳的文 + * 件,如果不存在,则返回最后一个MappedFile + * @param timestamp + * @return + */ public MappedFile getMappedFileByTime(final long timestamp) { Object[] mfs = this.copyMappedFiles(0); @@ -101,6 +134,18 @@ private Object[] copyMappedFiles(final int reservedMappedFiles) { return mfs; } + /** + * 删除offset之后的所有文件。遍历目录下的文件,如果 + * 文件的尾部偏移量小于offset则跳过该文件,如果尾部的偏移量大于 + * offset,则进一步比较offset与文件的开始偏移量。如果offset大于 + * 文件的起始偏移量,说明当前文件包含了有效偏移量,设置 + * MappedFile的flushedPosition和committedPosition。如果offset小 + * 于文件的起始偏移量,说明该文件是有效文件后面创建的,则调用 + * MappedFile#destory方法释放MappedFile占用的内存资源(内存映射 + * 与内存通道等),然后加入待删除文件列表中,最终调用 + * deleteExpiredFile将文件从物理磁盘上删除 + * @param offset + */ public void truncateDirtyFiles(long offset) { List willRemoveFiles = new ArrayList(); @@ -144,6 +189,12 @@ void deleteExpiredFile(List files) { } } + /** + * 加载CommitLog文件,加载 ${ROCKET_HOME}/store/commitlog 目录下所有文件并按照文件名进行 + * 排序。如果文件与配置文件的单个文件大小不一致,将忽略该目录下的所有文件,然后创建MappedFile对象。注意load()方法将 + * wrotePosition、flushedPosition、committedPosition三个指针都设置为文件大小。 + * @return + */ public boolean load() { File dir = new File(this.storePath); File[] files = dir.listFiles(); @@ -152,6 +203,7 @@ public boolean load() { Arrays.sort(files); for (File file : files) { + // if (file.length() != this.mappedFileSize) { log.warn(file + "\t" + file.length() + " length not matched message store config value, please check it manually"); @@ -285,6 +337,10 @@ public boolean resetOffset(long offset) { return true; } + /** + * 获取存储文件最小偏移量。 + * @return + */ public long getMinOffset() { if (!this.mappedFiles.isEmpty()) { @@ -299,6 +355,10 @@ public long getMinOffset() { return -1; } + /** + * 获取存储文件最大偏移量。 + * @return + */ public long getMaxOffset() { MappedFile mappedFile = getLastMappedFile(); if (mappedFile != null) { @@ -453,6 +513,13 @@ public boolean commit(final int commitLeastPages) { } /** + * 根据消息偏移量offset查找MappedFile,但是不能直接使用 + * offset%mappedFileSize。这是因为使用了内存映射,只要是存在于存 + * 储目录下的文件,都需要对应创建内存映射文件,RocketMQ采取定时删除存储文件的策略。 + * 也就是说,在存储文件中,第一个文件不一定是00000000000000000000,因为该文件在某一 + * 时刻会被删除,所以根据offset定位MappedFile的算法为(int) + * ((offset/this.mappedFileSize)-(firstMappedFile.getFileFromOffset()/this.MappedFileSize)) + * * Finds a mapped file by offset. * * @param offset Offset. @@ -472,6 +539,7 @@ public MappedFile findMappedFileByOffset(final long offset, final boolean return this.mappedFileSize, this.mappedFiles.size()); } else { + // 计算文件索引 int index = (int) ((offset / this.mappedFileSize) - (firstMappedFile.getFileFromOffset() / this.mappedFileSize)); MappedFile targetFile = null; try { diff --git a/store/src/main/java/org/apache/rocketmq/store/StoreCheckpoint.java b/store/src/main/java/org/apache/rocketmq/store/StoreCheckpoint.java index 7e6c706942b..c65c57c6e01 100644 --- a/store/src/main/java/org/apache/rocketmq/store/StoreCheckpoint.java +++ b/store/src/main/java/org/apache/rocketmq/store/StoreCheckpoint.java @@ -27,13 +27,27 @@ import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; +/** + * checkpoint(检查点)文件的作用是记录ComitLog、 + * ConsumeQueue、Index文件的刷盘时间点,文件固定长度为4KB,其中 + * 只用该文件的前面24字节。 + */ public class StoreCheckpoint { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.STORE_LOGGER_NAME); private final RandomAccessFile randomAccessFile; private final FileChannel fileChannel; private final MappedByteBuffer mappedByteBuffer; + /** + * CommitLog文件刷盘时间点。 + */ private volatile long physicMsgTimestamp = 0; + /** + * ConsumeQueue文件刷盘时间点。 + */ private volatile long logicsMsgTimestamp = 0; + /** + * Index文件刷盘时间点。 + */ private volatile long indexMsgTimestamp = 0; public StoreCheckpoint(final String scpPath) throws IOException { diff --git a/store/src/main/java/org/apache/rocketmq/store/TransientStorePool.java b/store/src/main/java/org/apache/rocketmq/store/TransientStorePool.java index f692a99b1cc..1e3d9cb08e0 100644 --- a/store/src/main/java/org/apache/rocketmq/store/TransientStorePool.java +++ b/store/src/main/java/org/apache/rocketmq/store/TransientStorePool.java @@ -28,11 +28,28 @@ import org.apache.rocketmq.store.util.LibC; import sun.nio.ch.DirectBuffer; +/** + * TransientStorePool即短暂的存储池。RocketMQ单独创建了一个 + * DirectByteBuffer内存缓存池,用来临时存储数据,数据先写入该内 + * 存映射中,然后由Commit线程定时将数据从该内存复制到与目标物理 + * 文件对应的内存映射中。RokcetMQ引入该机制是为了提供一种内存锁 + * 定,将当前堆外内存一直锁定在内存中,避免被进程将内存交换到磁 + * 盘中。 + */ public class TransientStorePool { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.STORE_LOGGER_NAME); + /** + * avaliableBuffers个数,可在broker配置文件中通过transient StorePoolSize进行设置,默认为5 + */ private final int poolSize; + /** + * 每个ByteBuffer的大小,默认为mapedFileSizeCommitLog,表明TransientStorePool为CommitLog文件服务。 + */ private final int fileSize; + /** + * ByteBuffer容器,双端队列。 + */ private final Deque availableBuffers; private final MessageStoreConfig storeConfig; diff --git a/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java b/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java index 7891f71067a..cf4198edaa8 100644 --- a/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java +++ b/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java @@ -107,6 +107,9 @@ public class MessageStoreConfig { private int maxTransferCountOnMessageInDisk = 8; @ImportantField private int accessMessageInMemoryMaxRatio = 40; + /** + * 是否开启消息索引 + */ @ImportantField private boolean messageIndexEnable = true; private int maxHashSlotNum = 5000000; diff --git a/store/src/main/java/org/apache/rocketmq/store/index/IndexFile.java b/store/src/main/java/org/apache/rocketmq/store/index/IndexFile.java index 3d76b73dc28..49c9581d8d3 100644 --- a/store/src/main/java/org/apache/rocketmq/store/index/IndexFile.java +++ b/store/src/main/java/org/apache/rocketmq/store/index/IndexFile.java @@ -27,9 +27,27 @@ import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.store.MappedFile; +/** + * ConsumeQueue是RocketMQ专门为消息订阅构建的索引文件,目的 + * 是提高根据主题与消息队列检索消息的速度。另外,RocketMQ引入哈 + * 希索引机制为消息建立索引,HashMap的设计包含两个基本点:哈希槽 + * 与哈希冲突的链表结构。 + * + * Index文件基于物理磁盘文件实现哈希索引。Index文件由40字节的文件头、 + * 500万个哈希槽、2000万个Index条目组成,每个哈希槽4字节、每个Index + * 条目含有20个字节,分别为4字节索引key的哈希码、8字节消息物理偏移量、 + * 4字节时间戳、4字节的前一个Index条目(哈希冲突的链表结构)。 + */ public class IndexFile { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.STORE_LOGGER_NAME); + /** + * 一个hash槽为4字节 + */ private static int hashSlotSize = 4; + /** + * 一个Index条目为20字节固定长度。分别为4字节索引key的哈希码、8字节消息物理偏移量、 + * 4字节时间戳、4字节的前一个Index条目(哈希冲突的链表结构) + */ private static int indexSize = 20; private static int invalidIndex = 0; private final int hashSlotNum; @@ -89,10 +107,22 @@ public boolean destroy(final long intervalForcibly) { return this.mappedFile.destroy(intervalForcibly); } + /** + * 将消息索引键与消息偏移量的映射关系写入Index的实现 + * @param key + * @param phyOffset + * @param storeTimestamp + * @return + */ public boolean putKey(final String key, final long phyOffset, final long storeTimestamp) { + // 当前已使用条目大于、等于允许最大条目数时,返回false,表示当前Index文件已写满。 if (this.indexHeader.getIndexCount() < this.indexNum) { + // 如果当前index文件未写满 + // 计算key的hashcode int keyHash = indexKeyHashMethod(key); + // 根据keyHash对哈希槽数量取余定位到哈希码对应的哈希槽下标 int slotPos = keyHash % this.hashSlotNum; + // 根据hash下标,计算hash槽在文件中的绝对偏移量 int absSlotPos = IndexHeader.INDEX_HEADER_SIZE + slotPos * hashSlotSize; FileLock fileLock = null; @@ -101,11 +131,13 @@ public boolean putKey(final String key, final long phyOffset, final long storeTi // fileLock = this.fileChannel.lock(absSlotPos, hashSlotSize, // false); + // 获取hash槽中的数据,代表当前 hash 槽指向的index条目索引 int slotValue = this.mappedByteBuffer.getInt(absSlotPos); if (slotValue <= invalidIndex || slotValue > this.indexHeader.getIndexCount()) { slotValue = invalidIndex; } + // 计算待存储消息的时间戳与第一条消息时间戳的差值,并转换成秒, long timeDiff = storeTimestamp - this.indexHeader.getBeginTimestamp(); timeDiff = timeDiff / 1000; @@ -118,17 +150,29 @@ public boolean putKey(final String key, final long phyOffset, final long storeTi timeDiff = 0; } + // 计算Index条目在文件中的绝对位置 int absIndexPos = IndexHeader.INDEX_HEADER_SIZE + this.hashSlotNum * hashSlotSize + this.indexHeader.getIndexCount() * indexSize; - + // 写入 4字节 key hash,值得注意的是,Index文件条目中存储的不是消息索 + //引key,而是消息属性key的哈希,在根据key查找时需要根据消息物理 + //偏移量找到消息,进而验证消息key的值。之所以只存储哈希,而不存 + //储具体的key,是为了将Index条目设计为定长结构,才能方便地检索 + //与定位条目 this.mappedByteBuffer.putInt(absIndexPos, keyHash); + // 写入 8字节 消息物理偏移量 this.mappedByteBuffer.putLong(absIndexPos + 4, phyOffset); + // 写入 4字节 时间戳 this.mappedByteBuffer.putInt(absIndexPos + 4 + 8, (int) timeDiff); + // 写入 4字节 前一个Index条目(哈希冲突的链表结构) this.mappedByteBuffer.putInt(absIndexPos + 4 + 8 + 4, slotValue); + // 写入 hash 槽中的数据,是当前 index 条目的下表索引 this.mappedByteBuffer.putInt(absSlotPos, this.indexHeader.getIndexCount()); + // 更新文件索引头信息。如果当前文件只包含一个条目, + //则更新beginPhyOffset、beginTimestamp、endPyhOffset、 + //endTimestamp以及当前文件使用索引条目等信息 if (this.indexHeader.getIndexCount() <= 1) { this.indexHeader.setBeginPhyOffset(phyOffset); this.indexHeader.setBeginTimestamp(storeTimestamp); @@ -186,11 +230,23 @@ public boolean isTimeMatched(final long begin, final long end) { return result; } + /** + * RocketMQ根据索引key查找消息的实现方法 + * @param phyOffsets 查找到的消息物理偏移量。 + * @param key 索引key + * @param maxNum 本次查找最大消息条数 + * @param begin 开始时间戳 + * @param end 结束时间戳 + * @param lock + */ public void selectPhyOffset(final List phyOffsets, final String key, final int maxNum, final long begin, final long end, boolean lock) { if (this.mappedFile.hold()) { + // 算出 key 的 hash值 int keyHash = indexKeyHashMethod(key); + // keyHash对哈希槽数量取余,定位到哈希码对应的哈希槽下标 int slotPos = keyHash % this.hashSlotNum; + // 哈希槽的物理地址为IndexHeader(40字节)加上下标乘以每个哈希槽的大小(4字节)得到hash槽在Index文件中的绝对地址 int absSlotPos = IndexHeader.INDEX_HEADER_SIZE + slotPos * hashSlotSize; FileLock fileLock = null; @@ -200,6 +256,7 @@ public void selectPhyOffset(final List phyOffsets, final String key, final // hashSlotSize, true); } + // 获取 hash 槽中的数据,该值为hash槽对应的Index链表中第一个Index条目的索引下标 int slotValue = this.mappedByteBuffer.getInt(absSlotPos); // if (fileLock != null) { // fileLock.release(); @@ -208,20 +265,25 @@ public void selectPhyOffset(final List phyOffsets, final String key, final if (slotValue <= invalidIndex || slotValue > this.indexHeader.getIndexCount() || this.indexHeader.getIndexCount() <= 1) { + // 代表当前hash槽的Index条目为空,及key未命中任何条目 } else { for (int nextIndexToRead = slotValue; ; ) { if (phyOffsets.size() >= maxNum) { break; } + // 根据Index下标,计算index条目在文件中的绝对地址 int absIndexPos = IndexHeader.INDEX_HEADER_SIZE + this.hashSlotNum * hashSlotSize + nextIndexToRead * indexSize; + // 获取Index条目的 key hash int keyHashRead = this.mappedByteBuffer.getInt(absIndexPos); + // 获取消息物理偏移量 long phyOffsetRead = this.mappedByteBuffer.getLong(absIndexPos + 4); - + // 获取时间戳 long timeDiff = (long) this.mappedByteBuffer.getInt(absIndexPos + 4 + 8); + // 获取链表中下一个Index条目索引下标 int prevIndexRead = this.mappedByteBuffer.getInt(absIndexPos + 4 + 8 + 4); if (timeDiff < 0) { @@ -232,7 +294,7 @@ public void selectPhyOffset(final List phyOffsets, final String key, final long timeRead = this.indexHeader.getBeginTimestamp() + timeDiff; boolean timeMatched = (timeRead >= begin) && (timeRead <= end); - + // 判断key hash是否一致 以及 消息存储时间是否满足要求 if (keyHash == keyHashRead && timeMatched) { phyOffsets.add(phyOffsetRead); } @@ -242,7 +304,7 @@ public void selectPhyOffset(final List phyOffsets, final String key, final || prevIndexRead == nextIndexToRead || timeRead < begin) { break; } - + // 将指针指向链表下一个元素 nextIndexToRead = prevIndexRead; } } diff --git a/store/src/main/java/org/apache/rocketmq/store/index/IndexHeader.java b/store/src/main/java/org/apache/rocketmq/store/index/IndexHeader.java index 44021cd5895..dc9405bbf21 100644 --- a/store/src/main/java/org/apache/rocketmq/store/index/IndexHeader.java +++ b/store/src/main/java/org/apache/rocketmq/store/index/IndexHeader.java @@ -29,12 +29,29 @@ public class IndexHeader { private static int hashSlotcountIndex = 32; private static int indexCountIndex = 36; private final ByteBuffer byteBuffer; + /** + * Index文件中消息的最小存储时间 + */ private AtomicLong beginTimestamp = new AtomicLong(0); + /** + * Index文件中消息的最大存储时间。 + */ private AtomicLong endTimestamp = new AtomicLong(0); + /** + * Index文件中消息的最小物理偏移量(CommitLog文件偏移量) + */ private AtomicLong beginPhyOffset = new AtomicLong(0); + /** + * Index文件中消息的最大物理偏移量(CommitLog文件偏移量)。 + */ private AtomicLong endPhyOffset = new AtomicLong(0); private AtomicInteger hashSlotCount = new AtomicInteger(0); - + /** + * Index条目列表当前已使用的个数,Index条目在Index条目列表中按顺序存储。 + * 一个Index默认包含500万个哈希槽。哈希槽存储的是落在该哈希 + * 槽的哈希码最新的Index索引。默认一个Index文件包含2000万个条 + * 目 + */ private AtomicInteger indexCount = new AtomicInteger(1); public IndexHeader(final ByteBuffer byteBuffer) { diff --git a/store/src/main/java/org/apache/rocketmq/store/index/IndexService.java b/store/src/main/java/org/apache/rocketmq/store/index/IndexService.java index bf17ecffeaf..a9e72abeb9f 100644 --- a/store/src/main/java/org/apache/rocketmq/store/index/IndexService.java +++ b/store/src/main/java/org/apache/rocketmq/store/index/IndexService.java @@ -54,6 +54,13 @@ public IndexService(final DefaultMessageStore store) { StorePathConfigHelper.getStorePathIndex(store.getMessageStoreConfig().getStorePathRootDir()); } + /** + * 加载Index文件 + * + * 如果上次异常退出,而且Index文件刷盘时间小于该文件最大的消息时间戳,则该文件将立即销毁 + * @param lastExitOK + * @return + */ public boolean load(final boolean lastExitOK) { File dir = new File(this.storePath); File[] files = dir.listFiles(); @@ -206,6 +213,9 @@ public void buildIndex(DispatchRequest req) { String topic = msg.getTopic(); String keys = msg.getKeys(); if (msg.getCommitLogOffset() < endPhyOffset) { + // 获取或创建Index文件并获取所有文件最大的物理偏移 + //量。如果该消息的物理偏移量小于Index文件中的物理偏移量,则说明 + //是重复数据,忽略本次索引构建 return; } @@ -219,6 +229,7 @@ public void buildIndex(DispatchRequest req) { return; } + // 如果消息的唯一键不为空,则添加到哈希索引中,以便加速根据唯一键检索消息 if (req.getUniqKey() != null) { indexFile = putKey(indexFile, msg, buildKey(topic, req.getUniqKey())); if (indexFile == null) { @@ -227,6 +238,7 @@ public void buildIndex(DispatchRequest req) { } } + // 构建索引键,RocketMQ支持为同一个消息建立多个索引,多个索引键用空格分开 if (keys != null && keys.length() > 0) { String[] keyset = keys.split(MessageConst.KEY_SEPARATOR); for (int i = 0; i < keyset.length; i++) { From fb223db4736c01d37805d8580fa3e40ade050663 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Thu, 12 Oct 2023 15:35:25 +0800 Subject: [PATCH 04/18] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E5=AD=98=E5=82=A8=E6=B5=81=E7=A8=8B=E4=BB=A3=E7=A0=81=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/rocketmq/store/CommitLog.java | 62 +++++++++++++++++++ .../rocketmq/store/DefaultMessageStore.java | 44 ++++++++++++- .../org/apache/rocketmq/store/MappedFile.java | 1 + .../rocketmq/store/MappedFileQueue.java | 3 + .../store/config/MessageStoreConfig.java | 47 ++++++++++++++ 5 files changed, 154 insertions(+), 3 deletions(-) diff --git a/store/src/main/java/org/apache/rocketmq/store/CommitLog.java b/store/src/main/java/org/apache/rocketmq/store/CommitLog.java index 581ff40afa7..b66d4f692f4 100644 --- a/store/src/main/java/org/apache/rocketmq/store/CommitLog.java +++ b/store/src/main/java/org/apache/rocketmq/store/CommitLog.java @@ -446,6 +446,7 @@ public void recoverAbnormally(long maxPhyOffsetOfConsumeQueue) { MappedFile mappedFile = null; for (; index >= 0; index--) { mappedFile = mappedFiles.get(index); + // 判断文件的魔数,如果不是MESSAGE_MAGIC_CODE,则返回false,表示该文件不符合CommitLog文件的存储格式 if (this.isMappedFileMatchedRecover(mappedFile)) { log.info("recover from this mapped file " + mappedFile.getFileName()); break; @@ -471,9 +472,11 @@ public void recoverAbnormally(long maxPhyOffsetOfConsumeQueue) { if (this.defaultMessageStore.getMessageStoreConfig().isDuplicationEnable()) { if (dispatchRequest.getCommitLogOffset() < this.defaultMessageStore.getConfirmOffset()) { + // 遍历MappedFile中的消息,验证消息的合法性,并将消息重新转发到ConsumeQueue与Index文件 this.defaultMessageStore.doDispatch(dispatchRequest); } } else { + // 遍历MappedFile中的消息,验证消息的合法性,并将消息重新转发到ConsumeQueue与Index文件 this.defaultMessageStore.doDispatch(dispatchRequest); } } @@ -534,9 +537,14 @@ private boolean isMappedFileMatchedRecover(final MappedFile mappedFile) { int msgStoreTimePos = 4 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 8 + bornhostLength; long storeTimestamp = byteBuffer.getLong(msgStoreTimePos); if (0 == storeTimestamp) { + //如果文件中第一条消息的存储时间等于0,则返回false,说明该消息的存储文件中未存储任何消息 return false; } + // 对比文件第一条消息的时间戳与检测点。如果文件第一条消息的时间戳小于文件检测点,说明该文件的部分消息是可靠的, + // 则从该文件开始恢复。checkpoint文件中保存了CommitLog、ConsumeQueue、Index的文件刷盘点,RocketMQ默认选择CommitLog文 + // 件与ConsumeQueue这两个文件的刷盘点中较小值与CommitLog文件第一条消息的时间戳做对比,如果messageIndexEnable为true,表示Index + // 文件的刷盘时间点也参与计算 if (this.defaultMessageStore.getMessageStoreConfig().isMessageIndexEnable() && this.defaultMessageStore.getMessageStoreConfig().isMessageIndexSafe()) { if (storeTimestamp <= this.defaultMessageStore.getStoreCheckpoint().getMinTimestampIndex()) { @@ -705,13 +713,24 @@ public PutMessageResult putMessage(final MessageExtBrokerInner msg) { return putMessageResult; } + /** + * 触发刷盘CommitLog + * @param result + * @param putMessageResult + * @param messageExt + */ public void handleDiskFlush(AppendMessageResult result, PutMessageResult putMessageResult, MessageExt messageExt) { // Synchronization flush if (FlushDiskType.SYNC_FLUSH == this.defaultMessageStore.getMessageStoreConfig().getFlushDiskType()) { + // 如果是同步刷盘 + final GroupCommitService service = (GroupCommitService) this.flushCommitLogService; if (messageExt.isWaitStoreMsgOK()) { + // 构建GroupCommitRequest同步任务并提交到GroupCommitRequest。 GroupCommitRequest request = new GroupCommitRequest(result.getWroteOffset() + result.getWroteBytes()); + // 将同步任务GroupCommitRequest提交到GroupCommitService线程 service.putRequest(request); + // 等待同步刷盘任务完成,异步刷盘线程刷写完毕后会唤醒当前线程,超时时间默认为5s,如果超时则返回刷盘错误,刷盘成功后正常返回给调用方。 boolean flushOK = request.waitForFlush(this.defaultMessageStore.getMessageStoreConfig().getSyncFlushTimeout()); if (!flushOK) { log.error("do groupcommit, wait for flush failed, topic: " + messageExt.getTopic() + " tags: " + messageExt.getTags() @@ -724,9 +743,14 @@ public void handleDiskFlush(AppendMessageResult result, PutMessageResult putMess } // Asynchronous flush else { + // 异步刷盘 if (!this.defaultMessageStore.getMessageStoreConfig().isTransientStorePoolEnable()) { + // 如果transientStorePoolEnable为false,消息将追加到与物理文件直接映射的内存中,然后写入磁盘 flushCommitLogService.wakeup(); } else { + // 如果transientStorePoolEnable为true,RocketMQ会单独申请一个与目标物理文件(CommitLog)同样大 + // 小的堆外内存,该堆外内存将使用内存锁定,确保不会被置换到虚拟内存中去,消息首先追加到堆外内存,然后提交到与物理文件的内存 + // 映射中,再经flush操作到磁盘 commitLogService.wakeup(); } } @@ -1001,6 +1025,7 @@ abstract class FlushCommitLogService extends ServiceThread { protected static final int RETRY_TIMES_OVER = 10; } + class CommitRealTimeService extends FlushCommitLogService { private long lastCommitTimestamp = 0; @@ -1054,6 +1079,9 @@ public void run() { } } + /** + * CommitLog 内存映射机制定时刷盘线程 + */ class FlushRealTimeService extends FlushCommitLogService { private long lastFlushTimestamp = 0; private long printTimes = 0; @@ -1062,11 +1090,15 @@ public void run() { CommitLog.log.info(this.getServiceName() + " service started"); while (!this.isStopped()) { + // 默认为false,表示使用await方法等待;如果为true,表示使用Thread.sleep方法等待 boolean flushCommitLogTimed = CommitLog.this.defaultMessageStore.getMessageStoreConfig().isFlushCommitLogTimed(); + // FlushRealTimeService线程任务运行间隔时间 int interval = CommitLog.this.defaultMessageStore.getMessageStoreConfig().getFlushIntervalCommitLog(); + // 一次刷盘任务至少包含页数,如果待写入数据不足,小于该参数配置的值,将忽略本次刷盘任务,默认4页 int flushPhysicQueueLeastPages = CommitLog.this.defaultMessageStore.getMessageStoreConfig().getFlushCommitLogLeastPages(); + // 两次真实刷盘任务的最大间隔时间,默认10s int flushPhysicQueueThoroughInterval = CommitLog.this.defaultMessageStore.getMessageStoreConfig().getFlushCommitLogThoroughInterval(); @@ -1075,12 +1107,15 @@ public void run() { // Print flush progress long currentTimeMillis = System.currentTimeMillis(); if (currentTimeMillis >= (this.lastFlushTimestamp + flushPhysicQueueThoroughInterval)) { + // 如果距上次提交数据的间隔时间超过flushPhysicQueueThoroughInterval,则本次刷盘任务将忽略 + //flushPhysicQueueLeastPages,也就是如果待写入数据小于指定页数,也执行刷盘操作。 this.lastFlushTimestamp = currentTimeMillis; flushPhysicQueueLeastPages = 0; printFlushProgress = (printTimes++ % 10) == 0; } try { + // 执行一次刷盘任务前先等待指定时间间隔,然后执行刷盘任务 if (flushCommitLogTimed) { Thread.sleep(interval); } else { @@ -1092,9 +1127,11 @@ public void run() { } long begin = System.currentTimeMillis(); + // 执行刷盘操作 CommitLog.this.mappedFileQueue.flush(flushPhysicQueueLeastPages); long storeTimestamp = CommitLog.this.mappedFileQueue.getStoreTimestamp(); if (storeTimestamp > 0) { + // 更新checkpoint中存储的CommitLog文件刷盘时间点。 CommitLog.this.defaultMessageStore.getStoreCheckpoint().setPhysicMsgTimestamp(storeTimestamp); } long past = System.currentTimeMillis() - begin; @@ -1136,8 +1173,15 @@ public long getJointime() { } public static class GroupCommitRequest { + + /** + * 刷盘点偏移量 + */ private final long nextOffset; private final CountDownLatch countDownLatch = new CountDownLatch(1); + /** + * 刷盘结果 + */ private volatile boolean flushOK = false; public GroupCommitRequest(long nextOffset) { @@ -1168,13 +1212,21 @@ public boolean waitForFlush(long timeout) { * GroupCommit Service */ class GroupCommitService extends FlushCommitLogService { + + /** + * 同步刷盘任务暂存容器 + */ private volatile List requestsWrite = new ArrayList(); + /** + * GroupCommitService线程每次处理的request容器,这是一个设计亮点,避免了任务提交与任务执行的锁冲突 + */ private volatile List requestsRead = new ArrayList(); public synchronized void putRequest(final GroupCommitRequest request) { synchronized (this.requestsWrite) { this.requestsWrite.add(request); } + // 将hasNotified设置为true,这样GroupCommitService线程就会立即执行刷盘操作 if (hasNotified.compareAndSet(false, true)) { waitPoint.countDown(); // notify } @@ -1197,15 +1249,19 @@ private void doCommit() { flushOK = CommitLog.this.mappedFileQueue.getFlushedWhere() >= req.getNextOffset(); if (!flushOK) { + // 同步刷盘 CommitLog.this.mappedFileQueue.flush(0); } } + // 每执行一次刷盘操作后,立即调用GroupCommitRequest#wakeupCustomer唤醒消息发送线程并通知刷盘结果 req.wakeupCustomer(flushOK); } long storeTimestamp = CommitLog.this.mappedFileQueue.getStoreTimestamp(); if (storeTimestamp > 0) { + //处理完所有同步刷盘任务后,更新刷盘检测点StoreCheckpoint中的physicMsg Timestamp,但并没有执行检测点的 + //刷盘操作,检测点的刷盘操作将在刷写消息队列文件时触发 CommitLog.this.defaultMessageStore.getStoreCheckpoint().setPhysicMsgTimestamp(storeTimestamp); } @@ -1218,12 +1274,18 @@ private void doCommit() { } } + /** + * GroupCommitService组提交线程,每处理一批刷盘请求后,如果 + * 后续有待刷盘的请求需要处理(hasNotified=true),组提交线程会马不停蹄地处理下一 + * 批;如果没有待处理的任务,则休息10ms,即每10ms空转一次 + */ public void run() { CommitLog.log.info(this.getServiceName() + " service started"); while (!this.isStopped()) { try { this.waitForRunning(10); + // 执行刷盘操作 this.doCommit(); } catch (Exception e) { CommitLog.log.warn(this.getServiceName() + " service has exception. ", e); diff --git a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java index 8992df9a80d..3f61af65c3a 100644 --- a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java +++ b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java @@ -1296,6 +1296,9 @@ private void createTempFile() throws IOException { private void addScheduleTask() { + // RocketMQ每隔10s调度一次cleanFilesPeriodically,检测是否需 + // 要清除过期文件。执行频率可以通过cleanResourceInterval进行设 + //置,默认10s this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { @@ -1435,10 +1438,10 @@ private void recover(final boolean lastExitOK) { long maxPhyOffsetOfConsumeQueue = this.recoverConsumeQueue(); if (lastExitOK) { - // 正常停止 + // 正常停止,恢复CommitLog this.commitLog.recoverNormally(maxPhyOffsetOfConsumeQueue); } else { - // 异常停止 + // 异常停止,恢复CommitLog this.commitLog.recoverAbnormally(maxPhyOffsetOfConsumeQueue); } @@ -1628,12 +1631,23 @@ public void dispatch(DispatchRequest request) { } } + /** + * CommitLog过期清理实现 + */ class CleanCommitLogService { private final static int MAX_MANUAL_DELETE_FILE_TIMES = 20; + /** + * 通过系统参数 -Drocketmq.broker.diskSpaceWarningLevelRatio进行设置, + * 默认0.90。如果磁盘分区使用率超过该阈值,将设置磁盘为不可写,此时会拒绝写入新消息 + */ private final double diskSpaceWarningLevelRatio = Double.parseDouble(System.getProperty("rocketmq.broker.diskSpaceWarningLevelRatio", "0.90")); + /** + * 通过系统参数 -Drocketmq.broker.diskSpaceCleanForcibly-Ratio进行设置, + * 默认0.85。如果磁盘分区使用超过该阈值,建议立即执行过期文件删除,但不会拒绝写入新消息 + */ private final double diskSpaceCleanForciblyRatio = Double.parseDouble(System.getProperty("rocketmq.broker.diskSpaceCleanForciblyRatio", "0.85")); private long lastRedeleteTimestamp = 0; @@ -1659,14 +1673,24 @@ public void run() { private void deleteExpiredFiles() { int deleteCount = 0; + // 文件保留时间,如果超过了该时间,则认为是过期文件,可以被删除。单位:小时 long fileReservedTime = DefaultMessageStore.this.getMessageStoreConfig().getFileReservedTime(); + // 删除物理文件的间隔时间,在一次清除过程中,可能需要被删除的文件不止一个,该值指定两次删除文件的间隔时间 int deletePhysicFilesInterval = DefaultMessageStore.this.getMessageStoreConfig().getDeleteCommitLogFilesInterval(); + // 在清除过期文件时,如果该文件被其他线程占用(引用次数大于0,比如读取消息),此时会 + // 阻止此次删除任务,同时在第一次试图删除该文件时记录当前时间戳,destroyMapedFileIntervalForcibly表示第一次拒绝删除之后能 + // 保留文件的最大时间,在此时间内,同样可以被拒绝删除,超过该时间后,会将引用次数设置为负数,文件将被强制删除 int destroyMapedFileIntervalForcibly = DefaultMessageStore.this.getMessageStoreConfig().getDestroyMapedFileIntervalForcibly(); + // 指定删除文件的时间点,RocketMQ通过deleteWhen设置每天在固定时间执行一次删除过期文件操作,默认凌晨4点 boolean timeup = this.isTimeToDelete(); + // 检查磁盘空间是否充足,如果磁盘占用达到阈值(默认90%)则会将broker设置为不可写状态, + // 如果磁盘空间不充足(默认使用率达到75%),则返回true,表示应该触发过期文件删除操作 boolean spacefull = this.isSpaceToDelete(); + // 预留手工触发机制,可以通过调用excuteDeleteFilesManualy方法手工触发删除过期文件的操作,目前RocketMQ暂未封装手工触发文件删除的命令 boolean manualDelete = this.manualDeleteFileSeveralTimes > 0; + // 满足任意一种情况,则触发过期文件删除功能 if (timeup || spacefull || manualDelete) { if (manualDelete) @@ -1683,6 +1707,7 @@ private void deleteExpiredFiles() { fileReservedTime *= 60 * 60 * 1000; + // 执行删除操作 deleteCount = DefaultMessageStore.this.commitLog.deleteExpiredFile(fileReservedTime, deletePhysicFilesInterval, destroyMapedFileIntervalForcibly, cleanAtOnce); if (deleteCount > 0) { @@ -1719,35 +1744,45 @@ private boolean isTimeToDelete() { } private boolean isSpaceToDelete() { + // 表示CommitLog文件、ConsumeQueue文件所在磁盘分区的最大使用量,如果超过该值,则需要立即清除过期文件,默认 75% double ratio = DefaultMessageStore.this.getMessageStoreConfig().getDiskMaxUsedSpaceRatio() / 100.0; + // 表示是否需要立即执行清除过期文件的操作 cleanImmediately = false; + // CommitLog存储空间计算 { String storePathPhysic = DefaultMessageStore.this.getMessageStoreConfig().getStorePathCommitLog(); + // 当前CommitLog目录所在的磁盘分区的磁盘使用率,通过File#getTotalSpace方法获取文件所在磁盘分区的总容量, + // 通过File#getFreeSpace方法获取文件所在磁盘分区的剩余容量 double physicRatio = UtilAll.getDiskPartitionSpaceUsedPercent(storePathPhysic); if (physicRatio > diskSpaceWarningLevelRatio) { + // 将broker设置为不可写状态 boolean diskok = DefaultMessageStore.this.runningFlags.getAndMakeDiskFull(); if (diskok) { DefaultMessageStore.log.error("physic disk maybe full soon " + physicRatio + ", so mark disk full"); } - + // 设置为需要立即清理 cleanImmediately = true; } else if (physicRatio > diskSpaceCleanForciblyRatio) { + // 设置为需要立即清理 cleanImmediately = true; } else { + // 恢复broker为可写状态 boolean diskok = DefaultMessageStore.this.runningFlags.getAndMakeDiskOK(); if (!diskok) { DefaultMessageStore.log.info("physic disk space OK " + physicRatio + ", so mark disk ok"); } } + // 判断磁盘使用率,是否达到指定值(默认75%) if (physicRatio < 0 || physicRatio > ratio) { DefaultMessageStore.log.info("physic disk maybe full soon, so reclaim space, " + physicRatio); return true; } } + // ConsumeQueue 存储空间计算 { String storePathLogics = StorePathConfigHelper .getStorePathConsumeQueue(DefaultMessageStore.this.getMessageStoreConfig().getStorePathRootDir()); @@ -1786,6 +1821,9 @@ public void setManualDeleteFileSeveralTimes(int manualDeleteFileSeveralTimes) { } } + /** + * ConsumeQueue过期清理实现 + */ class CleanConsumeQueueService { private long lastPhysicalMinOffset = 0; diff --git a/store/src/main/java/org/apache/rocketmq/store/MappedFile.java b/store/src/main/java/org/apache/rocketmq/store/MappedFile.java index f5765ad22c5..fe22139ba7f 100644 --- a/store/src/main/java/org/apache/rocketmq/store/MappedFile.java +++ b/store/src/main/java/org/apache/rocketmq/store/MappedFile.java @@ -526,6 +526,7 @@ public boolean destroy(final long intervalForcibly) { log.info("close file channel " + this.fileName + " OK"); long beginTime = System.currentTimeMillis(); + // 删除文件 boolean result = this.file.delete(); log.info("delete file[REF:" + this.getRefCount() + "] " + this.fileName + (result ? " OK, " : " Failed, ") + "W:" + this.getWrotePosition() + " M:" diff --git a/store/src/main/java/org/apache/rocketmq/store/MappedFileQueue.java b/store/src/main/java/org/apache/rocketmq/store/MappedFileQueue.java index 1210bb0f064..b6e6c21427c 100644 --- a/store/src/main/java/org/apache/rocketmq/store/MappedFileQueue.java +++ b/store/src/main/java/org/apache/rocketmq/store/MappedFileQueue.java @@ -409,6 +409,9 @@ public int deleteExpiredFileByTime(final long expiredTime, for (int i = 0; i < mfsLength; i++) { MappedFile mappedFile = (MappedFile) mfs[i]; long liveMaxTimestamp = mappedFile.getLastModifiedTimestamp() + expiredTime; + // 从倒数第二个文件开始遍历,计算文件的最大存活时间,即文件的最后一次更新时间+文件存活时间(默认 + // 72小时),如果当前时间大于文件的最大存活时间或需要强制删除文件(当磁盘使用超过设定的阈值)时,执行MappedFile#destory方 + // 法,清除MappedFile占有的相关资源,如果执行成功,将该文件加入待删除文件列表中,最后统一执行File#delete方法将文件从物理磁盘中删除 if (System.currentTimeMillis() >= liveMaxTimestamp || cleanImmediately) { if (mappedFile.destroy(intervalForcibly)) { files.add(mappedFile); diff --git a/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java b/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java index cf4198edaa8..16d48e072f3 100644 --- a/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java +++ b/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java @@ -44,6 +44,9 @@ public class MessageStoreConfig { // CommitLog flush interval // flush data to disk + /** + * ConmmitLog 刷盘线程任务运行间隔时间 + */ @ImportantField private int flushIntervalCommitLog = 500; @@ -68,14 +71,29 @@ public class MessageStoreConfig { // CommitLog removal interval private int deleteCommitLogFilesInterval = 100; // ConsumeQueue removal interval + /** + * 删除物理文件的间隔时间,在一次清除过程中,可能需要被删除的文件不止一个,该值指定两次删除文件的间隔时间 + */ private int deleteConsumeQueueFilesInterval = 100; + /** + * 在清除过期文件时,如果该文件被其他线程占用(引用次数大于0,比如读取消息),此时会 + * 阻止此次删除任务,同时在第一次试图删除该文件时记录当前时间戳,destroyMapedFileIntervalForcibly表示第一次拒绝删除之后能 + * 保留文件的最大时间,在此时间内,同样可以被拒绝删除,超过该时间后,会将引用次数设置为负数,文件将被强制删除 + */ private int destroyMapedFileIntervalForcibly = 1000 * 120; private int redeleteHangedFileInterval = 1000 * 120; // When to delete,default is at 4 am @ImportantField private String deleteWhen = "04"; + /** + * 表示CommitLog文件、ConsumeQueue文件所在磁盘分区的最大使用量,如果超过该值,则需要立即清除过 + * 期文件,默认 75,如果超过了 75% 就会触发清理过期文件的动作 + */ private int diskMaxUsedSpaceRatio = 75; // The number of hours to keep a log file before deleting it (in hours) + /** + * 日志文件保存的小时数 + */ @ImportantField private int fileReservedTime = 72; // Flow control for ConsumeQueue @@ -87,6 +105,9 @@ public class MessageStoreConfig { // This check adds some overhead,so it may be disabled in cases seeking extreme performance. private boolean checkCRCOnRecover = true; // How many pages are to be flushed when flush CommitLog + /** + * 一次刷盘任务至少包含页数,如果待写入数据不足,小于该参数配置的值,将忽略本次刷盘任务,默认4页 + */ private int flushCommitLogLeastPages = 4; // How many pages are to be committed when commit data to file private int commitCommitLogLeastPages = 4; @@ -94,6 +115,9 @@ public class MessageStoreConfig { private int flushLeastPagesWhenWarmMapedFile = 1024 / 4 * 16; // How many pages are to be flushed when flush ConsumeQueue private int flushConsumeQueueLeastPages = 2; + /** + * 两次真实刷盘任务的最大间隔时间,默认10s + */ private int flushCommitLogThoroughInterval = 1000 * 10; private int commitCommitLogThoroughInterval = 200; private int flushConsumeQueueThoroughInterval = 1000 * 60; @@ -131,6 +155,10 @@ public class MessageStoreConfig { private int syncFlushTimeout = 1000 * 5; private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h"; private long flushDelayOffsetInterval = 1000 * 10; + /** + * 在一些情况下,即使CommitLog文件已经过期,也可能因为某些原因(例如消费者消费速度慢等)而无法被清理。 + * 此时,如果cleanFileForciblyEnable参数被设置为true,那么RocketMQ将会强制地清理这些文件,从而释放磁盘空间。 + */ @ImportantField private boolean cleanFileForciblyEnable = true; private boolean warmMapedFileEnable = false; @@ -141,6 +169,25 @@ public class MessageStoreConfig { private long osPageCacheBusyTimeOutMills = 1000; private int defaultQueryMaxNum = 32; + /** + * 是否开启 transientStorePool 机制 + * + * 开启TransientStorePool机制,消息数据首先被写入到堆外内存(也就是TransientStorePool中的DirectByteBuffer)。然后由刷盘线程(CommitRealTimeService) + * 在合适的时机把数据从堆外内存复制到内存映射区域(MappedByteBuffer),并调用force()方法将数据写入磁盘。 + * + * 有了 TransientStorePool 的存在,消息可以批量写入内存缓冲区,RocketMQ也就可以有效地控制何时以及如何将脏页(Dirty Page,即已修改但还未写入磁盘的内存页) + * 刷写到磁盘,避免了操作系统自动进行的随机性、不可预测的脏页刷写操作,从而提升了I/O性能,特别是在大量写入请求的场景下。 + * + * 值得一提的是,使用TransientStorePool并非没有代价。因为需要额外的一次内存复制操作,即从堆外内存复制到内存映射区域。 + * 但是在大多数情况下,通过控制脏页刷写带来的性能提升,相比于增加的内存复制开销,更加明显。 + * + * 并且开启transientStorePool机制后,由于消息数据会先写入 堆外内存,然后由特定后台线程(CommitRealTimeService),将堆外内存中的修改 + * commit 到 内存映射区域,而这一步如果发生 断电、服务宕机,都会产生消息丢失。而传统的异步刷盘,由于消息是直接写入内存映射区域,所以服务宕机 + * 并不会丢失数据,只有在服务器突然断电时才会丢失少量数据。 + * + * 所以整体来看消息存储可靠性: 同步刷盘(任何情况不会丢失消息)> 异步刷盘+transientStorePool=false(突然断电丢失少量消息)> 异步刷盘+transientStorePool=true(突然断电或服务宕机都会丢失消息) + * + */ @ImportantField private boolean transientStorePoolEnable = false; private int transientStorePoolSize = 5; From 937b843ec2236b2f613098c5d4e3e37e04de8de4 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Fri, 20 Oct 2023 17:00:35 +0800 Subject: [PATCH 05/18] =?UTF-8?q?RocketMQ=E6=B6=88=E6=81=AF=E6=8B=89?= =?UTF-8?q?=E5=8F=96=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../processor/PullMessageProcessor.java | 13 ++++ .../consumer/DefaultMQPushConsumer.java | 37 +++++++++++ .../rocketmq/client/consumer/MQConsumer.java | 11 ++++ .../client/consumer/MQPushConsumer.java | 5 ++ .../rocketmq/client/consumer/PullResult.java | 9 +++ .../client/impl/FindBrokerResult.java | 10 +++ .../consumer/DefaultMQPushConsumerImpl.java | 44 ++++++++++++- .../client/impl/consumer/ProcessQueue.java | 64 +++++++++++++++++++ .../client/impl/consumer/PullAPIWrapper.java | 31 +++++++++ .../impl/consumer/PullMessageService.java | 17 +++++ .../client/impl/consumer/PullRequest.java | 16 +++++ .../client/impl/factory/MQClientInstance.java | 3 + .../impl/producer/DefaultMQProducerImpl.java | 2 + .../impl/producer/TopicPublishInfo.java | 5 ++ .../client/latency/MQFaultStrategy.java | 2 +- .../apache/rocketmq/common/BrokerConfig.java | 3 + .../common/consumer/ConsumeFromWhere.java | 9 +++ .../header/PullMessageRequestHeader.java | 31 +++++++++ .../rocketmq/common/sysflag/PullSysFlag.java | 13 ++++ .../rocketmq/store/DefaultMessageStore.java | 33 ++++++++++ 20 files changed, 356 insertions(+), 2 deletions(-) diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java index b4f6daa05eb..26b11647b68 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java @@ -67,6 +67,9 @@ import org.apache.rocketmq.store.config.BrokerRole; import org.apache.rocketmq.store.stats.BrokerStatsManager; +/** + * 消息拉取请求处理类。处理Consumer端拉取消息的请求。 + */ public class PullMessageProcessor implements NettyRequestProcessor { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME); private final BrokerController brokerController; @@ -98,14 +101,17 @@ private RemotingCommand processRequest(final Channel channel, RemotingCommand re log.debug("receive PullMessage request command, {}", request); + // 判断broker是否可读 if (!PermName.isReadable(this.brokerController.getBrokerConfig().getBrokerPermission())) { response.setCode(ResponseCode.NO_PERMISSION); response.setRemark(String.format("the broker[%s] pulling message is forbidden", this.brokerController.getBrokerConfig().getBrokerIP1())); return response; } + // 获取消费组的配置信息 SubscriptionGroupConfig subscriptionGroupConfig = this.brokerController.getSubscriptionGroupManager().findSubscriptionGroupConfig(requestHeader.getConsumerGroup()); + if (null == subscriptionGroupConfig) { response.setCode(ResponseCode.SUBSCRIPTION_GROUP_NOT_EXIST); response.setRemark(String.format("subscription group [%s] does not exist, %s", requestHeader.getConsumerGroup(), FAQUrl.suggestTodo(FAQUrl.SUBSCRIPTION_GROUP_NOT_EXIST))); @@ -147,6 +153,7 @@ private RemotingCommand processRequest(final Channel channel, RemotingCommand re return response; } + /*********************************构建消息过滤器开始***********************************/ SubscriptionData subscriptionData = null; ConsumerFilterData consumerFilterData = null; if (hasSubscriptionFlag) { @@ -233,10 +240,13 @@ private RemotingCommand processRequest(final Channel channel, RemotingCommand re messageFilter = new ExpressionMessageFilter(subscriptionData, consumerFilterData, this.brokerController.getConsumerFilterManager()); } + /*********************************构建消息过滤器完毕***********************************/ + // 读取broker中存储的消息 final GetMessageResult getMessageResult = this.brokerController.getMessageStore().getMessage(requestHeader.getConsumerGroup(), requestHeader.getTopic(), requestHeader.getQueueId(), requestHeader.getQueueOffset(), requestHeader.getMaxMsgNums(), messageFilter); + if (getMessageResult != null) { response.setRemark(getMessageResult.getStatus().name()); responseHeader.setNextBeginOffset(getMessageResult.getNextBeginOffset()); @@ -406,6 +416,7 @@ public void operationComplete(ChannelFuture future) throws Exception { break; case ResponseCode.PULL_NOT_FOUND: + // broker是否开启了长轮询 以及 客户端是否使用长轮询 if (brokerAllowSuspend && hasSuspendFlag) { long pollingTimeMills = suspendTimeoutMillisLong; if (!this.brokerController.getBrokerConfig().isLongPollingEnable()) { @@ -417,6 +428,7 @@ public void operationComplete(ChannelFuture future) throws Exception { int queueId = requestHeader.getQueueId(); PullRequest pullRequest = new PullRequest(request, channel, pollingTimeMills, this.brokerController.getMessageStore().now(), offset, subscriptionData, messageFilter); + // 每隔5s重试一次 this.brokerController.getPullRequestHoldService().suspendPullRequest(topic, queueId, pullRequest); response = null; break; @@ -464,6 +476,7 @@ public void operationComplete(ChannelFuture future) throws Exception { storeOffsetEnable = storeOffsetEnable && this.brokerController.getMessageStoreConfig().getBrokerRole() != BrokerRole.SLAVE; if (storeOffsetEnable) { + //如果CommitLog标记为可用并且当前节点为主节点,则更新消息消费进度, this.brokerController.getConsumerOffsetManager().commitOffset(RemotingHelper.parseChannelRemoteAddr(channel), requestHeader.getConsumerGroup(), requestHeader.getTopic(), requestHeader.getQueueId(), requestHeader.getCommitOffset()); } diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultMQPushConsumer.java b/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultMQPushConsumer.java index 339f799f9ac..ce9da315262 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultMQPushConsumer.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultMQPushConsumer.java @@ -70,6 +70,8 @@ public class DefaultMQPushConsumer extends ClientConfig implements MQPushConsume protected final transient DefaultMQPushConsumerImpl defaultMQPushConsumerImpl; /** + * 消费者所属组 + * * Consumers of the same role is required to have exactly same subscriptions and consumerGroup to correctly achieve * load balance. It's required and needs to be globally unique. *

@@ -79,6 +81,8 @@ public class DefaultMQPushConsumer extends ClientConfig implements MQPushConsume private String consumerGroup; /** + * 消息消费模式,分为集群模式、广播模式,默认为集群模式 + * * Message model defines the way how messages are delivered to each consumer clients. *

* @@ -93,6 +97,16 @@ public class DefaultMQPushConsumer extends ClientConfig implements MQPushConsume private MessageModel messageModel = MessageModel.CLUSTERING; /** + * 第一次消费时指定消费策略。 + * CONSUME_FROM_LAST_OFFSET:此处分为两种情况,如果磁盘消息未过期且未被删除,则从最小偏移量开始消费。如果磁盘已过期 + * 并被删除,则从最大偏移量开始消费。 + * CONSUME_FROM_FIRST_OFFSET:从队列当前最小偏移量开始消费。 + * CONSUME_FROM_TIMESTAMP:从消费者指定时间戳开始消费。 + * + * 注意:如果从消息进度服务OffsetStore读取到MessageQueue中的 + * 偏移量不小于0,则使用读取到的偏移量拉取消息,只有在读到的偏移 + * 量小于0时,上述策略才会生效 + * * Consuming point on consumer booting. *

* @@ -134,31 +148,37 @@ public class DefaultMQPushConsumer extends ClientConfig implements MQPushConsume private String consumeTimestamp = UtilAll.timeMillisToHumanString3(System.currentTimeMillis() - (1000 * 60 * 30)); /** + * 集群模式下消息队列的负载策略 * Queue allocation algorithm specifying how message queues are allocated to each consumer clients. */ private AllocateMessageQueueStrategy allocateMessageQueueStrategy; /** + * 订阅信息 * Subscription relationship */ private Map subscription = new HashMap(); /** + * 消息业务监听器 * Message listener */ private MessageListener messageListener; /** + * 消息消费进度存储器 * Offset Storage */ private OffsetStore offsetStore; /** + * 消费者最小线程数 * Minimum consumer thread number */ private int consumeThreadMin = 20; /** + * 消费者最大线程数,因为消费者线程池使用无界队列,所以此参数不生效 * Max consumer thread number */ private int consumeThreadMax = 20; @@ -169,17 +189,25 @@ public class DefaultMQPushConsumer extends ClientConfig implements MQPushConsume private long adjustThreadPoolNumsThreshold = 100000; /** + * 并发消息消费时处理队列最大跨度,默认2000,表示如果消息处理队列中偏移量最大的消息 + * 与偏移量最小的消息的跨度超过2000,则延迟50ms后再拉取消息。 * Concurrently max span offset.it has no effect on sequential consumption */ private int consumeConcurrentlyMaxSpan = 2000; /** + * 队列级别的流量控制阈值,默认情况下每个消息队列最多缓存1000条消息; + * * Flow control threshold on queue level, each message queue will cache at most 1000 messages by default, * Consider the {@code pullBatchSize}, the instantaneous value may exceed the limit */ private int pullThresholdForQueue = 1000; /** + * 在队列级别限制缓存的消息大小,默认情况下每个消息队列最多缓存100 MiB消息。 + * 考虑{@code pullBatchSize},瞬时值可能超过限制 + * 消息的大小仅由消息体来衡量,因此不准确 + * * Limit the cached message size on queue level, each message queue will cache at most 100 MiB messages by default, * Consider the {@code pullBatchSize}, the instantaneous value may exceed the limit * @@ -211,21 +239,26 @@ public class DefaultMQPushConsumer extends ClientConfig implements MQPushConsume private int pullThresholdSizeForTopic = -1; /** + * 推模式下拉取任务的间隔时间,默认一次拉取任务完成后继续拉取 * Message pull Interval */ private long pullInterval = 0; /** + * 消息并发消费时一次消费消息的条数,通俗点说,就是每次传入MessageListener#consumeMessage中的消息条数 * Batch consumption size */ private int consumeMessageBatchMaxSize = 1; /** + * 每次消息拉取的条数,默认32条 * Batch pull size */ private int pullBatchSize = 32; /** + * 是否每次拉取消息都更新订阅信息,默认为false + * * Whether update subscription relationship when every pull */ private boolean postSubscriptionWhenPull = false; @@ -236,6 +269,8 @@ public class DefaultMQPushConsumer extends ClientConfig implements MQPushConsume private boolean unitMode = false; /** + * 最大消费重试次数。如果消息消费次数超过maxReconsume Times还未成功,则将该消息转移到一个失败队列,等待被删除 + * * Max re-consume times. -1 means 16 times. *

* @@ -245,11 +280,13 @@ public class DefaultMQPushConsumer extends ClientConfig implements MQPushConsume private int maxReconsumeTimes = -1; /** + * 延迟将该队列的消息提交到消费者线程的等待时间,默认延迟1s。 * Suspending pulling time for cases requiring slow pulling like flow-control scenario. */ private long suspendCurrentQueueTimeMillis = 1000; /** + * 消息消费超时时间,默认为15,单位为分钟 * Maximum amount of time in minutes a message may block the consuming thread. */ private long consumeTimeout = 15; diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/MQConsumer.java b/client/src/main/java/org/apache/rocketmq/client/consumer/MQConsumer.java index f4a8eda23a4..1e18ac264b7 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/MQConsumer.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/MQConsumer.java @@ -28,8 +28,16 @@ * Message queue consumer interface */ public interface MQConsumer extends MQAdmin { + /** * If consuming failure,message will be send back to the brokers,and delay consuming some time + * 如果消费失败,则将消息发送回broker,并延迟消费一段时间 + * @param msg + * @param delayLevel 消息延迟级别 + * @throws RemotingException + * @throws MQBrokerException + * @throws InterruptedException + * @throws MQClientException */ @Deprecated void sendMessageBack(final MessageExt msg, final int delayLevel) throws RemotingException, @@ -37,12 +45,15 @@ void sendMessageBack(final MessageExt msg, final int delayLevel) throws Remoting /** * If consuming failure,message will be send back to the broker,and delay consuming some time + * + * 如果消费失败,则将消息发送回broker,并延迟消费一段时间 */ void sendMessageBack(final MessageExt msg, final int delayLevel, final String brokerName) throws RemotingException, MQBrokerException, InterruptedException, MQClientException; /** * Fetch message queues from consumer cache according to the topic + * 获取消费者对topic分配了哪些消息队列 * * @param topic message topic * @return queue set diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/MQPushConsumer.java b/client/src/main/java/org/apache/rocketmq/client/consumer/MQPushConsumer.java index bc6d328c430..ca39a985e24 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/MQPushConsumer.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/MQPushConsumer.java @@ -22,6 +22,7 @@ import org.apache.rocketmq.client.exception.MQClientException; /** + * 推模式消费者 * Push consumer */ public interface MQPushConsumer extends MQConsumer { @@ -37,6 +38,9 @@ public interface MQPushConsumer extends MQConsumer { /** * Register the message listener + * 注册并发消息事件监听器 + * + * @param messageListener */ @Deprecated void registerMessageListener(MessageListener messageListener); @@ -46,6 +50,7 @@ public interface MQPushConsumer extends MQConsumer { void registerMessageListener(final MessageListenerOrderly messageListener); /** + * 基于主题订阅消息 * Subscribe some topic * * @param subExpression subscription expression.it only support or operation such as "tag1 || tag2 || tag3"
if diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/PullResult.java b/client/src/main/java/org/apache/rocketmq/client/consumer/PullResult.java index 30d995270c9..0d77d65529c 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/PullResult.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/PullResult.java @@ -21,8 +21,17 @@ public class PullResult { private final PullStatus pullStatus; + /** + * 下次拉取的偏移量 + */ private final long nextBeginOffset; + /** + * 消息队列的最小偏移量 + */ private final long minOffset; + /** + * 消息队列的最大偏移量 + */ private final long maxOffset; private List msgFoundList; diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/FindBrokerResult.java b/client/src/main/java/org/apache/rocketmq/client/impl/FindBrokerResult.java index 4367a4c1dbe..0521ac32ef8 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/FindBrokerResult.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/FindBrokerResult.java @@ -17,8 +17,18 @@ package org.apache.rocketmq.client.impl; public class FindBrokerResult { + + /** + * broker地址 + */ private final String brokerAddr; + /** + * 是否是从节点 + */ private final boolean slave; + /** + * broker版本 + */ private final int brokerVersion; public FindBrokerResult(String brokerAddr, boolean slave) { diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java index 807e9c6d6fc..5c341cfecb7 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java @@ -92,6 +92,9 @@ public class DefaultMQPushConsumerImpl implements MQConsumerInner { * Delay some time when suspend pull service */ private static final long PULL_TIME_DELAY_MILLS_WHEN_SUSPEND = 1000; + /** + * 长轮询的超时时间 + */ private static final long BROKER_SUSPEND_MAX_TIME_MILLIS = 1000 * 15; private static final long CONSUMER_TIMEOUT_MILLIS_WHEN_SUSPEND = 1000 * 30; private final InternalLogger log = ClientLogger.getLog(); @@ -105,6 +108,9 @@ public class DefaultMQPushConsumerImpl implements MQConsumerInner { private MQClientInstance mQClientFactory; private PullAPIWrapper pullAPIWrapper; private volatile boolean pause = false; + /** + * 是否是顺序消费 + */ private boolean consumeOrderly = false; private MessageListener messageListenerInner; private OffsetStore offsetStore; @@ -236,7 +242,10 @@ public void pullMessage(final PullRequest pullRequest) { long cachedMessageCount = processQueue.getMsgCount().get(); long cachedMessageSizeInMiB = processQueue.getMsgSize().get() / (1024 * 1024); + // 已缓存消息总数维度的流量控制 if (cachedMessageCount > this.defaultMQPushConsumer.getPullThresholdForQueue()) { + // 如果ProcessQueue当前处理的消息条数超过了pullThresholdForQueue=1000,将触发流控,放弃本次拉取任务,并 + // 且该队列的下一次拉取任务将在50ms后才加入拉取任务队列。 this.executePullRequestLater(pullRequest, PULL_TIME_DELAY_MILLS_WHEN_FLOW_CONTROL); if ((queueFlowControlTimes++ % 1000) == 0) { log.warn( @@ -246,7 +255,9 @@ public void pullMessage(final PullRequest pullRequest) { return; } + // 缓存消息大小维度的流量控制 if (cachedMessageSizeInMiB > this.defaultMQPushConsumer.getPullThresholdSizeForQueue()) { + // 缓存消息的大小不能超过pullThresholdSizeForQueue,否则触发流控 this.executePullRequestLater(pullRequest, PULL_TIME_DELAY_MILLS_WHEN_FLOW_CONTROL); if ((queueFlowControlTimes++ % 1000) == 0) { log.warn( @@ -289,8 +300,10 @@ public void pullMessage(final PullRequest pullRequest) { } } + // 获取主题的订阅信息 final SubscriptionData subscriptionData = this.rebalanceImpl.getSubscriptionInner().get(pullRequest.getMessageQueue().getTopic()); if (null == subscriptionData) { + // 拉取该主题的订阅信息,如果为空则结束本次消息拉取,关于该队列的下一次拉取任务将延迟3s执行 this.executePullRequestLater(pullRequest, pullTimeDelayMillsWhenException); log.warn("find the consumer's subscription failed, {}", pullRequest); return; @@ -307,6 +320,7 @@ public void onSuccess(PullResult pullResult) { switch (pullResult.getPullStatus()) { case FOUND: + // 获取到了消息 long prevRequestOffset = pullRequest.getNextOffset(); pullRequest.setNextOffset(pullResult.getNextBeginOffset()); long pullRT = System.currentTimeMillis() - beginTimestamp; @@ -315,6 +329,13 @@ public void onSuccess(PullResult pullResult) { long firstMsgOffset = Long.MAX_VALUE; if (pullResult.getMsgFoundList() == null || pullResult.getMsgFoundList().isEmpty()) { + // 如果msgFoundList为空,则立即将PullReqeuest放入PullMessageService的pullRequestQueue, + // 以便PullMessageSerivce能及时唤醒并再次执行消息拉取 + + // 为什么PullResult.msgFoundList + //还会为空呢?因为RocketMQ根据TAG进行消息过滤时,在服务端只是验 + //证了TAG的哈希码,所以客户端再次对消息进行过滤时,可能会出现 + //msgFoundList为空的情况 DefaultMQPushConsumerImpl.this.executePullRequestImmediately(pullRequest); } else { firstMsgOffset = pullResult.getMsgFoundList().get(0).getQueueOffset(); @@ -322,7 +343,10 @@ public void onSuccess(PullResult pullResult) { DefaultMQPushConsumerImpl.this.getConsumerStatsManager().incPullTPS(pullRequest.getConsumerGroup(), pullRequest.getMessageQueue().getTopic(), pullResult.getMsgFoundList().size()); + // 将消息存入processQueue boolean dispatchToConsume = processQueue.putMessage(pullResult.getMsgFoundList()); + + // 然后将拉取到的消息提交到Consume MessageService中供消费者消费 DefaultMQPushConsumerImpl.this.consumeMessageService.submitConsumeRequest( pullResult.getMsgFoundList(), processQueue, @@ -402,9 +426,12 @@ public void onException(Throwable e) { } }; + // 是否更新已消费物理偏移量 boolean commitOffsetEnable = false; + // 已消费偏移量 long commitOffsetValue = 0L; if (MessageModel.CLUSTERING == this.defaultMQPushConsumer.getMessageModel()) { + // 如果是集群消费,更新已消费偏移量 commitOffsetValue = this.offsetStore.readOffset(pullRequest.getMessageQueue(), ReadOffsetType.READ_FROM_MEMORY); if (commitOffsetValue > 0) { commitOffsetEnable = true; @@ -424,19 +451,26 @@ public void onException(Throwable e) { int sysFlag = PullSysFlag.buildSysFlag( commitOffsetEnable, // commitOffset + // 是否开启长轮询 true, // suspend subExpression != null, // subscription classFilter // class filter ); try { + // 通过远程调用,从broker中拉取消息。拉取成功后,调用 pullCallback.onSuccess 方法 this.pullAPIWrapper.pullKernelImpl( + // 需要拉取的消息队列信息 pullRequest.getMessageQueue(), + // 消息过滤表达式 subExpression, subscriptionData.getExpressionType(), subscriptionData.getSubVersion(), + // 拉取的物理偏移量 pullRequest.getNextOffset(), + // 拉取的消息数量 this.defaultMQPushConsumer.getPullBatchSize(), sysFlag, + // 已消费偏移量 commitOffsetValue, BROKER_SUSPEND_MAX_TIME_MILLIS, CONSUMER_TIMEOUT_MILLIS_WHEN_SUSPEND, @@ -580,6 +614,7 @@ public synchronized void start() throws MQClientException { this.defaultMQPushConsumer.changeInstanceNameToPID(); } + // 创建MQClientInstance实例。同一个clientId只会创建一个MQClientInstance实例 this.mQClientFactory = MQClientManager.getInstance().getOrCreateMQClientInstance(this.defaultMQPushConsumer, this.rpcHook); this.rebalanceImpl.setConsumerGroup(this.defaultMQPushConsumer.getConsumerGroup()); @@ -592,9 +627,13 @@ public synchronized void start() throws MQClientException { this.defaultMQPushConsumer.getConsumerGroup(), isUnitMode()); this.pullAPIWrapper.registerFilterMessageHook(filterMessageHookList); + // 初始化消息进度 if (this.defaultMQPushConsumer.getOffsetStore() != null) { this.offsetStore = this.defaultMQPushConsumer.getOffsetStore(); } else { + // 初始化消息进度。如果消息消费采用集群模式,那么消 + // 息进度存储在Broker上,如果采用广播模式,那么消息消费进度存储 + // 在消费端 switch (this.defaultMQPushConsumer.getMessageModel()) { case BROADCASTING: this.offsetStore = new LocalFileOffsetStore(this.mQClientFactory, this.defaultMQPushConsumer.getConsumerGroup()); @@ -609,6 +648,7 @@ public synchronized void start() throws MQClientException { } this.offsetStore.load(); + // 如果是顺序消费,创建消费端消费线程服务。ConsumeMessageService主要负责消息消费,在内部维护一个线程池 if (this.getMessageListenerInner() instanceof MessageListenerOrderly) { this.consumeOrderly = true; this.consumeMessageService = @@ -621,6 +661,7 @@ public synchronized void start() throws MQClientException { this.consumeMessageService.start(); + // 向MQClientInstance注册消费者 boolean registerOK = mQClientFactory.registerConsumer(this.defaultMQPushConsumer.getConsumerGroup(), this); if (!registerOK) { this.serviceState = ServiceState.CREATE_JUST; @@ -629,7 +670,7 @@ public synchronized void start() throws MQClientException { + "] has been created before, specify another name please." + FAQUrl.suggestTodo(FAQUrl.GROUP_NAME_DUPLICATE_URL), null); } - + // 启动MQClientInstance,JVM中的所有消费者、生产者持有同一个MQClientInstance,MQClientInstance只会启动一次 mQClientFactory.start(); log.info("the consumer [{}] start OK.", this.defaultMQPushConsumer.getConsumerGroup()); this.serviceState = ServiceState.RUNNING; @@ -842,6 +883,7 @@ private void copySubscription() throws MQClientException { case BROADCASTING: break; case CLUSTERING: + // RocketMQ消息重试是以消费组为单位,而不是主题,消息重试主题名为%RETRY%+消费组名 final String retryTopic = MixAll.getRetryTopic(this.defaultMQPushConsumer.getConsumerGroup()); SubscriptionData subscriptionData = FilterAPI.buildSubscriptionData(this.defaultMQPushConsumer.getConsumerGroup(), retryTopic, SubscriptionData.SUB_ALL); diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ProcessQueue.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ProcessQueue.java index 092da9aa33e..3a9d5f6abdc 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ProcessQueue.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ProcessQueue.java @@ -36,6 +36,11 @@ import org.apache.rocketmq.common.protocol.body.ProcessQueueInfo; /** + * ProcessQueue是MessageQueue在消费端的重现、快照。 + * PullMessageService从消息服务器默认每次拉取32条消息,按消息队 + * 列偏移量的顺序存放在ProcessQueue中,PullMessageService将消息 + * 提交到消费者消费线程池,消息成功消费后,再从ProcessQueue中移 + * 除。 * Queue consumption snapshot */ public class ProcessQueue { @@ -44,34 +49,66 @@ public class ProcessQueue { public final static long REBALANCE_LOCK_INTERVAL = Long.parseLong(System.getProperty("rocketmq.client.rebalance.lockInterval", "20000")); private final static long PULL_MAX_IDLE_TIME = Long.parseLong(System.getProperty("rocketmq.client.pull.pullMaxIdleTime", "120000")); private final InternalLogger log = ClientLogger.getLog(); + /** + * 读写锁,控制多线程并发修改msgTreeMap + */ private final ReadWriteLock lockTreeMap = new ReentrantReadWriteLock(); + /** + * 消息存储容器,键为消息在ConsumeQueue中的偏移量 + */ private final TreeMap msgTreeMap = new TreeMap(); + /** + * ProcessQueue中总消息数 + */ private final AtomicLong msgCount = new AtomicLong(); private final AtomicLong msgSize = new AtomicLong(); private final Lock lockConsume = new ReentrantLock(); /** * A subset of msgTreeMap, will only be used when orderly consume + * + * 用于存储消息消费队列中正在被顺序消费的消息。其键值对的关系为 Offset -> Message Queue,也就是按照消息在 Broker 中存储的物理偏移量进行排序。 */ private final TreeMap consumingMsgOrderlyTreeMap = new TreeMap(); private final AtomicLong tryUnlockTimes = new AtomicLong(0); + /** + * 当前ProcessQueue中包含的最大队列偏移量 + */ private volatile long queueOffsetMax = 0L; + /** + * 当前ProccesQueue是否被丢弃 + */ private volatile boolean dropped = false; + /** + * 上一次开始拉取消息的时间戳 + */ private volatile long lastPullTimestamp = System.currentTimeMillis(); + /** + * 上一次消费消息的时间戳 + */ private volatile long lastConsumeTimestamp = System.currentTimeMillis(); private volatile boolean locked = false; private volatile long lastLockTimestamp = System.currentTimeMillis(); private volatile boolean consuming = false; private volatile long msgAccCnt = 0; + /** + * 判断锁是否过期,锁超时时间默认为30s,通过系统参数rocketmq.client.rebalance.lockMaxLiveTime进行设置 + * @return + */ public boolean isLockExpired() { return (System.currentTimeMillis() - this.lastLockTimestamp) > REBALANCE_LOCK_MAX_LIVE_TIME; } + /** + * 判断PullMessageService是否空闲,空闲时间默认120s,通过系统参数rocketmq.client.pull.pullMaxIdleTime进行设置 + * @return + */ public boolean isPullExpired() { return (System.currentTimeMillis() - this.lastPullTimestamp) > PULL_MAX_IDLE_TIME; } /** + * 移除消费超时的消息,默认超过15min未消费的消息将延迟3个延迟级别再消费 * @param pushConsumer */ public void cleanExpiredMsg(DefaultMQPushConsumer pushConsumer) { @@ -124,6 +161,11 @@ public void cleanExpiredMsg(DefaultMQPushConsumer pushConsumer) { } } + /** + * 添加消息,PullMessageService拉取消息后,调用该方法将消息添加到ProcessQueue。 + * @param msgs + * @return + */ public boolean putMessage(final List msgs) { boolean dispatchToConsume = false; try { @@ -165,6 +207,13 @@ public boolean putMessage(final List msgs) { return dispatchToConsume; } + /** + * 获取当前消息的最大间隔。 + * getMaxSpan()并不能说明ProceQueue包含的消息个数,但是能说明当 + * 前处理队列中第一条消息与最后一条消息的偏移量已经超过的消息个 + * 数 + * @return + */ public long getMaxSpan() { try { this.lockTreeMap.readLock().lockInterruptibly(); @@ -257,6 +306,10 @@ public void rollback() { } } + /** + * 清空 consumingMsgOrderlyTreeMap中的消息,代表成功处理这批消息 + * @return + */ public long commit() { try { this.lockTreeMap.writeLock().lockInterruptibly(); @@ -266,6 +319,7 @@ public long commit() { for (MessageExt msg : this.consumingMsgOrderlyTreeMap.values()) { msgSize.addAndGet(0 - msg.getBody().length); } + // 清空 consumingMsgOrderlyTreeMap 代表这些消息被成功消费 this.consumingMsgOrderlyTreeMap.clear(); if (offset != null) { return offset + 1; @@ -280,6 +334,10 @@ public long commit() { return -1; } + /** + * 重新消费这批消息 + * @param msgs + */ public void makeMessageToCosumeAgain(List msgs) { try { this.lockTreeMap.writeLock().lockInterruptibly(); @@ -296,6 +354,11 @@ public void makeMessageToCosumeAgain(List msgs) { } } + /** + * 从ProcessQueue中取出batchSize条消息。 + * @param batchSize + * @return + */ public List takeMessags(final int batchSize) { List result = new ArrayList(batchSize); final long now = System.currentTimeMillis(); @@ -308,6 +371,7 @@ public List takeMessags(final int batchSize) { Map.Entry entry = this.msgTreeMap.pollFirstEntry(); if (entry != null) { result.add(entry.getValue()); + // 将消息加入 consumingMsgOrderlyTreeMap,代表这些消息正在被消费 consumingMsgOrderlyTreeMap.put(entry.getKey(), entry.getValue()); } else { break; diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java index 1917d27cf15..be1afd00885 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java @@ -139,6 +139,26 @@ public void executeHook(final FilterMessageContext context) { } } + /** + * 通过远程调用,从 broker 拉取消息 + * @param mq 从哪个队列拉取消息 + * @param subExpression 消息过滤表达式。 + * @param expressionType 消息表达式类型,分为TAG、SQL92。 + * @param subVersion + * @param offset 拉取的消息的起始偏移量 + * @param maxNums 拉取的消息数量 + * @param sysFlag 表示位,参考: org.apache.rocketmq.common.sysflag.PullSysFlag + * @param commitOffset 已消费偏移量 + * @param brokerSuspendMaxTimeMillis 消息拉取过程中允许Broker挂起的时间,默认15s。 + * @param timeoutMillis 消息拉取超时时间 + * @param communicationMode 消息拉取模式,默认为异步拉取。 + * @param pullCallback 拉取回调 + * @return + * @throws MQClientException + * @throws RemotingException + * @throws MQBrokerException + * @throws InterruptedException + */ public PullResult pullKernelImpl( final MessageQueue mq, final String subExpression, @@ -154,6 +174,10 @@ public PullResult pullKernelImpl( final PullCallback pullCallback ) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { FindBrokerResult findBrokerResult = + // 根据brokerName、BrokerId从MQClientInstance中获取 + //Broker地址,在整个RocketMQ Broker的部署结构中,相同名称的 + //Broker构成主从结构,其BrokerId会不一样,在每次拉取消息后,会 + //给出一个建议,下次是从主节点还是从节点拉取 this.mQClientFactory.findBrokerAddressInSubscribe(mq.getBrokerName(), this.recalculatePullFromWhichNode(mq), false); if (null == findBrokerResult) { @@ -179,12 +203,19 @@ public PullResult pullKernelImpl( } PullMessageRequestHeader requestHeader = new PullMessageRequestHeader(); + // 消费组名称 requestHeader.setConsumerGroup(this.consumerGroup); + // topic名称 requestHeader.setTopic(mq.getTopic()); + // 队列ID requestHeader.setQueueId(mq.getQueueId()); + // 队列的偏移量 requestHeader.setQueueOffset(offset); + // 拉取的消息数量 requestHeader.setMaxMsgNums(maxNums); + // 消息拉取的标识位,参考:org.apache.rocketmq.common.sysflag.PullSysFlag requestHeader.setSysFlag(sysFlagInner); + // 已经消费完成的消息偏移量 requestHeader.setCommitOffset(commitOffset); requestHeader.setSuspendTimeoutMillis(brokerSuspendMaxTimeMillis); requestHeader.setSubscription(subExpression); diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullMessageService.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullMessageService.java index bd46a58859a..5c6e00c68e5 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullMessageService.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullMessageService.java @@ -29,6 +29,9 @@ public class PullMessageService extends ServiceThread { private final InternalLogger log = ClientLogger.getLog(); + /** + * 消息拉取任务阻塞队列 + */ private final LinkedBlockingQueue pullRequestQueue = new LinkedBlockingQueue(); private final MQClientInstance mQClientFactory; private final ScheduledExecutorService scheduledExecutorService = Executors @@ -76,6 +79,15 @@ public ScheduledExecutorService getScheduledExecutorService() { return scheduledExecutorService; } + /** + * 根据消费组名从MQClientInstance中获取消费者的内部实现类 + * MQConsumerInner,令人意外的是,这里将consumer强制转换为 + * DefaultMQPushConsumerImpl,也就是PullMessageService,该线程只 + * 为推模式服务,那拉模式如何拉取消息呢?其实细想也不难理解,对 + * 于拉模式,RocketMQ只需要提供拉取消息API,再由应用程序调用API + * + * @param pullRequest + */ private void pullMessage(final PullRequest pullRequest) { final MQConsumerInner consumer = this.mQClientFactory.selectConsumer(pullRequest.getConsumerGroup()); if (consumer != null) { @@ -90,8 +102,13 @@ private void pullMessage(final PullRequest pullRequest) { public void run() { log.info(this.getServiceName() + " service started"); + // while (!this.isStopped()) 是一种通用的设计技巧,Stopped + // 声明为volatile,每执行一次业务逻辑,检测一下其运行状态,可以 + // 通过其他线程将Stopped设置为true,从而停止该线程 while (!this.isStopped()) { try { + // 从pullRequestQueue中获取一个PullRequest消息拉取任务, + // 如果pullRequestQueue为空,则线程将阻塞,直到有拉取任务被放入 PullRequest pullRequest = this.pullRequestQueue.take(); this.pullMessage(pullRequest); } catch (InterruptedException ignored) { diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullRequest.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullRequest.java index 10aded07625..438abba762d 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullRequest.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullRequest.java @@ -19,10 +19,26 @@ import org.apache.rocketmq.common.message.MessageQueue; public class PullRequest { + + /** + * 消费者组 + */ private String consumerGroup; + /** + * 待拉取消费队列 + */ private MessageQueue messageQueue; + /** + * 消息处理队列,从Broker中拉取到的消息会先存入ProccessQueue,然后再提交到消费者消费线程池进行消费 + */ private ProcessQueue processQueue; + /** + * 待拉取的MessageQueue偏移量 + */ private long nextOffset; + /** + * 是否被锁定 + */ private boolean lockedFirst = false; public boolean isLockedFirst() { diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java index 0089df09382..5625b6c68f4 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java @@ -115,6 +115,9 @@ public Thread newThread(Runnable r) { } }); private final ClientRemotingProcessor clientRemotingProcessor; + /** + * 消息拉取线程 + */ private final PullMessageService pullMessageService; private final RebalanceService rebalanceService; private final DefaultMQProducer defaultMQProducer; diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java index 1bdb535b7e2..6404ae2afa1 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java @@ -564,9 +564,11 @@ private SendResult sendDefaultImpl( MessageQueue mq = null; Exception exception = null; SendResult sendResult = null; + // 总计发送次数(1+重试次数) int timesTotal = communicationMode == CommunicationMode.SYNC ? 1 + this.defaultMQProducer.getRetryTimesWhenSendFailed() : 1; int times = 0; String[] brokersSent = new String[timesTotal]; + // 循环指定发送指定次数,直到成功发送后退出循环 for (; times < timesTotal; times++) { String lastBrokerName = null == mq ? null : mq.getBrokerName(); // 选择一个消息队列 diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/producer/TopicPublishInfo.java b/client/src/main/java/org/apache/rocketmq/client/impl/producer/TopicPublishInfo.java index 94f0d5ebc51..41ddd738e11 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/producer/TopicPublishInfo.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/producer/TopicPublishInfo.java @@ -79,6 +79,11 @@ public void setHaveTopicRouterInfo(boolean haveTopicRouterInfo) { this.haveTopicRouterInfo = haveTopicRouterInfo; } + /** + * 选择一个队列,如果上一次发送失败,这一次会尽量规避调上一次失败的broker上的队列 + * @param lastBrokerName 上一次失败的broker + * @return + */ public MessageQueue selectOneMessageQueue(final String lastBrokerName) { if (lastBrokerName == null) { // 在消息发送过程中,可能会多次执行选择消息队列这个方法, diff --git a/client/src/main/java/org/apache/rocketmq/client/latency/MQFaultStrategy.java b/client/src/main/java/org/apache/rocketmq/client/latency/MQFaultStrategy.java index f397118b03a..9420881da49 100644 --- a/client/src/main/java/org/apache/rocketmq/client/latency/MQFaultStrategy.java +++ b/client/src/main/java/org/apache/rocketmq/client/latency/MQFaultStrategy.java @@ -31,7 +31,7 @@ public class MQFaultStrategy { * 开启与不开启sendLatencyFaultEnable机制在消息发送时都能规避故 * 障的Broker,那么这两种机制有何区别呢? * - * 开启所谓的故障延迟机制,即设置sendLatencyFaultEnable为ture, + * 开启所谓的故障延迟机制,即设置sendLatencyFaultEnable为true, * 其实是一种较为悲观的做法。当消息发送者遇到一次消息发送失败 * 后,就会悲观地认为Broker不可用,在接下来的一段时间内就不再向 * 其发送消息,直接避开该Broker。而不开启延迟规避机制,就只会在 diff --git a/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java b/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java index a7568f0a207..2d5794df014 100644 --- a/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java +++ b/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java @@ -93,6 +93,9 @@ public class BrokerConfig { private int filterServerNums = 0; + /** + * 消息拉取是否开启长轮询 + */ private boolean longPollingEnable = true; private long shortPollingTimeMills = 1000; diff --git a/common/src/main/java/org/apache/rocketmq/common/consumer/ConsumeFromWhere.java b/common/src/main/java/org/apache/rocketmq/common/consumer/ConsumeFromWhere.java index a33f46568ba..1bd542b7284 100644 --- a/common/src/main/java/org/apache/rocketmq/common/consumer/ConsumeFromWhere.java +++ b/common/src/main/java/org/apache/rocketmq/common/consumer/ConsumeFromWhere.java @@ -17,6 +17,9 @@ package org.apache.rocketmq.common.consumer; public enum ConsumeFromWhere { + /** + * 此处分为两种情况,如果磁盘消息未过期且未被删除,则从最小偏移量开始消费。如果磁盘已过期并被删除,则从最大偏移量开始消费。 + */ CONSUME_FROM_LAST_OFFSET, @Deprecated @@ -25,6 +28,12 @@ public enum ConsumeFromWhere { CONSUME_FROM_MIN_OFFSET, @Deprecated CONSUME_FROM_MAX_OFFSET, + /** + * 从队列当前最小偏移量开始消费 + */ CONSUME_FROM_FIRST_OFFSET, + /** + * 从消费者指定时间戳开始消费 + */ CONSUME_FROM_TIMESTAMP, } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java index 106e89e511c..70f19c4df38 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java @@ -26,26 +26,57 @@ import org.apache.rocketmq.remoting.exception.RemotingCommandException; public class PullMessageRequestHeader implements CommandCustomHeader { + + /** + * 消费组名称 + */ @CFNotNull private String consumerGroup; + /** + * topic名称 + */ @CFNotNull private String topic; + /** + * 队列ID + */ @CFNotNull private Integer queueId; + /** + * 队列的偏移量 + */ @CFNotNull private Long queueOffset; + /** + * 拉取的消息数量 + */ @CFNotNull private Integer maxMsgNums; + /** + * 消息拉取的标识位,参考:org.apache.rocketmq.common.sysflag.PullSysFlag + */ @CFNotNull private Integer sysFlag; + /** + * 已经消费完成的消息偏移量 + */ @CFNotNull private Long commitOffset; + /** + * broker暂停最大时间毫秒 + */ @CFNotNull private Long suspendTimeoutMillis; + /** + * 消息过滤表达式 + */ @CFNullable private String subscription; @CFNotNull private Long subVersion; + /** + * 参考:org.apache.rocketmq.common.filter.ExpressionType + */ private String expressionType; @Override diff --git a/common/src/main/java/org/apache/rocketmq/common/sysflag/PullSysFlag.java b/common/src/main/java/org/apache/rocketmq/common/sysflag/PullSysFlag.java index d476a35b749..b0d8d1c57a8 100644 --- a/common/src/main/java/org/apache/rocketmq/common/sysflag/PullSysFlag.java +++ b/common/src/main/java/org/apache/rocketmq/common/sysflag/PullSysFlag.java @@ -17,9 +17,22 @@ package org.apache.rocketmq.common.sysflag; public class PullSysFlag { + + /** + * 是否更新已消费偏移量 + */ private final static int FLAG_COMMIT_OFFSET = 0x1; + /** + * 表示消息拉取时是否支持挂起 + */ private final static int FLAG_SUSPEND = 0x1 << 1; + /** + * 消息过滤机制为表达式,则设置该标记位 + */ private final static int FLAG_SUBSCRIPTION = 0x1 << 2; + /** + * 消息过滤机制为类模式,则设置该标记 + */ private final static int FLAG_CLASS_FILTER = 0x1 << 3; public static int buildSysFlag(final boolean commitOffset, final boolean suspend, diff --git a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java index 3f61af65c3a..6a3b262f2ff 100644 --- a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java +++ b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java @@ -550,6 +550,16 @@ public CommitLog getCommitLog() { return commitLog; } + /** + * 获取消息 + * @param group 消费组名称 + * @param topic topic名称. + * @param queueId 队列ID. + * @param offset 待拉取偏移量. + * @param maxMsgNums 最大拉取消息条数. + * @param messageFilter 消息过滤器. + * @return + */ public GetMessageResult getMessage(final String group, final String topic, final int queueId, final long offset, final int maxMsgNums, final MessageFilter messageFilter) { @@ -566,12 +576,16 @@ public GetMessageResult getMessage(final String group, final String topic, final long beginTime = this.getSystemClock().now(); GetMessageStatus status = GetMessageStatus.NO_MESSAGE_IN_QUEUE; + // 待查找队列的偏移量 long nextBeginOffset = offset; + // 当前消息队列的最小偏移量 long minOffset = 0; + // 当前消息队列的最大偏移量 long maxOffset = 0; GetMessageResult getResult = new GetMessageResult(); + // 当前CommitLog文件的最大偏移量 final long maxOffsetPy = this.commitLog.getMaxOffset(); ConsumeQueue consumeQueue = findConsumeQueue(topic, queueId); @@ -580,15 +594,32 @@ public GetMessageResult getMessage(final String group, final String topic, final maxOffset = consumeQueue.getMaxOffsetInQueue(); if (maxOffset == 0) { + //表示当前消费队列中没有消息,拉取结果为 + //NO_MESSAGE_IN_QUEUE。如果当前Broker为主节点,下次拉取偏移量为 + //0。如果当前Broker为从节点并且offsetCheckInSlave为true,设置下 + //次拉取偏移量为0。其他情况下次拉取时使用原偏移量 status = GetMessageStatus.NO_MESSAGE_IN_QUEUE; nextBeginOffset = nextOffsetCorrection(offset, 0); } else if (offset < minOffset) { + //表示待拉取消息偏移量小于队列的起始偏 + //移量,拉取结果为OFFSET_TOO_SMALL。如果当前Broker为主节点,下 + //次拉取偏移量为队列的最小偏移量。如果当前Broker为从节点并且 + //offsetCheckInSlave为true,下次拉取偏移量为队列的最小偏移量。 + //其他情况下次拉取时使用原偏移量。 status = GetMessageStatus.OFFSET_TOO_SMALL; nextBeginOffset = nextOffsetCorrection(offset, minOffset); } else if (offset == maxOffset) { + // 如果待拉取偏移量等于队列最大偏移 + //量,拉取结果为OFFSET_OVERFLOW_ONE,则下次拉取偏移量依然为 + //offset。 status = GetMessageStatus.OFFSET_OVERFLOW_ONE; nextBeginOffset = nextOffsetCorrection(offset, offset); } else if (offset > maxOffset) { + // 表示偏移量越界,拉取结果为 + //OFFSET_OVERFLOW_BADLY。此时需要考虑当前队列的偏移量是否为0, + //如果当前队列的最小偏移量为0,则使用最小偏移量纠正下次拉取偏移 + //量。如果当前队列的最小偏移量不为0,则使用该队列的最大偏移量来 + //纠正下次拉取偏移量 status = GetMessageStatus.OFFSET_OVERFLOW_BADLY; if (0 == minOffset) { nextBeginOffset = nextOffsetCorrection(offset, minOffset); @@ -2023,8 +2054,10 @@ private void doReput() { // 执行CommitLog转发 DefaultMessageStore.this.doDispatch(dispatchRequest); + // 如果开启了长轮询 if (BrokerRole.SLAVE != DefaultMessageStore.this.getMessageStoreConfig().getBrokerRole() && DefaultMessageStore.this.brokerConfig.isLongPollingEnable()) { + // 有新消息到达,唤醒长轮询等待的线程,返回消息 DefaultMessageStore.this.messageArrivingListener.arriving(dispatchRequest.getTopic(), dispatchRequest.getQueueId(), dispatchRequest.getConsumeQueueOffset() + 1, dispatchRequest.getTagsCode(), dispatchRequest.getStoreTimestamp(), From 0a4d238d24970df62549addcb0b1e31db436ca19 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sat, 28 Oct 2023 12:01:44 +0800 Subject: [PATCH 06/18] =?UTF-8?q?'RocketMQ=E6=B6=88=E6=81=AF=E6=8B=89?= =?UTF-8?q?=E5=8F=96=E5=92=8C=E6=B6=88=E8=B4=B9=E6=B5=81=E7=A8=8B=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=B3=A8=E9=87=8A'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 75 +++--------------- .../processor/SendMessageProcessor.java | 22 ++++- .../AllocateMessageQueueStrategy.java | 1 + .../AllocateMessageQueueAveragely.java | 7 ++ ...AllocateMessageQueueAveragelyByCircle.java | 9 +++ .../AllocateMessageQueueByConfig.java | 3 + .../AllocateMessageQueueByMachineRoom.java | 1 + .../AllocateMessageQueueConsistentHash.java | 1 + .../rocketmq/client/impl/MQClientAPIImpl.java | 19 +++++ .../ConsumeMessageConcurrentlyService.java | 65 ++++++++++++++- .../ConsumeMessageOrderlyService.java | 3 + .../impl/consumer/ConsumeMessageService.java | 23 ++++++ .../consumer/DefaultMQPushConsumerImpl.java | 1 + .../client/impl/consumer/ProcessQueue.java | 5 ++ .../client/impl/consumer/RebalanceImpl.java | 16 +++- .../impl/consumer/RebalancePushImpl.java | 7 ++ .../impl/consumer/RebalanceService.java | 7 ++ .../client/impl/factory/MQClientInstance.java | 2 + .../common/consumer/ConsumeFromWhere.java | 11 ++- .../ConsumerSendMsgBackRequestHeader.java | 13 +++ .../subscription/SubscriptionGroupConfig.java | 40 ++++++++-- ...0\350\264\271\346\265\201\347\250\213.png" | Bin 0 -> 202248 bytes 22 files changed, 252 insertions(+), 79 deletions(-) create mode 100644 "images/RocketMQ\346\266\210\346\201\257\346\213\211\345\217\226\345\222\214\346\266\210\350\264\271\346\265\201\347\250\213.png" diff --git a/README.md b/README.md index 33b42800cf3..d52b1ce9355 100644 --- a/README.md +++ b/README.md @@ -1,73 +1,16 @@ -## Apache RocketMQ [![Build Status](https://travis-ci.org/apache/rocketmq.svg?branch=master)](https://travis-ci.org/apache/rocketmq) [![Coverage Status](https://coveralls.io/repos/github/apache/rocketmq/badge.svg?branch=master)](https://coveralls.io/github/apache/rocketmq?branch=master) -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.rocketmq/rocketmq-all/badge.svg)](http://search.maven.org/#search%7Cga%7C1%7Corg.apache.rocketmq) -[![GitHub release](https://img.shields.io/badge/release-download-orange.svg)](https://rocketmq.apache.org/dowloading/releases) -[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) +# RocketMQ 源码分析 -**[Apache RocketMQ](https://rocketmq.apache.org) is a distributed messaging and streaming platform with low latency, high performance and reliability, trillion-level capacity and flexible scalability.** +## 消息存储 -It offers a variety of features: -* Pub/Sub messaging model -* Financial grade transactional message -* A variety of cross language clients, such as Java, C/C++, Python, Go -* Pluggable transport protocols, such as TCP, SSL, AIO -* Inbuilt message tracing capability, also support opentracing -* Versatile big-data and streaming ecosytem integration -* Message retroactivity by time or offset -* Reliable FIFO and strict ordered messaging in the same queue -* Efficient pull&push consumption model -* Million-level message accumulation capacity in a single queue -* Multiple messaging protocols like JMS and OpenMessaging -* Flexible distributed scale-out deployment architecture -* Lightning-fast batch message exchange system -* Various message filter mechanics such as SQL and Tag -* Docker images for isolated testing and cloud isolated clusters -* Feature-rich administrative dashboard for configuration, metrics and monitoring -* Authentication and authorisation +## 消息拉取与消费 ----------- +- 消息拉取代码入口:org.apache.rocketmq.client.impl.consumer.PullMessageService.run + - RocketMQ 消费者API层面分为推模式和拉模式两种消费模式,但是底层都是使用的拉模式实现的消息拉取,如果使用的推模式API,RocketMQ Client会使用长轮询的方式拉取消息,将录取到的消息放入 `ProcessQueue` 本地队列中供消费者消费。 -## Learn it & Contact us -* Mailing Lists: -* Home: -* Docs: -* Issues: -* Rips: -* Ask: -* Slack: - +- 消息队列负载均衡代码入口:org.apache.rocketmq.client.impl.consumer.RebalanceService.run + - 主要为了实现消息队列负载与重新分布机制。RebalanceService会在第一次启动时计算当前节点消费的topic的队列ID,然后创建PullRequest拉取消息 ----------- +- 消息消费代码入口:org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService.ConsumeRequest.run -## Apache RocketMQ Community -* [RocketMQ Community Projects](https://github.com/apache/rocketmq-externals) ----------- - -## Contributing -We always welcome new contributions, whether for trivial cleanups, [big new features](https://github.com/apache/rocketmq/wiki/RocketMQ-Improvement-Proposal) or other material rewards, more details see [here](http://rocketmq.apache.org/docs/how-to-contribute/). - ----------- -## License -[Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) Copyright (C) Apache Software Foundation - - ----------- -## Export Control Notice -This distribution includes cryptographic software. The country in which you currently reside may have -restrictions on the import, possession, use, and/or re-export to another country, of encryption software. -BEFORE using any encryption software, please check your country's laws, regulations and policies concerning -the import, possession, or use, and re-export of encryption software, to see if this is permitted. See - for more information. - -The U.S. Government Department of Commerce, Bureau of Industry and Security (BIS), has classified this -software as Export Commodity Control Number (ECCN) 5D002.C.1, which includes information security software -using or performing cryptographic functions with asymmetric algorithms. The form and manner of this Apache -Software Foundation distribution makes it eligible for export under the License Exception ENC Technology -Software Unrestricted (TSU) exception (see the BIS Export Administration Regulations, Section 740.13) for -both object code and source code. - -The following provides more details on the included cryptographic software: - -This software uses Apache Commons Crypto (https://commons.apache.org/proper/commons-crypto/) to -support authentication, and encryption and decryption of data sent across the network between -services. +![](./images/RocketMQ消息拉取和消费流程.png) \ No newline at end of file diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java index 2589a7547dc..624296a8207 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java @@ -68,6 +68,7 @@ public RemotingCommand processRequest(ChannelHandlerContext ctx, SendMessageContext mqtraceContext; switch (request.getCode()) { case RequestCode.CONSUMER_SEND_MSG_BACK: + // 客户端消费消息失败,将消息重新发回 broker retry topic,使得消费者能延迟一定时间后能重新消费该消息 return this.consumerSendMsgBack(ctx, request); default: SendMessageRequestHeader requestHeader = parseRequestHeader(request); @@ -96,6 +97,13 @@ public boolean rejectRequest() { this.brokerController.getMessageStore().isTransientStorePoolDeficient(); } + /** + * + * @param ctx + * @param request + * @return + * @throws RemotingCommandException + */ private RemotingCommand consumerSendMsgBack(final ChannelHandlerContext ctx, final RemotingCommand request) throws RemotingCommandException { final RemotingCommand response = RemotingCommand.createResponseCommand(null); @@ -116,6 +124,7 @@ private RemotingCommand consumerSendMsgBack(final ChannelHandlerContext ctx, fin this.executeConsumeMessageHookAfter(context); } + // 获取消费组的订阅配置信息 SubscriptionGroupConfig subscriptionGroupConfig = this.brokerController.getSubscriptionGroupManager().findSubscriptionGroupConfig(requestHeader.getGroup()); if (null == subscriptionGroupConfig) { @@ -137,6 +146,7 @@ private RemotingCommand consumerSendMsgBack(final ChannelHandlerContext ctx, fin return response; } + // 创建重试主题,重试主题名称为%RETRY%+消费组名称,从重试队列中随机选择一个队列,并构建TopicConfig主题配置信息 String newTopic = MixAll.getRetryTopic(requestHeader.getGroup()); int queueIdInt = Math.abs(this.random.nextInt() % 99999999) % subscriptionGroupConfig.getRetryQueueNums(); @@ -145,6 +155,7 @@ private RemotingCommand consumerSendMsgBack(final ChannelHandlerContext ctx, fin topicSysFlag = TopicSysFlag.buildSysFlag(false, true); } + // 如果没有重试主题则创建一个 TopicConfig topicConfig = this.brokerController.getTopicConfigManager().createTopicInSendMessageBackMethod( newTopic, subscriptionGroupConfig.getRetryQueueNums(), @@ -161,15 +172,16 @@ private RemotingCommand consumerSendMsgBack(final ChannelHandlerContext ctx, fin return response; } + // 根据消息物理偏移量从CommitLog中获取消息 MessageExt msgExt = this.brokerController.getMessageStore().lookMessageByOffset(requestHeader.getOffset()); if (null == msgExt) { response.setCode(ResponseCode.SYSTEM_ERROR); response.setRemark("look message by offset failed, " + requestHeader.getOffset()); return response; } - final String retryTopic = msgExt.getProperty(MessageConst.PROPERTY_RETRY_TOPIC); if (null == retryTopic) { + // 将消息的主题信息存入属性 MessageAccessor.putProperty(msgExt, MessageConst.PROPERTY_RETRY_TOPIC, msgExt.getTopic()); } msgExt.setWaitStoreMsgOK(false); @@ -183,6 +195,8 @@ private RemotingCommand consumerSendMsgBack(final ChannelHandlerContext ctx, fin if (msgExt.getReconsumeTimes() >= maxReconsumeTimes || delayLevel < 0) { + // 设置消息重试次数,如果消息重试次数已超过maxReconsumeTimes,再次改变newTopic主题为DLQ("%DLQ%"),该主 + // 题的权限为只写,说明消息一旦进入DLQ队列,RocketMQ将不负责再次调度消费了,需要人工干预 newTopic = MixAll.getDLQTopic(requestHeader.getGroup()); queueIdInt = Math.abs(this.random.nextInt() % 99999999) % DLQ_NUMS_PER_GROUP; @@ -203,7 +217,10 @@ private RemotingCommand consumerSendMsgBack(final ChannelHandlerContext ctx, fin msgExt.setDelayTimeLevel(delayLevel); } + // 根据原先的消息创建一个新的消息对象,重试消息会拥有一个唯一消息ID(msgId)并存入CommitLog文件。这里不会更新原 + // 先的消息,而是会将原先的主题、消息ID存入消息属性,主题名称为重试主题,其他属性与原消息保持一致。 MessageExtBrokerInner msgInner = new MessageExtBrokerInner(); + // 将重试的消息放入重试topic,或则死信topic msgInner.setTopic(newTopic); msgInner.setBody(msgExt.getBody()); msgInner.setFlag(msgExt.getFlag()); @@ -218,9 +235,12 @@ private RemotingCommand consumerSendMsgBack(final ChannelHandlerContext ctx, fin msgInner.setStoreHost(this.getStoreHost()); msgInner.setReconsumeTimes(msgExt.getReconsumeTimes() + 1); + // 原始的消息ID String originMsgId = MessageAccessor.getOriginMessageId(msgExt); + // 设置原始的消息ID MessageAccessor.setOriginMessageId(msgInner, UtilAll.isBlank(originMsgId) ? msgExt.getMsgId() : originMsgId); + // 将重试的消息写入重试topic,或则死信topic。根据 newTopic 变量决定写入哪个topic PutMessageResult putMessageResult = this.brokerController.getMessageStore().putMessage(msgInner); if (putMessageResult != null) { switch (putMessageResult.getPutMessageStatus()) { diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/AllocateMessageQueueStrategy.java b/client/src/main/java/org/apache/rocketmq/client/consumer/AllocateMessageQueueStrategy.java index c1f060406b5..8e0fb032dfa 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/AllocateMessageQueueStrategy.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/AllocateMessageQueueStrategy.java @@ -21,6 +21,7 @@ /** * Strategy Algorithm for message allocating between consumers + * 多个消费者之间分配消息队列算法策略 */ public interface AllocateMessageQueueStrategy { diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueAveragely.java b/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueAveragely.java index 155e692ad0b..d92f0b48573 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueAveragely.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueAveragely.java @@ -25,6 +25,13 @@ /** * Average Hashing queue algorithm + * 平均分配 + * 举例来说,如果现在有8个消息消费队列q1、q2、q3、q4、q5、 + * q6、q7、q8,有3个消费者c1、c2、c3,那么根据该负载算法,消息队 + * 列分配如下。 + * c1:q1、q2、q3。 + * c2:q4、q5、q6。 + * c3:q7、q8。 */ public class AllocateMessageQueueAveragely implements AllocateMessageQueueStrategy { private final InternalLogger log = ClientLogger.getLog(); diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueAveragelyByCircle.java b/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueAveragelyByCircle.java index fe78f0a6bbf..823c7856208 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueAveragelyByCircle.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueAveragelyByCircle.java @@ -25,6 +25,15 @@ /** * Cycle average Hashing queue algorithm + * + * 平均轮询分配 + * 举例来说,如果现在有8个消息消费队列q1、q2、q3、q4、q5、 + * q6、q7、q8,有3个消费者c1、c2、c3,那么根据该负载算法,消息队 + * 列分配如下 + * + * c1:q1、q4、q7。 + * c2:q2、q5、q8。 + * c3:q3、q6。 */ public class AllocateMessageQueueAveragelyByCircle implements AllocateMessageQueueStrategy { private final InternalLogger log = ClientLogger.getLog(); diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueByConfig.java b/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueByConfig.java index e548803d0d0..97fc275209f 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueByConfig.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueByConfig.java @@ -20,6 +20,9 @@ import org.apache.rocketmq.client.consumer.AllocateMessageQueueStrategy; import org.apache.rocketmq.common.message.MessageQueue; +/** + * 根据配置,为每一个消费者配置固定的消息队列。 + */ public class AllocateMessageQueueByConfig implements AllocateMessageQueueStrategy { private List messageQueueList; diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueByMachineRoom.java b/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueByMachineRoom.java index 37568317cb0..b1a91cf23b2 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueByMachineRoom.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueByMachineRoom.java @@ -24,6 +24,7 @@ /** * Computer room Hashing queue algorithm, such as Alipay logic room + * 根据Broker部署机房名,对每个消费者负责不同的Broker上的队列。 */ public class AllocateMessageQueueByMachineRoom implements AllocateMessageQueueStrategy { private Set consumeridcs; diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsistentHash.java b/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsistentHash.java index 65dcf799271..80b01aeeaac 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsistentHash.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsistentHash.java @@ -29,6 +29,7 @@ /** * Consistent Hashing queue algorithm + * 一致性哈希。因为消息队列负载信息不容易跟踪,所以不推荐使用 */ public class AllocateMessageQueueConsistentHash implements AllocateMessageQueueStrategy { private final InternalLogger log = ClientLogger.getLog(); diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java index 116bc4d5610..12b84031296 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java @@ -1096,6 +1096,18 @@ public boolean registerClient(final String addr, final HeartbeatData heartbeat, return response.getCode() == ResponseCode.SUCCESS; } + /** + * 将消息重新发回 broker retry topic,使得消费者能延迟一定时间后重新消费该消息 + * @param addr + * @param msg + * @param consumerGroup + * @param delayLevel + * @param timeoutMillis + * @param maxConsumeRetryTimes + * @throws RemotingException + * @throws MQBrokerException + * @throws InterruptedException + */ public void consumerSendMessageBack( final String addr, final MessageExt msg, @@ -1105,13 +1117,20 @@ public void consumerSendMessageBack( final int maxConsumeRetryTimes ) throws RemotingException, MQBrokerException, InterruptedException { ConsumerSendMsgBackRequestHeader requestHeader = new ConsumerSendMsgBackRequestHeader(); + // 命令类型为CONSUMER_SEND_MSG_BACK,broker端处理类为:org.apache.rocketmq.broker.processor.SendMessageProcessor.processRequest RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); requestHeader.setGroup(consumerGroup); + // 消息topic requestHeader.setOriginTopic(msg.getTopic()); + // 消息物理偏移量 requestHeader.setOffset(msg.getCommitLogOffset()); + // 延迟级别。RcketMQ不支持精确的定时消息调度,而是提供几个延时级别,MessageStoreConfig#messageDelayLevel = "1s 5s 10s 30s 1m 2m + //3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h",delayLevel=1,表示延迟5s,delayLevel=2,表示延迟10s。 requestHeader.setDelayLevel(delayLevel); + // 消息ID requestHeader.setOriginMsgId(msg.getMsgId()); + // 最大重试消费次数,默认16次 requestHeader.setMaxReconsumeTimes(maxConsumeRetryTimes); RemotingCommand response = this.remotingClient.invokeSync(MixAll.brokerVIPChannel(this.clientConfig.isVipChannelEnabled(), addr), diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyService.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyService.java index 258e4dbf877..7566761a951 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyService.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyService.java @@ -48,16 +48,47 @@ import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.remoting.common.RemotingHelper; +/** + * 并发消息消费实现 + */ public class ConsumeMessageConcurrentlyService implements ConsumeMessageService { private static final InternalLogger log = ClientLogger.getLog(); + /** + * 消息推模式的实现类,本质上使用的是拉模式(长轮询机制) + */ private final DefaultMQPushConsumerImpl defaultMQPushConsumerImpl; + /** + * 消费者对象 + */ private final DefaultMQPushConsumer defaultMQPushConsumer; + /** + * 并发消息业务事件类 + */ private final MessageListenerConcurrently messageListener; + /** + * 消息消费任务队列 + */ private final BlockingQueue consumeRequestQueue; + /** + * 消息消费线程池 + */ private final ThreadPoolExecutor consumeExecutor; + /** + * 消费组 + */ private final String consumerGroup; + /** + * 添加消费任务到consumeExecutor延迟调度器。 + */ private final ScheduledExecutorService scheduledExecutorService; + /** + * 定时删除过期消息线程池。为了揭示消息消费的完整过程,从服务器拉取 + * 到消息后,回调PullCallBack方法,先将消息放入ProccessQueue中, + * 然后把消息提交到消费线程池中执行,也就是调用 + * ConsumeMessageService#submitConsumeRequest开始进入消息消费的 + * 世界。 + */ private final ScheduledExecutorService cleanExpireMsgExecutors; public ConsumeMessageConcurrentlyService(DefaultMQPushConsumerImpl defaultMQPushConsumerImpl, @@ -203,15 +234,21 @@ public void submitConsumeRequest( final ProcessQueue processQueue, final MessageQueue messageQueue, final boolean dispatchToConsume) { + // consumeMessageBatchMaxSize表示消息批次,也就是一次消息消费任务ConsumeRequest中包含的消息条数,默认为1。 + // msgs.size()默认最多为32条消息,受DefaultMQPushConsumer.pullBatchSize属性控制,如果msgs.size() + // 小于consumeMessage BatchMaxSize,则直接将拉取到的消息放入ConsumeRequest,然后将consumeRequest提交到消息消费者线程池中 final int consumeBatchSize = this.defaultMQPushConsumer.getConsumeMessageBatchMaxSize(); if (msgs.size() <= consumeBatchSize) { ConsumeRequest consumeRequest = new ConsumeRequest(msgs, processQueue, messageQueue); try { this.consumeExecutor.submit(consumeRequest); } catch (RejectedExecutionException e) { + // 如果提交过程中出现拒绝提交异常,则延迟5s再提交 this.submitConsumeRequestLater(consumeRequest); } } else { + // 如果拉取的消息条数大于consumeMessageBatchMaxSize,则对拉取消息进行分页,每页 + // consumeMessageBatchMaxSize条消息,创建多个ConsumeRequest任务并提交到消费线程池 for (int total = 0; total < msgs.size(); ) { List msgThis = new ArrayList(consumeBatchSize); for (int i = 0; i < consumeBatchSize; i++, total++) { @@ -257,9 +294,12 @@ public void processConsumeResult( if (consumeRequest.getMsgs().isEmpty()) return; + // 根据消息监听器返回的结果计算ackIndex switch (status) { case CONSUME_SUCCESS: if (ackIndex >= consumeRequest.getMsgs().size()) { + // 如果返回CONSUME_SUCCESS,则将ackIndex设置为msgs.size()-1,这样在后面就不会执行 sendMessageBack,将消息重新 + // 发送至broker retry队列中去尝试重新消费该消息。 ackIndex = consumeRequest.getMsgs().size() - 1; } int ok = ackIndex + 1; @@ -268,6 +308,7 @@ public void processConsumeResult( this.getConsumerStatsManager().incConsumeFailedTPS(consumerGroup, consumeRequest.getMessageQueue().getTopic(), failed); break; case RECONSUME_LATER: + // 如果返回 RECONSUME_LATER,则将ackIndex设置为-1。这样就会将这一批消息全部发送至broker retry topic中,然后消费者就能重新消费到这一批消息 ackIndex = -1; this.getConsumerStatsManager().incConsumeFailedTPS(consumerGroup, consumeRequest.getMessageQueue().getTopic(), consumeRequest.getMsgs().size()); @@ -287,6 +328,7 @@ public void processConsumeResult( List msgBackFailed = new ArrayList(consumeRequest.getMsgs().size()); for (int i = ackIndex + 1; i < consumeRequest.getMsgs().size(); i++) { MessageExt msg = consumeRequest.getMsgs().get(i); + // 将消息重新发送至broker的 retry topic中, boolean result = this.sendMessageBack(msg, context); if (!result) { msg.setReconsumeTimes(msg.getReconsumeTimes() + 1); @@ -296,7 +338,7 @@ public void processConsumeResult( if (!msgBackFailed.isEmpty()) { consumeRequest.getMsgs().removeAll(msgBackFailed); - + // 消息确认失败,则五秒后重新消费消息 this.submitConsumeRequestLater(msgBackFailed, consumeRequest.getProcessQueue(), consumeRequest.getMessageQueue()); } break; @@ -304,8 +346,10 @@ public void processConsumeResult( break; } + // 从 processQueue中移除已确认消息,返回的偏移量是移除该批消息后最小的偏移量。 long offset = consumeRequest.getProcessQueue().removeMessage(consumeRequest.getMsgs()); if (offset >= 0 && !consumeRequest.getProcessQueue().isDropped()) { + // 然后更新已消费的offset,以便消费者重启后能从上一次的消费进度开始消费 this.defaultMQPushConsumerImpl.getOffsetStore().updateOffset(consumeRequest.getMessageQueue(), offset, true); } } @@ -314,6 +358,12 @@ public ConsumerStatsManager getConsumerStatsManager() { return this.defaultMQPushConsumerImpl.getConsumerStatsManager(); } + /** + * 将消息重新发回 broker retry topic,使得消费者能延迟一定时间后重新消费该消息 + * @param msg + * @param context + * @return + */ public boolean sendMessageBack(final MessageExt msg, final ConsumeConcurrentlyContext context) { int delayLevel = context.getDelayLevelWhenNextConsume(); @@ -356,6 +406,9 @@ public void run() { }, 5000, TimeUnit.MILLISECONDS); } + /** + * ConsumeRequest的run()方法封装了消息消费的具体逻辑 + */ class ConsumeRequest implements Runnable { private final List msgs; private final ProcessQueue processQueue; @@ -387,6 +440,8 @@ public void run() { ConsumeConcurrentlyStatus status = null; defaultMQPushConsumerImpl.resetRetryAndNamespace(msgs, defaultMQPushConsumer.getConsumerGroup()); + // 执行消息消费钩子函数ConsumeMessageHook#consumeMessageBefore。通过 + // consumer.getDefaultMQPushConsumerImpl().registerConsumeMessageHook(hook)方法消息消费执行钩子函数 ConsumeMessageContext consumeMessageContext = null; if (ConsumeMessageConcurrentlyService.this.defaultMQPushConsumerImpl.hasHook()) { consumeMessageContext = new ConsumeMessageContext(); @@ -408,6 +463,7 @@ public void run() { MessageAccessor.setConsumeStartTimeStamp(msg, String.valueOf(System.currentTimeMillis())); } } + // 执行业务代码消费消息 status = listener.consumeMessage(Collections.unmodifiableList(msgs), context); } catch (Throwable e) { log.warn("consumeMessage exception: {} Group: {} Msgs: {} MQ: {}", @@ -415,6 +471,7 @@ public void run() { ConsumeMessageConcurrentlyService.this.consumerGroup, msgs, messageQueue); + // 若出现异常,则设置未true hasException = true; } long consumeRT = System.currentTimeMillis() - beginTimestamp; @@ -425,6 +482,7 @@ public void run() { returnType = ConsumeReturnType.RETURNNULL; } } else if (consumeRT >= defaultMQPushConsumer.getConsumeTimeout() * 60 * 1000) { + // 消费超时 returnType = ConsumeReturnType.TIME_OUT; } else if (ConsumeConcurrentlyStatus.RECONSUME_LATER == status) { returnType = ConsumeReturnType.FAILED; @@ -444,6 +502,7 @@ public void run() { status = ConsumeConcurrentlyStatus.RECONSUME_LATER; } + // 执行消息消费钩子函数ConsumeMessageHook#consumeMessageAfter if (ConsumeMessageConcurrentlyService.this.defaultMQPushConsumerImpl.hasHook()) { consumeMessageContext.setStatus(status.toString()); consumeMessageContext.setSuccess(ConsumeConcurrentlyStatus.CONSUME_SUCCESS == status); @@ -453,7 +512,11 @@ public void run() { ConsumeMessageConcurrentlyService.this.getConsumerStatsManager() .incConsumeRT(ConsumeMessageConcurrentlyService.this.consumerGroup, messageQueue.getTopic(), consumeRT); + // 执行业务消息消费后,在处理结果前再次验证一次ProcessQueue的isDroped状态值。如果状态值为true,将不对结果进 + // 行任何处理。也就是说,在消息消费进入第四步时,如果因新的消费者加入或原先的消费者出现宕机,导致原先分配给消费者的队列在负 + // 载之后分配给了别的消费者,那么消息会被重复消费 if (!processQueue.isDropped()) { + // 处理消息消费结果 ConsumeMessageConcurrentlyService.this.processConsumeResult(status, context, this); } else { log.warn("processQueue is dropped without process consume result. messageQueue={}, msgs={}", messageQueue, msgs); diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageOrderlyService.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageOrderlyService.java index edc2647a5f1..06f936d78e7 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageOrderlyService.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageOrderlyService.java @@ -51,6 +51,9 @@ import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.remoting.common.RemotingHelper; +/** + * 顺序消息消费实现 + */ public class ConsumeMessageOrderlyService implements ConsumeMessageService { private static final InternalLogger log = ClientLogger.getLog(); private final static long MAX_TIME_CONSUME_CONTINUOUSLY = diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageService.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageService.java index 0f6f3bb38af..34bd9c7ff11 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageService.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageService.java @@ -21,6 +21,16 @@ import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; +/** + * RocketMQ使用ConsumeMessageService来实现消息消费的处理逻辑。 + * + * PullMessageService负责对消 + * 息队列进行消息拉取,从远端服务器拉取消息后存入ProcessQueue消 + * 息处理队列中,然后调用 + * ConsumeMessageService#submitConsumeRequest方法进行消息消费。 + * 使用线程池消费消息,确保了消息拉取与消息消费的解耦。 + * + */ public interface ConsumeMessageService { void start(); @@ -34,8 +44,21 @@ public interface ConsumeMessageService { int getCorePoolSize(); + /** + * 直接消费消息,主要用于通过管理命令接收消费消息 + * @param msg 消息 + * @param brokerName broker名称 + * @return + */ ConsumeMessageDirectlyResult consumeMessageDirectly(final MessageExt msg, final String brokerName); + /** + * 提交消息消费 + * @param msgs 消息列表,默认一次从服务器拉取32条消息 + * @param processQueue 消息处理队列 + * @param messageQueue 消息所属消费队列 + * @param dispathToConsume + */ void submitConsumeRequest( final List msgs, final ProcessQueue processQueue, diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java index 5c341cfecb7..73dc24fc7d0 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java @@ -547,6 +547,7 @@ public void sendMessageBack(MessageExt msg, int delayLevel, final String brokerN try { String brokerAddr = (null != brokerName) ? this.mQClientFactory.findBrokerAddressInPublish(brokerName) : RemotingHelper.parseSocketAddressAddr(msg.getStoreHost()); + // 将消息重新发回 broker retry topic,使得消费者能延迟一定时间后重新消费该消息 this.mQClientFactory.getMQClientAPIImpl().consumerSendMessageBack(brokerAddr, msg, this.defaultMQPushConsumer.getConsumerGroup(), delayLevel, 5000, getMaxReconsumeTimes()); } catch (Exception e) { diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ProcessQueue.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ProcessQueue.java index 3a9d5f6abdc..06568d1c0b6 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ProcessQueue.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ProcessQueue.java @@ -231,6 +231,11 @@ public long getMaxSpan() { return 0; } + /** + * 将消息移除,返回本地队列中最小的偏移量 + * @param msgs + * @return + */ public long removeMessage(final List msgs) { long result = -1; final long now = System.currentTimeMillis(); diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java index 146fce6e1e3..bba283d3f8c 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java @@ -240,6 +240,11 @@ public ConcurrentMap getSubscriptionInner() { return subscriptionInner; } + /** + * 对 topic下的消息进行重新负载 + * @param topic + * @param isOrder + */ private void rebalanceByTopic(final String topic, final boolean isOrder) { switch (messageModel) { case BROADCASTING: { @@ -260,7 +265,9 @@ private void rebalanceByTopic(final String topic, final boolean isOrder) { break; } case CLUSTERING: { + // 获取topic 的队列信息 Set mqSet = this.topicSubscribeInfoTable.get(topic); + // 发送请求,从broker中获取该消费组内当前所有的消费者客户端ID List cidAll = this.mQClientFactory.findConsumerIdList(topic, consumerGroup); if (null == mqSet) { if (!topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) { @@ -334,6 +341,8 @@ private boolean updateProcessQueueTableInRebalance(final String topic, final Set final boolean isOrder) { boolean changed = false; + // processQueueTable是当前消费者负载的消息队列缓存表,如果缓存表中的MessageQueue不包含在mqSet中,说明经过本次消息队列负载后, + // 该mq被分配给其他消费者,需要暂停该消息队列消息的消费 Iterator> it = this.processQueueTable.entrySet().iterator(); while (it.hasNext()) { Entry next = it.next(); @@ -342,7 +351,9 @@ private boolean updateProcessQueueTableInRebalance(final String topic, final Set if (mq.getTopic().equals(topic)) { if (!mqSet.contains(mq)) { + // 如果缓存表中的MessageQueue不包含在mqSet中,说明经过本次消息队列负载后,该mq被分配给其他消费者 pq.setDropped(true); + // 持久化消费进度至broker if (this.removeUnnecessaryMessageQueue(mq, pq)) { it.remove(); changed = true; @@ -371,13 +382,15 @@ private boolean updateProcessQueueTableInRebalance(final String topic, final Set List pullRequestList = new ArrayList(); for (MessageQueue mq : mqSet) { if (!this.processQueueTable.containsKey(mq)) { + // 如果 mqSet 不存在于本地缓存中,则证明是新增加的消息队列 if (isOrder && !this.lock(mq)) { log.warn("doRebalance, {}, add a new mq failed, {}, because lock failed", consumerGroup, mq); continue; } - + // 从内存中移除消息进度 this.removeDirtyOffset(mq); ProcessQueue pq = new ProcessQueue(); + // 计算消息消费的起始偏移量 long nextOffset = this.computePullFromWhere(mq); if (nextOffset >= 0) { ProcessQueue pre = this.processQueueTable.putIfAbsent(mq, pq); @@ -399,6 +412,7 @@ private boolean updateProcessQueueTableInRebalance(final String topic, final Set } } + // 将PullRequest 放入 PullMessageService 任务队列中,这样消费者就可以开始拉取消息 this.dispatchPullRequest(pullRequestList); return changed; diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java index e5166f35b59..aafc2db9276 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java @@ -81,6 +81,12 @@ public void messageQueueChanged(String topic, Set mqAll, Set= 0) { result = lastOffset; diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceService.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceService.java index c8f8ab14079..a427adf67f2 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceService.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceService.java @@ -21,6 +21,12 @@ import org.apache.rocketmq.common.ServiceThread; import org.apache.rocketmq.logging.InternalLogger; +/** + * 消息队列负载与重新分布机制的实现。 + * 问题一:集群内多个消费者如何负载topic下多个消息队列的呢? + * 问题二:如果有新的消费者加入,消息队列又会如何分布? + * + */ public class RebalanceService extends ServiceThread { private static long waitInterval = Long.parseLong(System.getProperty( @@ -37,6 +43,7 @@ public void run() { log.info(this.getServiceName() + " service started"); while (!this.isStopped()) { + // 默认每20s执行一次 doRebalance this.waitForRunning(waitInterval); this.mqClientFactory.doRebalance(); } diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java index 5625b6c68f4..4f47cbed79c 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java @@ -988,10 +988,12 @@ public void rebalanceImmediately() { } public void doRebalance() { + // 遍历消费者 for (Map.Entry entry : this.consumerTable.entrySet()) { MQConsumerInner impl = entry.getValue(); if (impl != null) { try { + // 对消费者执行 doRebalance impl.doRebalance(); } catch (Throwable e) { log.error("doRebalance exception", e); diff --git a/common/src/main/java/org/apache/rocketmq/common/consumer/ConsumeFromWhere.java b/common/src/main/java/org/apache/rocketmq/common/consumer/ConsumeFromWhere.java index 1bd542b7284..bdd59e709dd 100644 --- a/common/src/main/java/org/apache/rocketmq/common/consumer/ConsumeFromWhere.java +++ b/common/src/main/java/org/apache/rocketmq/common/consumer/ConsumeFromWhere.java @@ -18,7 +18,8 @@ public enum ConsumeFromWhere { /** - * 此处分为两种情况,如果磁盘消息未过期且未被删除,则从最小偏移量开始消费。如果磁盘已过期并被删除,则从最大偏移量开始消费。 + * 一个新的订阅组第一次启动从队列的最后位置开始消费
+ * 后续再启动接着上次消费的进度开始消费 */ CONSUME_FROM_LAST_OFFSET, @@ -28,12 +29,16 @@ public enum ConsumeFromWhere { CONSUME_FROM_MIN_OFFSET, @Deprecated CONSUME_FROM_MAX_OFFSET, + /** - * 从队列当前最小偏移量开始消费 + * 一个新的订阅组第一次启动从队列的最前位置开始消费
+ * 后续再启动接着上次消费的进度开始消费 */ CONSUME_FROM_FIRST_OFFSET, /** - * 从消费者指定时间戳开始消费 + * 一个新的订阅组第一次启动从指定时间点开始消费
+ * 后续再启动接着上次消费的进度开始消费
+ * 时间点设置参见DefaultMQPushConsumer.consumeTimestamp参数 */ CONSUME_FROM_TIMESTAMP, } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java index bd8fbb44ca0..f823b46e12e 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java @@ -23,13 +23,26 @@ import org.apache.rocketmq.remoting.exception.RemotingCommandException; public class ConsumerSendMsgBackRequestHeader implements CommandCustomHeader { + /** + * 消息物理偏移量 + */ @CFNotNull private Long offset; @CFNotNull private String group; + /** + * 延迟级别。RcketMQ不支持精确的定时消息调度,而是提供几个延时级别,MessageStoreConfig#messageDelayLevel = "1s 5s 10s 30s 1m 2m + * 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h",delayLevel=1,表示延迟5s,delayLevel=2,表示延迟10s。 + */ @CFNotNull private Integer delayLevel; + /** + * 消息ID + */ private String originMsgId; + /** + * 消息topic + */ private String originTopic; @CFNullable private boolean unitMode = false; diff --git a/common/src/main/java/org/apache/rocketmq/common/subscription/SubscriptionGroupConfig.java b/common/src/main/java/org/apache/rocketmq/common/subscription/SubscriptionGroupConfig.java index 8f4703f6c80..c73bb7001b9 100644 --- a/common/src/main/java/org/apache/rocketmq/common/subscription/SubscriptionGroupConfig.java +++ b/common/src/main/java/org/apache/rocketmq/common/subscription/SubscriptionGroupConfig.java @@ -21,21 +21,47 @@ public class SubscriptionGroupConfig { + /** + * 消费组名 + */ private String groupName; - + /** + * 是否可以消费,默认为true,如果consumeEnable=false,该消费组无法拉取消息,因而无法消费消息 + */ private boolean consumeEnable = true; + /** + * 是否允许从队列最小偏移量开始消费,默认为true,目前未使用该参数 + */ private boolean consumeFromMinEnable = true; - + /** + * 设置该消费组是否能以广播模式消费,默认为true,如果设置为false,表示只能以集群模式消费 + */ private boolean consumeBroadcastEnable = true; - + /** + * 重试队列个数,默认为1,每一个Broker上有一个重试队列 + */ private int retryQueueNums = 1; - + /** + * 消息最大重试次数,默认16次 + */ private int retryMaxTimes = 16; - + /** + * 主节点ID + */ private long brokerId = MixAll.MASTER_ID; - + /** + * 如果消息堵塞(主节点),将转向该brokerId的服务器上拉取消息,默认为1 + */ private long whichBrokerWhenConsumeSlowly = 1; - + /** + * 当消费发生变化时,是否 + * 立即进行消息队列重新负载。消费组订阅信息配置信息存储在Broker + * 的 ${ROCKET_HOME}/store/config/subscriptionGroup.json中。 + * BrokerConfig.autoCreateSubscriptionGroup默认为true,表示在第 + * 一次使用消费组配置信息时如果不存在消费组,则使用上述默认值自 + * 动创建一个,如果为false,则只能通过客户端命令mqadmin + * updateSubGroup创建消费组后再修改相关参数 + */ private boolean notifyConsumerIdsChangedEnable = true; public String getGroupName() { diff --git "a/images/RocketMQ\346\266\210\346\201\257\346\213\211\345\217\226\345\222\214\346\266\210\350\264\271\346\265\201\347\250\213.png" "b/images/RocketMQ\346\266\210\346\201\257\346\213\211\345\217\226\345\222\214\346\266\210\350\264\271\346\265\201\347\250\213.png" new file mode 100644 index 0000000000000000000000000000000000000000..85ea709a034dffd5fc45be5e19a5c8156c689544 GIT binary patch literal 202248 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�i^ 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 WeoR0Yorxj8kd;)DC>4MF{Qm(sZTTty literal 0 HcmV?d00001 From 07debfb2ded9dd961fdfc4edff0ce11d4e529d5c Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sun, 29 Oct 2023 17:14:48 +0800 Subject: [PATCH 07/18] =?UTF-8?q?'RocketMQ=E6=B6=88=E6=81=AF=E6=B6=88?= =?UTF-8?q?=E8=B4=B9=E6=B5=81=E7=A8=8B=E4=BB=A3=E7=A0=81=E6=B3=A8=E9=87=8A?= =?UTF-8?q?'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 ++- .../broker/filter/ConsumerFilterManager.java | 3 + .../filter/ExpressionMessageFilter.java | 23 +++++- .../processor/ClientManageProcessor.java | 4 + .../processor/PullMessageProcessor.java | 5 ++ .../consumer/store/LocalFileOffsetStore.java | 12 +++ .../client/consumer/store/OffsetStore.java | 25 ++++-- .../store/RemoteBrokerOffsetStore.java | 4 + .../ConsumeMessageOrderlyService.java | 42 +++++++++- .../client/impl/consumer/PullAPIWrapper.java | 1 + .../client/impl/consumer/RebalanceImpl.java | 6 ++ .../rocketmq/common/filter/FilterAPI.java | 6 ++ .../protocol/heartbeat/SubscriptionData.java | 18 +++++ .../org/apache/rocketmq/store/CommitLog.java | 9 ++- .../rocketmq/store/DefaultMessageStore.java | 5 ++ .../apache/rocketmq/store/MessageFilter.java | 8 +- .../schedule/ScheduleMessageService.java | 81 +++++++++++++++++++ 17 files changed, 245 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index d52b1ce9355..7421fdda9c9 100644 --- a/README.md +++ b/README.md @@ -13,4 +13,11 @@ - 消息消费代码入口:org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService.ConsumeRequest.run -![](./images/RocketMQ消息拉取和消费流程.png) \ No newline at end of file +![](./images/RocketMQ消息拉取和消费流程.png) + +- 消息消费进度存储接口:org.apache.rocketmq.client.consumer.store.OffsetStore + - 集群模式消息消费进度存储:org.apache.rocketmq.client.consumer.store.RemoteBrokerOffsetStore + - 广播模式消息消费进度存储: org.apache.rocketmq.client.consumer.store.LocalFileOffsetStore +- 定时消息代码入口:org.apache.rocketmq.store.schedule.ScheduleMessageService +- 消息过滤代码入口:org.apache.rocketmq.store.DefaultMessageStore.getMessage、org.apache.rocketmq.broker.filter.ExpressionMessageFilter +- \ No newline at end of file diff --git a/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterManager.java b/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterManager.java index e9c5286bb1b..0f9fe9bf0cf 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterManager.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterManager.java @@ -136,10 +136,12 @@ public void register(final String consumerGroup, final Collection properties) { if (subscriptionData == null) { @@ -125,6 +142,8 @@ public boolean isMatchedByCommitLog(ByteBuffer msgBuffer, Map pr } if (ExpressionType.isTagType(subscriptionData.getExpressionType())) { + // 如果是TAG过滤,则默认返回True,因为前面比对了ConsumeQueue中的TAG hash码,如果出现Hash冲突,则交由客户端解决。 + // 因为客户端拿到消息后,会对消息中的TAG进行严格比对,而不是Hash比对。 return true; } @@ -138,6 +157,7 @@ public boolean isMatchedByCommitLog(ByteBuffer msgBuffer, Map pr } if (tempProperties == null && msgBuffer != null) { + // 对消息进行解码,获取消息中的属性值 tempProperties = MessageDecoder.decodeProperties(msgBuffer); } @@ -145,6 +165,7 @@ public boolean isMatchedByCommitLog(ByteBuffer msgBuffer, Map pr try { MessageEvaluationContext context = new MessageEvaluationContext(tempProperties); + // 使用SQL92方式过滤消息 ret = realFilterData.getCompiledExpression().evaluate(context); } catch (Throwable e) { log.error("Message Filter error, " + realFilterData + ", " + tempProperties, e); diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java index 971237929ab..45f3a5db324 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java @@ -54,6 +54,7 @@ public ClientManageProcessor(final BrokerController brokerController) { public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) throws RemotingCommandException { switch (request.getCode()) { + // 接收客户端心跳指令,保存客户端信息 case RequestCode.HEART_BEAT: return this.heartBeat(ctx, request); case RequestCode.UNREGISTER_CLIENT: @@ -81,6 +82,7 @@ public RemotingCommand heartBeat(ChannelHandlerContext ctx, RemotingCommand requ request.getVersion() ); + // 处理消费者心跳 for (ConsumerData data : heartbeatData.getConsumerDataSet()) { SubscriptionGroupConfig subscriptionGroupConfig = this.brokerController.getSubscriptionGroupManager().findSubscriptionGroupConfig( @@ -99,6 +101,7 @@ public RemotingCommand heartBeat(ChannelHandlerContext ctx, RemotingCommand requ PermName.PERM_WRITE | PermName.PERM_READ, topicSysFlag); } + // 注册消费者信息 boolean changed = this.brokerController.getConsumerManager().registerConsumer( data.getGroupName(), clientChannelInfo, @@ -117,6 +120,7 @@ public RemotingCommand heartBeat(ChannelHandlerContext ctx, RemotingCommand requ } } + // 处理生产者心跳 for (ProducerData data : heartbeatData.getProducerDataSet()) { this.brokerController.getProducerManager().registerProducer(data.getGroupName(), clientChannelInfo); diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java index 26b11647b68..0455608efb6 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java @@ -158,10 +158,12 @@ private RemotingCommand processRequest(final Channel channel, RemotingCommand re ConsumerFilterData consumerFilterData = null; if (hasSubscriptionFlag) { try { + subscriptionData = FilterAPI.build( requestHeader.getTopic(), requestHeader.getSubscription(), requestHeader.getExpressionType() ); if (!ExpressionType.isTagType(subscriptionData.getExpressionType())) { + // 如果不是TAG过滤模式,则构建ConsumerFilterData consumerFilterData = ConsumerFilterManager.build( requestHeader.getTopic(), requestHeader.getConsumerGroup(), requestHeader.getSubscription(), requestHeader.getExpressionType(), requestHeader.getSubVersion() @@ -232,11 +234,14 @@ private RemotingCommand processRequest(final Channel channel, RemotingCommand re return response; } + // 构建消息过滤器 MessageFilter messageFilter; if (this.brokerController.getBrokerConfig().isFilterSupportRetry()) { + //表示支持对重试topic的属性进行过滤 messageFilter = new ExpressionForRetryMessageFilter(subscriptionData, consumerFilterData, this.brokerController.getConsumerFilterManager()); } else { + // 表示不支持对重试topic的属性进行过滤 messageFilter = new ExpressionMessageFilter(subscriptionData, consumerFilterData, this.brokerController.getConsumerFilterManager()); } diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java b/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java index b758ac70609..ca96bae593e 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java @@ -36,16 +36,26 @@ import org.apache.rocketmq.remoting.exception.RemotingException; /** + * 消费进度存储的本地实现。广播消费模式下使用该实现。 * Local storage implementation */ public class LocalFileOffsetStore implements OffsetStore { + /** + * 消息进度存储目录 + */ public final static String LOCAL_OFFSET_STORE_DIR = System.getProperty( "rocketmq.client.localOffsetStoreDir", System.getProperty("user.home") + File.separator + ".rocketmq_offsets"); private final static InternalLogger log = ClientLogger.getLog(); private final MQClientInstance mQClientFactory; private final String groupName; + /** + * 消息进度存储文件LOCAL_OFFSET_STORE_DIR/.rocketmq_offsets/{mQClientFactory.getClientId()}/groupName/offsets.json + */ private final String storePath; + /** + * 消息消费进度(内存) + */ private ConcurrentMap offsetTable = new ConcurrentHashMap(); @@ -60,6 +70,8 @@ public LocalFileOffsetStore(MQClientInstance mQClientFactory, String groupName) @Override public void load() throws MQClientException { + // OffsetSerializeWrapper内部就是ConcurrentMapoffsetTable数据结构的封装,readLocalOffset方法首先 + // 从storePath中尝试加载内容,如果读取的内容为空,尝试从storePath+".bak"中加载,如果还是未找到内容,则返回null。 OffsetSerializeWrapper offsetSerializeWrapper = this.readLocalOffset(); if (offsetSerializeWrapper != null && offsetSerializeWrapper.getOffsetTable() != null) { offsetTable.putAll(offsetSerializeWrapper.getOffsetTable()); diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/store/OffsetStore.java b/client/src/main/java/org/apache/rocketmq/client/consumer/store/OffsetStore.java index 9deed0e3dfe..e03bcb1759a 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/store/OffsetStore.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/store/OffsetStore.java @@ -28,24 +28,31 @@ */ public interface OffsetStore { /** + * 从消息进度存储文件加载消息进度到内存 * Load */ void load() throws MQClientException; /** - * Update the offset,store it in memory + * 更新内存中的消息消费进度 + * @param mq 消息消费队列 + * @param offset 消息消费偏移量 + * @param increaseOnly true表示offset必须大于内存中当前的消费偏移量才更新 */ void updateOffset(final MessageQueue mq, final long offset, final boolean increaseOnly); /** - * Get offset from local storage - * - * @return The fetched offset + * 读取消息消费进度 + * @param mq 消息消费队列 + * @param type 读取方式,可选值包括 + * READ_FROM_MEMORY,即从内存中读取,READ_FROM_STORE,即从磁盘中读取,MEMORY_FIRST_THEN_STORE,即先从内存中读取,再从磁盘中读取 + * @return */ long readOffset(final MessageQueue mq, final ReadOffsetType type); /** - * Persist all offsets,may be in local storage or remote name server + * 持久化指定消息队列进度到磁盘 + * @param mqs */ void persistAll(final Set mqs); @@ -55,16 +62,20 @@ public interface OffsetStore { void persist(final MessageQueue mq); /** - * Remove offset + * 将消息队列的消息消费进度从内存中移除。 + * @param mq */ void removeOffset(MessageQueue mq); /** - * @return The cloned offset table of given topic + * 复制该主题下所有消息队列的消息消费进度。 + * @param topic + * @return */ Map cloneOffsetTable(String topic); /** + * 使用集群模式更新存储在Broker端的消息消费进度 * @param mq * @param offset * @param isOneway diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java b/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java index 6b762383717..e5d2b6e15eb 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java @@ -37,12 +37,16 @@ import org.apache.rocketmq.remoting.exception.RemotingException; /** + * 消费进度存储的远程实现。集群消费模式下使用该实现。 * Remote storage implementation */ public class RemoteBrokerOffsetStore implements OffsetStore { private final static InternalLogger log = ClientLogger.getLog(); private final MQClientInstance mQClientFactory; private final String groupName; + /** + * 内存中的消息消费进度 + */ private ConcurrentMap offsetTable = new ConcurrentHashMap(); diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageOrderlyService.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageOrderlyService.java index 06f936d78e7..fd2c36a272e 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageOrderlyService.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageOrderlyService.java @@ -60,11 +60,27 @@ public class ConsumeMessageOrderlyService implements ConsumeMessageService { Long.parseLong(System.getProperty("rocketmq.client.maxTimeConsumeContinuously", "60000")); private final DefaultMQPushConsumerImpl defaultMQPushConsumerImpl; private final DefaultMQPushConsumer defaultMQPushConsumer; + /** + * 顺序消息消费监听器 + */ private final MessageListenerOrderly messageListener; + /** + * 消息消费任务队列 + */ private final BlockingQueue consumeRequestQueue; + /** + * 消息消费线程池 + */ private final ThreadPoolExecutor consumeExecutor; private final String consumerGroup; + /** + * 消息消费端消息消费队列锁容器,内部持有 + * ConcurrentMap mqLockTable =new ConcurrentHashMap() + */ private final MessageQueueLock messageQueueLock = new MessageQueueLock(); + /** + * 调度任务线程池 + */ private final ScheduledExecutorService scheduledExecutorService; private volatile boolean stopped = false; @@ -90,6 +106,8 @@ public ConsumeMessageOrderlyService(DefaultMQPushConsumerImpl defaultMQPushConsu public void start() { if (MessageModel.CLUSTERING.equals(ConsumeMessageOrderlyService.this.defaultMQPushConsumerImpl.messageModel())) { + // 如果消费模式为集群模式,启动定时任务,默认每隔20s锁定一次分配给自己的消息消费队列。通过 + // -Drocketmq.client.rebalance.lockInterval=20000设置间隔,该值建议与一次消息负载频率相同 this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { @@ -195,6 +213,13 @@ public ConsumeMessageDirectlyResult consumeMessageDirectly(MessageExt msg, Strin return result; } + /** + * 提交消息消费任务 + * @param msgs 消息列表,默认一次从服务器拉取32条消息 + * @param processQueue 消息处理队列 + * @param messageQueue 消息所属消费队列 + * @param dispathToConsume + */ @Override public void submitConsumeRequest( final List msgs, @@ -415,15 +440,22 @@ public MessageQueue getMessageQueue() { @Override public void run() { + // 如果消息处理队列为丢弃,则停止本次消费任务 if (this.processQueue.isDropped()) { log.warn("run, the message queue not be able to consume, because it's dropped. {}", this.messageQueue); return; } + // 根据消息队列获取一个对象。消费消息时申请独占objLock,顺序消息消费的并发度为消息队列,也就是一个消息消费队 + // 列同一时刻只会被一个消费线程池中的一个线程消费 final Object objLock = messageQueueLock.fetchLockObject(this.messageQueue); + synchronized (objLock) { + // 如果是广播模式,则直接进入消费,无须锁定处理队列,因为相互之间无竞争。如果是集群模式,消息消费的前提条件是 + //proceessQueue被锁定并且锁未超时 if (MessageModel.BROADCASTING.equals(ConsumeMessageOrderlyService.this.defaultMQPushConsumerImpl.messageModel()) || (this.processQueue.isLocked() && !this.processQueue.isLockExpired())) { + final long beginTime = System.currentTimeMillis(); for (boolean continueConsume = true; continueConsume; ) { if (this.processQueue.isDropped()) { @@ -434,6 +466,9 @@ public void run() { if (MessageModel.CLUSTERING.equals(ConsumeMessageOrderlyService.this.defaultMQPushConsumerImpl.messageModel()) && !this.processQueue.isLocked()) { log.warn("the message queue not locked, so consume later, {}", this.messageQueue); + // 当一个新的消费队列分配给消费者时,在添加其拉取任务之前必须先向Broker发送对该消息队列加锁的请求,只有加锁成功后, + //才能添加拉取消息,否则等到下一次负载后,只有消费队列被原先占有的消费者释放后,才能开始新的拉取任务 + // 集群模式下,如果未锁定处理队列,则延迟该队列的消息消费 ConsumeMessageOrderlyService.this.tryLockLaterAndReconsume(this.messageQueue, this.processQueue, 10); break; } @@ -441,6 +476,7 @@ public void run() { if (MessageModel.CLUSTERING.equals(ConsumeMessageOrderlyService.this.defaultMQPushConsumerImpl.messageModel()) && this.processQueue.isLockExpired()) { log.warn("the message queue lock expired, so consume later, {}", this.messageQueue); + // 锁超时,延迟该队列的消息消费 ConsumeMessageOrderlyService.this.tryLockLaterAndReconsume(this.messageQueue, this.processQueue, 10); break; } @@ -462,6 +498,9 @@ public void run() { ConsumeOrderlyStatus status = null; ConsumeMessageContext consumeMessageContext = null; + // 执行消息消费钩子函数(消息消费之前before方法)。通过 + // DefaultMQPushConsumerImpl#registerConsumeMessageHook(ConsumeMessageHookconsumeMessagehook) + // 注册消息消费钩子函数并可以注册多个 if (ConsumeMessageOrderlyService.this.defaultMQPushConsumerImpl.hasHook()) { consumeMessageContext = new ConsumeMessageContext(); consumeMessageContext @@ -479,13 +518,14 @@ public void run() { ConsumeReturnType returnType = ConsumeReturnType.SUCCESS; boolean hasException = false; try { + // 申请消息消费锁,如果消息队列被丢弃,则放弃消费该消息消费队列,然后执行消息消费监听器 this.processQueue.getLockConsume().lock(); if (this.processQueue.isDropped()) { log.warn("consumeMessage, the message queue not be able to consume, because it's dropped. {}", this.messageQueue); break; } - + // 执行消息消费 status = messageListener.consumeMessage(Collections.unmodifiableList(msgs), context); } catch (Throwable e) { log.warn("consumeMessage exception: {} Group: {} Msgs: {} MQ: {}", diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java index be1afd00885..b2edbc1d454 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java @@ -77,6 +77,7 @@ public PullResult processPullResult(final MessageQueue mq, final PullResult pull List msgList = MessageDecoder.decodes(byteBuffer); List msgListFilterAgain = msgList; + // 根据TAG值进行过滤 if (!subscriptionData.getTagsSet().isEmpty() && !subscriptionData.isClassFilterMode()) { msgListFilterAgain = new ArrayList(msgList.size()); for (MessageExt msg : msgList) { diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java index bba283d3f8c..da1723f2dc6 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java @@ -169,6 +169,8 @@ public boolean lock(final MessageQueue mq) { } public void lockAll() { + // ConcurrentMap processQueueTable表示将消息队列按照Broker组织成 + // Map>,方便下一步向Broker发送锁定消息队列请求 HashMap> brokerMqs = this.buildProcessQueueTableByBrokerName(); Iterator>> it = brokerMqs.entrySet().iterator(); @@ -188,9 +190,11 @@ public void lockAll() { requestBody.setMqSet(mqs); try { + // 向Broker(主节点)发送锁定消息队列,该方法会返回成功被当前消费者锁定的消息消费队列 Set lockOKMQSet = this.mQClientFactory.getMQClientAPIImpl().lockBatchMQ(findBrokerResult.getBrokerAddr(), requestBody, 1000); + // 将成功锁定的消息消费队列对应的处理队列设置为锁定状态,同时更新加锁时间 for (MessageQueue mq : lockOKMQSet) { ProcessQueue processQueue = this.processQueueTable.get(mq); if (processQueue != null) { @@ -203,6 +207,8 @@ public void lockAll() { } } for (MessageQueue mq : mqs) { + // 遍历当前处理队列中的消息消费队列,如果当前消费者不持该消息队列的锁,则将处理队列锁的状态设置为false,暂停该消 + // 息消费队列的消息拉取与消息消费 if (!lockOKMQSet.contains(mq)) { ProcessQueue processQueue = this.processQueueTable.get(mq); if (processQueue != null) { diff --git a/common/src/main/java/org/apache/rocketmq/common/filter/FilterAPI.java b/common/src/main/java/org/apache/rocketmq/common/filter/FilterAPI.java index 9268a6ef45d..624b01b5079 100644 --- a/common/src/main/java/org/apache/rocketmq/common/filter/FilterAPI.java +++ b/common/src/main/java/org/apache/rocketmq/common/filter/FilterAPI.java @@ -43,15 +43,19 @@ public static SubscriptionData buildSubscriptionData(final String consumerGroup, subscriptionData.setSubString(subString); if (null == subString || subString.equals(SubscriptionData.SUB_ALL) || subString.length() == 0) { + // 订阅所有消息 subscriptionData.setSubString(SubscriptionData.SUB_ALL); } else { + // 如果订阅的不是*,则通过 || 分割 String[] tags = subString.split("\\|\\|"); if (tags.length > 0) { for (String tag : tags) { if (tag.length() > 0) { String trimString = tag.trim(); if (trimString.length() > 0) { + // 保存分割后的TAG值 subscriptionData.getTagsSet().add(trimString); + // 保存分割后的TAG HashCode subscriptionData.getCodeSet().add(trimString.hashCode()); } } @@ -66,6 +70,7 @@ public static SubscriptionData buildSubscriptionData(final String consumerGroup, public static SubscriptionData build(final String topic, final String subString, final String type) throws Exception { + // 如果是TAG过滤,则执行这里 if (ExpressionType.TAG.equals(type) || type == null) { return buildSubscriptionData(null, topic, subString); } @@ -74,6 +79,7 @@ public static SubscriptionData build(final String topic, final String subString, throw new IllegalArgumentException("Expression can't be null! " + type); } + // 如果是SQL过滤,则执行这里,相对简单,直接原样发送给broker SubscriptionData subscriptionData = new SubscriptionData(); subscriptionData.setTopic(topic); subscriptionData.setSubString(subString); diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/SubscriptionData.java b/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/SubscriptionData.java index 83e254f22ed..d55e15ae01d 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/SubscriptionData.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/SubscriptionData.java @@ -27,13 +27,31 @@ import java.util.Set; public class SubscriptionData implements Comparable { + /** + * 过滤模式,默认为全匹配 + */ public final static String SUB_ALL = "*"; + /** + * 是否为类过滤模式,默认为false + */ private boolean classFilterMode = false; private String topic; + /** + * 消息过滤表达式,多个用双竖线隔开,例如“TAGA||TAGB” + */ private String subString; + /** + * 消息过滤标志集合,是消费端过滤时进行消息过滤的依据 + */ private Set tagsSet = new HashSet(); + /** + * 消息过滤标志hash码集合 + */ private Set codeSet = new HashSet(); private long subVersion = System.currentTimeMillis(); + /** + * 过滤类型,TAG 或 SQL92 + */ private String expressionType = ExpressionType.TAG; @JSONField(serialize = false) diff --git a/store/src/main/java/org/apache/rocketmq/store/CommitLog.java b/store/src/main/java/org/apache/rocketmq/store/CommitLog.java index b66d4f692f4..d624a3cad44 100644 --- a/store/src/main/java/org/apache/rocketmq/store/CommitLog.java +++ b/store/src/main/java/org/apache/rocketmq/store/CommitLog.java @@ -595,19 +595,20 @@ public PutMessageResult putMessage(final MessageExtBrokerInner msg) { final int tranType = MessageSysFlag.getTransactionValue(msg.getSysFlag()); if (tranType == MessageSysFlag.TRANSACTION_NOT_TYPE || tranType == MessageSysFlag.TRANSACTION_COMMIT_TYPE) { - // Delay Delivery + // 延迟消息判断,如果大于0则代表是延迟消息 if (msg.getDelayTimeLevel() > 0) { if (msg.getDelayTimeLevel() > this.defaultMessageStore.getScheduleMessageService().getMaxDelayLevel()) { msg.setDelayTimeLevel(this.defaultMessageStore.getScheduleMessageService().getMaxDelayLevel()); } - + // 将延迟消息的topic替换为broker固定的topic: SCHEDULE_TOPIC_XXXX topic = ScheduleMessageService.SCHEDULE_TOPIC; + // 将queueid替换为(延迟级别-1) queueId = ScheduleMessageService.delayLevel2QueueId(msg.getDelayTimeLevel()); // Backup real topic, queueId - // 如果消息的延迟级别大于0,将消息的原主题名称与原消息队列ID存入消息属性中,用延迟消息主题SCHEDULE_TOPIC_XXXX、消 - //息队列ID更新原先消息的主题与队列,这是并发消息重试关键的异步 + // 如果延迟消息,将消息的原主题名称与原消息队列ID存入消息属性中,用延迟消息主题SCHEDULE_TOPIC_XXXX、消 + //息队列ID更新原先消息的主题与队列,这是并发消息重试关键的一步 MessageAccessor.putProperty(msg, MessageConst.PROPERTY_REAL_TOPIC, msg.getTopic()); MessageAccessor.putProperty(msg, MessageConst.PROPERTY_REAL_QUEUE_ID, String.valueOf(msg.getQueueId())); msg.setPropertiesString(MessageDecoder.messageProperties2String(msg.getProperties())); diff --git a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java index 6a3b262f2ff..4f59b16c0ac 100644 --- a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java +++ b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java @@ -640,8 +640,11 @@ public GetMessageResult getMessage(final String group, final String topic, final final boolean diskFallRecorded = this.messageStoreConfig.isDiskFallRecorded(); ConsumeQueueExt.CqExtUnit cqExtUnit = new ConsumeQueueExt.CqExtUnit(); for (; i < bufferConsumeQueue.getSize() && i < maxFilterMessageCount; i += ConsumeQueue.CQ_STORE_UNIT_SIZE) { + // 消息物理偏移量 long offsetPy = bufferConsumeQueue.getByteBuffer().getLong(); + // 消息长度 int sizePy = bufferConsumeQueue.getByteBuffer().getInt(); + // 消息TAG的hash码 long tagsCode = bufferConsumeQueue.getByteBuffer().getLong(); maxPhyOffsetPulling = offsetPy; @@ -671,6 +674,7 @@ public GetMessageResult getMessage(final String group, final String topic, final } } + // 对消息TAG的Hash码进行比对,如果未匹配,则继续拉取下一条消息 if (messageFilter != null && !messageFilter.isMatchedByConsumeQueue(isTagsCodeLegal ? tagsCode : null, extRet ? cqExtUnit : null)) { if (getResult.getBufferTotalSize() == 0) { @@ -690,6 +694,7 @@ public GetMessageResult getMessage(final String group, final String topic, final continue; } + // 对消息属性进行SQL92过滤,此种过滤方式会反序列化消息内容,性能相对TAG过滤会差一点 if (messageFilter != null && !messageFilter.isMatchedByCommitLog(selectResult.getByteBuffer().slice(), null)) { if (getResult.getBufferTotalSize() == 0) { diff --git a/store/src/main/java/org/apache/rocketmq/store/MessageFilter.java b/store/src/main/java/org/apache/rocketmq/store/MessageFilter.java index 3dd0fee2907..cf5e511cbd5 100644 --- a/store/src/main/java/org/apache/rocketmq/store/MessageFilter.java +++ b/store/src/main/java/org/apache/rocketmq/store/MessageFilter.java @@ -21,16 +21,20 @@ public interface MessageFilter { /** + * 根据ConsumeQueue判断消息是否匹配 + * * match by tags code or filter bit map which is calculated when message received * and stored in consume queue ext. * - * @param tagsCode tagsCode - * @param cqExtUnit extend unit of consume queue + * @param tagsCode 消息标志的哈希码 + * @param cqExtUnit ConsumeQueue条目扩展属性 */ boolean isMatchedByConsumeQueue(final Long tagsCode, final ConsumeQueueExt.CqExtUnit cqExtUnit); /** + * 根据存储在CommitLog文件中的内容判断消息是否匹配。 + * * match by message content which are stored in commit log. *
{@code msgBuffer} and {@code properties} are not all null.If invoked in store, * {@code properties} is null;If invoked in {@code PullRequestHoldService}, {@code msgBuffer} is null. diff --git a/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java b/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java index 50a48d4de9c..652a562b21b 100644 --- a/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java +++ b/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java @@ -44,19 +44,58 @@ import org.apache.rocketmq.store.SelectMappedBufferResult; import org.apache.rocketmq.store.config.StorePathConfigHelper; +/** + * 定时消息的实现类 + * + * ScheduleMessageService方法的调用顺序为构造方法→load()方法→start()方法。 + * + * 定时消息的第一个设计关键点是,定时消息单独一个主题: + * SCHEDULE_TOPIC_XXXX,该主题下的队列数量等于 + * MessageStoreConfig#messageDelayLevel配置的延迟级别,其对应关 + * 系为queueId等于延迟级别减1。ScheduleMessageService为每个延迟 + * 级别创建一个定时器,根据延迟级别对应的延迟时间进行延迟调度。 + * 在消息发送时,如果消息的延迟级别delayLevel大于0,将消息的原主 + * 题名称、队列ID存入消息属性,然后改变消息的主题、队列与延迟主 + * 题所属队列,消息将最终转发到延迟队列的消费队列中。 + * + * 定时器会根据延迟级别的间隔,扫描对应的延迟队列(延迟级别和延迟队列ID的对应关系是:queueId等于延迟级别减1),如果发现有 + * 达到消费时间的延迟消息,则会将延迟消息重新发送至原始的topic,这样消费者就能开始消费这条消息了。 + */ public class ScheduleMessageService extends ConfigManager { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.STORE_LOGGER_NAME); + /** + * 定时消息统一主题 + */ public static final String SCHEDULE_TOPIC = "SCHEDULE_TOPIC_XXXX"; + /** + * 第一次调度时延迟的时间,默认为1s + */ private static final long FIRST_DELAY_TIME = 1000L; + /** + * 每一个延时级别调度一次后,延迟该时间间隔后再放入调度池 + */ private static final long DELAY_FOR_A_WHILE = 100L; + /** + * 消息发送异常后延迟该时间后再继续参与调度 + */ private static final long DELAY_FOR_A_PERIOD = 10000L; + /** + * 延迟级别,将“1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h” 字符串解析成delayLevelTable,转换后的数据结构类似 + * {1:1000,2:5000,3:30000,...} + */ private final ConcurrentMap delayLevelTable = new ConcurrentHashMap(32); + /** + * 延迟级别消息消费进度 + */ private final ConcurrentMap offsetTable = new ConcurrentHashMap(32); + /** + * 默认消息存储器 + */ private final DefaultMessageStore defaultMessageStore; private final AtomicBoolean started = new AtomicBoolean(false); private Timer timer; @@ -110,12 +149,24 @@ public long computeDeliverTimestamp(final int delayLevel, final long storeTimest return storeTimestamp + 1000; } + /** + * 根据延迟级别创建对应的定时任务 + */ public void start() { if (started.compareAndSet(false, true)) { this.timer = new Timer("ScheduleMessageTimerThread", true); + // 根据延迟队列创建定时任务。遍历延迟级别,根据延迟 + // 级别从offsetTable中获取消息队列的消费进度,如果不存在,则使用 + // 0。也就是说每个延迟级别对应一个消息消费队列。然后创建定时任 + // 务,每个定时任务第一次启动时,默认延迟1s后执行一次定时任务, + // 从第二次调度开始,才使用相应的延迟时间执行定时任务。延迟级别 + // 与消息消费队列的映射关系为消息队列ID=延迟级别-1 for (Map.Entry entry : this.delayLevelTable.entrySet()) { + // 延迟级别 Integer level = entry.getKey(); + // 延迟级别对应的毫秒值 Long timeDelay = entry.getValue(); + // 对应延迟级别的消费进度 Long offset = this.offsetTable.get(level); if (null == offset) { offset = 0L; @@ -126,6 +177,7 @@ public void start() { } } + // 创建定时任务,每隔10s持久化一次延迟队列的消息消费进度(延迟消息调进度),持久化频率可以通过flushDelayOffsetInterval配置属性进行设置 this.timer.scheduleAtFixedRate(new TimerTask() { @Override @@ -160,8 +212,17 @@ public String encode() { return this.encode(false); } + /** + * 该方法主要完成延迟消息消费队列消息进度的加载与 + * delayLevelTable数据的构造,延迟队列消息消费进度默认存储路径为 + * ${ROCKET_HOME}/store/config/delayOffset.json + * + * @return + */ public boolean load() { + // 调用 configFilePath() 加载 ${ROCKET_HOME}/store/config/delayOffset.json,然后调用decode() 反序列化延迟消费进度 boolean result = super.load(); + // 初始化 delayLevel result = result && this.parseDelayLevel(); return result; } @@ -260,6 +321,7 @@ private long correctDeliverTimestamp(final long now, final long deliverTimestamp } public void executeOnTimeup() { + // 根据队列ID与延迟主题查找消息消费队列,如果未找到,说明当前不存在该延时级别的消息,则忽略本次任务,根据延时级别创建下一次调度任务 ConsumeQueue cq = ScheduleMessageService.this.defaultMessageStore.findConsumeQueue(SCHEDULE_TOPIC, delayLevel2QueueId(delayLevel)); @@ -267,15 +329,21 @@ public void executeOnTimeup() { long failScheduleOffset = offset; if (cq != null) { + // 根据offset从消息消费队列中获取当前队列中所有有效的消息。如果未找到,则更新延迟队列的定时拉取进度并创建定时任务,待下一次继续尝试 SelectMappedBufferResult bufferCQ = cq.getIndexBuffer(this.offset); if (bufferCQ != null) { try { long nextOffset = offset; int i = 0; + // 遍历ConsumeQueue文件,每一个标准ConsumeQueue条目为20个字节。解析出消息的物理偏移量、消息长度、消息标志的哈希 + //码,为从CommitLog文件加载具体的消息做准备 ConsumeQueueExt.CqExtUnit cqExtUnit = new ConsumeQueueExt.CqExtUnit(); for (; i < bufferCQ.getSize(); i += ConsumeQueue.CQ_STORE_UNIT_SIZE) { + // 消息在CommitLog中物理偏移量 long offsetPy = bufferCQ.getByteBuffer().getLong(); + // 消息长度 int sizePy = bufferCQ.getByteBuffer().getInt(); + // tag hashcode, 如果为延迟消息,这8个字节放的是消息存储时间 long tagsCode = bufferCQ.getByteBuffer().getLong(); if (cq.isExtAddr(tagsCode)) { @@ -286,11 +354,14 @@ public void executeOnTimeup() { log.error("[BUG] can't find consume queue extend file content!addr={}, offsetPy={}, sizePy={}", tagsCode, offsetPy, sizePy); long msgStoreTime = defaultMessageStore.getCommitLog().pickupStoreTimestamp(offsetPy, sizePy); + // 根据延迟级别,计算当前消息应该消费的时间 tagsCode = computeDeliverTimestamp(delayLevel, msgStoreTime); } } + long now = System.currentTimeMillis(); + // 计算投递时间,时间存储在 tag hashcode那8个字节中了 long deliverTimestamp = this.correctDeliverTimestamp(now, tagsCode); nextOffset = offset + (i / ConsumeQueue.CQ_STORE_UNIT_SIZE); @@ -298,13 +369,19 @@ public void executeOnTimeup() { long countdown = deliverTimestamp - now; if (countdown <= 0) { + // 如果当前这个消息已经达到应该投递的事件了,则将延迟消息发送至原始的Topic中 + + // 去broker中将消息读取出来 MessageExt msgExt = ScheduleMessageService.this.defaultMessageStore.lookMessageByOffset( offsetPy, sizePy); if (msgExt != null) { try { + // 根据从延迟队列中拉取的消息,组装一个新的消息,恢复延迟消息原始的topic和queueId,删除延迟信息 MessageExtBrokerInner msgInner = this.messageTimeup(msgExt); + + // 将延迟消息发送至原始的topic中 PutMessageResult putMessageResult = ScheduleMessageService.this.writeMessageStore .putMessage(msgInner); @@ -338,9 +415,11 @@ public void executeOnTimeup() { } } } else { + // 当前消息未到消费的时候,则重新创建一个任务,等待下一次扫描 延迟队列 ScheduleMessageService.this.timer.schedule( new DeliverDelayedMessageTimerTask(this.delayLevel, nextOffset), countdown); + // 更新一下已经消费的延迟消息进度 ScheduleMessageService.this.updateOffset(this.delayLevel, nextOffset); return; } @@ -392,8 +471,10 @@ private MessageExtBrokerInner messageTimeup(MessageExt msgExt) { msgInner.setWaitStoreMsgOK(false); MessageAccessor.clearProperty(msgInner, MessageConst.PROPERTY_DELAY_TIME_LEVEL); + // 恢复原始的topic信息 msgInner.setTopic(msgInner.getProperty(MessageConst.PROPERTY_REAL_TOPIC)); + // 恢复原始的队列ID String queueIdStr = msgInner.getProperty(MessageConst.PROPERTY_REAL_QUEUE_ID); int queueId = Integer.parseInt(queueIdStr); msgInner.setQueueId(queueId); From 25cd16a59fd6f18887a7d4f242907140eae3ec6b Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Mon, 30 Oct 2023 19:24:04 +0800 Subject: [PATCH 08/18] =?UTF-8?q?RocketMQ=E9=A1=BA=E5=BA=8F=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E4=BB=A3=E7=A0=81=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- .../AbstractSendMessageProcessor.java | 4 +++- .../broker/topic/TopicConfigManager.java | 2 ++ .../ConsumeMessageOrderlyService.java | 20 +++++++++++++++---- .../consumer/DefaultMQPushConsumerImpl.java | 2 ++ .../client/impl/consumer/RebalanceImpl.java | 3 +++ .../impl/consumer/RebalancePushImpl.java | 5 +++++ .../rocketmq/example/quickstart/Consumer.java | 2 ++ 8 files changed, 34 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7421fdda9c9..0b2dab69a9b 100644 --- a/README.md +++ b/README.md @@ -20,4 +20,4 @@ - 广播模式消息消费进度存储: org.apache.rocketmq.client.consumer.store.LocalFileOffsetStore - 定时消息代码入口:org.apache.rocketmq.store.schedule.ScheduleMessageService - 消息过滤代码入口:org.apache.rocketmq.store.DefaultMessageStore.getMessage、org.apache.rocketmq.broker.filter.ExpressionMessageFilter -- \ No newline at end of file +- 顺序消息消费代码入口:org.apache.rocketmq.client.impl.consumer.ConsumeMessageOrderlyService \ No newline at end of file diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java index 08769e52c9c..6ae88c836da 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java @@ -172,7 +172,8 @@ protected RemotingCommand msgCheck(final ChannelHandlerContext ctx, + "] sending message is forbidden"); return response; } - // 检查topic是否可以进行消息发送。主要针对默认主题,默认主题不能发送消息,仅供路由查找。 + // 检查topic是否可以进行消息发送。主要针对默认主题,默认主题不能发送消息,默认主题仅在生产者指定Topic还未创建时提供路由查找, + // 使得客户端能将消息发送出来,broker收到消息后,发现没有指定的topic就会创建topic if (!this.brokerController.getTopicConfigManager().isTopicCanSendMessage(requestHeader.getTopic())) { String errorMsg = "the topic[" + requestHeader.getTopic() + "] is conflict with system reserved words."; log.warn(errorMsg); @@ -193,6 +194,7 @@ protected RemotingCommand msgCheck(final ChannelHandlerContext ctx, } } + // 如果生产者指定topic不存在,则创建对应的topic log.warn("the topic {} not exist, producer: {}", requestHeader.getTopic(), ctx.channel().remoteAddress()); topicConfig = this.brokerController.getTopicConfigManager().createTopicInSendMessageMethod( requestHeader.getTopic(), diff --git a/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java b/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java index cb2901117f8..a215cde69c0 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java @@ -67,6 +67,7 @@ public TopicConfigManager(BrokerController brokerController) { } { // MixAll.AUTO_CREATE_TOPIC_KEY_TOPIC + // 是否开启了自动创建主题 if (this.brokerController.getBrokerConfig().isAutoCreateTopicEnable()) { String topic = MixAll.AUTO_CREATE_TOPIC_KEY_TOPIC; TopicConfig topicConfig = new TopicConfig(topic); @@ -228,6 +229,7 @@ public TopicConfig createTopicInSendMessageMethod(final String topic, final Stri } if (createNew) { + // 同步NameServer this.brokerController.registerBrokerAll(false, true, true); } diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageOrderlyService.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageOrderlyService.java index fd2c36a272e..f772b53735d 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageOrderlyService.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageOrderlyService.java @@ -53,6 +53,10 @@ /** * 顺序消息消费实现 + * + * 该类中有一个 ConsumeMessageOrderlyService.ConsumeRequest 内部类 + * 区分于 ConsumeMessageConcurrentlyService.ConsumeRequest,当前类的ConsumeRequest实现中,会尝试对消费的队列加分布式锁, + * 只有加锁成功后才会消费该队列 */ public class ConsumeMessageOrderlyService implements ConsumeMessageService { private static final InternalLogger log = ClientLogger.getLog(); @@ -106,8 +110,7 @@ public ConsumeMessageOrderlyService(DefaultMQPushConsumerImpl defaultMQPushConsu public void start() { if (MessageModel.CLUSTERING.equals(ConsumeMessageOrderlyService.this.defaultMQPushConsumerImpl.messageModel())) { - // 如果消费模式为集群模式,启动定时任务,默认每隔20s锁定一次分配给自己的消息消费队列。通过 - // -Drocketmq.client.rebalance.lockInterval=20000设置间隔,该值建议与一次消息负载频率相同 + // Broker 消息队列锁会过期,默认配置 30s。因此,Consumer 需要不断向 Broker 刷新该锁过期时间,默认配置 20s 刷新一次。 this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { @@ -450,9 +453,12 @@ public void run() { // 列同一时刻只会被一个消费线程池中的一个线程消费 final Object objLock = messageQueueLock.fetchLockObject(this.messageQueue); + // 在当前进程内队列加锁 + // 虽然在PullMessage时已经对队列加了分布式锁,但是这一步是为了防止多个线程同时消费同一个消息队列的消息。 + // 这样一来,在多线程环境下,也能保持每个消息队列都是单线程消费,保证了顺序 synchronized (objLock) { // 如果是广播模式,则直接进入消费,无须锁定处理队列,因为相互之间无竞争。如果是集群模式,消息消费的前提条件是 - //proceessQueue被锁定并且锁未超时 + // proceessQueue被锁定并且锁未超时(超时时间默认30s) if (MessageModel.BROADCASTING.equals(ConsumeMessageOrderlyService.this.defaultMQPushConsumerImpl.messageModel()) || (this.processQueue.isLocked() && !this.processQueue.isLockExpired())) { @@ -518,7 +524,13 @@ public void run() { ConsumeReturnType returnType = ConsumeReturnType.SUCCESS; boolean hasException = false; try { - // 申请消息消费锁,如果消息队列被丢弃,则放弃消费该消息消费队列,然后执行消息消费监听器 + // 申请消息消费锁, + // 外面已经对队列加了一次锁了,理论上来说一个队列只会有一个线程消费,为什么还要在这里再加一个消费锁呢? + // 这是因为有队列重平衡的逻辑存在,A实例消费者的某个队列被分配给了B实例消费者,那么此时A实例消费者需要解除对broker队列加的分布式锁, + // 如果此时A实例正在消费消息,并且不在这里加消费锁,A实例重平衡后就会立即释放broker队列锁,就可能会出现B实例消费者拿到了 broker 队列的分布式锁拉取到消息, + // 这样就会出现A实例和B实例同时消费同一个队列的存在 + + // 说白了,在这里加锁是为了防止在消费途中,发生重平衡,将broker队列锁释放(org.apache.rocketmq.client.impl.consumer.RebalancePushImpl.removeUnnecessaryMessageQueue) this.processQueue.getLockConsume().lock(); if (this.processQueue.isDropped()) { log.warn("consumeMessage, the message queue not be able to consume, because it's dropped. {}", diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java index 73dc24fc7d0..bfe86f935a8 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java @@ -651,10 +651,12 @@ public synchronized void start() throws MQClientException { // 如果是顺序消费,创建消费端消费线程服务。ConsumeMessageService主要负责消息消费,在内部维护一个线程池 if (this.getMessageListenerInner() instanceof MessageListenerOrderly) { + // 如果是顺序消费,将 consumeOrderly 置为 true,这样在RebalanceService负载队列时对队列加锁,实现消费端顺序消费,防止多个客户端同时消费同一个队列 this.consumeOrderly = true; this.consumeMessageService = new ConsumeMessageOrderlyService(this, (MessageListenerOrderly) this.getMessageListenerInner()); } else if (this.getMessageListenerInner() instanceof MessageListenerConcurrently) { + // 如果是并发消费,则设置 consumeOrderly 为 false,消费时不会对队列进行加锁 this.consumeOrderly = false; this.consumeMessageService = new ConsumeMessageConcurrentlyService(this, (MessageListenerConcurrently) this.getMessageListenerInner()); diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java index da1723f2dc6..68f573b49ae 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java @@ -144,8 +144,10 @@ public boolean lock(final MessageQueue mq) { requestBody.getMqSet().add(mq); try { + // 远程RPC,锁定broker中的队列 Set lockedMq = this.mQClientFactory.getMQClientAPIImpl().lockBatchMQ(findBrokerResult.getBrokerAddr(), requestBody, 1000); + for (MessageQueue mmqq : lockedMq) { ProcessQueue processQueue = this.processQueueTable.get(mmqq); if (processQueue != null) { @@ -389,6 +391,7 @@ private boolean updateProcessQueueTableInRebalance(final String topic, final Set for (MessageQueue mq : mqSet) { if (!this.processQueueTable.containsKey(mq)) { // 如果 mqSet 不存在于本地缓存中,则证明是新增加的消息队列 + // 如果是顺序消费,则需要对queue进行加锁,只有加锁成功才会创建 PullRequest 拉取broker消息 if (isOrder && !this.lock(mq)) { log.warn("doRebalance, {}, add a new mq failed, {}, because lock failed", consumerGroup, mq); continue; diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java index aafc2db9276..6690bd4ae3d 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java @@ -93,9 +93,13 @@ public boolean removeUnnecessaryMessageQueue(MessageQueue mq, ProcessQueue pq) { this.defaultMQPushConsumerImpl.getOffsetStore().removeOffset(mq); if (this.defaultMQPushConsumerImpl.isConsumeOrderly() && MessageModel.CLUSTERING.equals(this.defaultMQPushConsumerImpl.messageModel())) { + // 集群模式下,顺序消费移除时,解锁对队列的锁定 try { + // 获取消息队列消费锁,避免和消息队列消费冲突。如果获取锁失败,则移除消息队列失败,等待下次重新分配消费队列时,再进行移除。 + // 如果未获得锁而进行移除,则可能出现另外的 Consumer 和当前 Consumer 同时消费该消息队列,导致消息无法严格顺序消费。 if (pq.getLockConsume().tryLock(1000, TimeUnit.MILLISECONDS)) { try { + // 解除在broker上加的队列锁 return this.unlockDelay(mq, pq); } finally { pq.getLockConsume().unlock(); @@ -118,6 +122,7 @@ public boolean removeUnnecessaryMessageQueue(MessageQueue mq, ProcessQueue pq) { private boolean unlockDelay(final MessageQueue mq, final ProcessQueue pq) { + // 解锁 Broker 消息队列锁。如果消息处理队列存在剩余消息,则延迟解锁 Broker 消息队列锁。 if (pq.hasTempMessage()) { log.info("[{}]unlockDelay, begin {} ", mq.hashCode(), mq); this.defaultMQPushConsumerImpl.getmQClientFactory().getScheduledExecutorService().schedule(new Runnable() { diff --git a/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java b/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java index 9eba15934da..7023d90708a 100644 --- a/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java +++ b/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java @@ -59,6 +59,8 @@ public static void main(String[] args) throws InterruptedException, MQClientExce */ consumer.subscribe("TopicTest", "*"); + consumer.registerMessageListener(); + /* * Register callback to execute on arrival of messages fetched from brokers. */ From 3198910b227a380ecd17589479ed60a40bd2d795 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Mon, 30 Oct 2023 19:31:00 +0800 Subject: [PATCH 09/18] =?UTF-8?q?=E6=9B=B4=E6=96=B0README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b2dab69a9b..e4da68fbebd 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,14 @@ # RocketMQ 源码分析 ## 消息存储 +- 文件内存映射:org.apache.rocketmq.store.MappedFileQueue + - 消息存储文件:org.apache.rocketmq.store.CommitLog + - 消息队列索引:org.apache.rocketmq.store.ConsumeQueue + - 消息属性索引文件:org.apache.rocketmq.store.index.IndexFile +- 消息刷盘机制:org.apache.rocketmq.store.CommitLog#handleDiskFlush +- 消息存储流程:org.apache.rocketmq.store.DefaultMessageStore#putMessage +> 参考文章:[详解RocketMQ消息存储原理](https://blog.bigcoder.cn/archives/17b04280) ## 消息拉取与消费 @@ -20,4 +27,6 @@ - 广播模式消息消费进度存储: org.apache.rocketmq.client.consumer.store.LocalFileOffsetStore - 定时消息代码入口:org.apache.rocketmq.store.schedule.ScheduleMessageService - 消息过滤代码入口:org.apache.rocketmq.store.DefaultMessageStore.getMessage、org.apache.rocketmq.broker.filter.ExpressionMessageFilter -- 顺序消息消费代码入口:org.apache.rocketmq.client.impl.consumer.ConsumeMessageOrderlyService \ No newline at end of file +- 顺序消息消费代码入口:org.apache.rocketmq.client.impl.consumer.ConsumeMessageOrderlyService + +> 参考文章:[RocketMQ源码分析](https://github.com/bigcoder84/study-notes/blob/master/%E5%88%86%E5%B8%83%E5%BC%8F%E4%B8%8E%E5%BE%AE%E6%9C%8D%E5%8A%A1/MessageQueue/RocketMQ/index.md) \ No newline at end of file From b6323734125a2506144a3bbb8759b96b01f0a73d Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Tue, 31 Oct 2023 20:02:18 +0800 Subject: [PATCH 10/18] =?UTF-8?q?RocketMQ=E4=BA=8B=E5=8A=A1=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E4=BB=A3=E7=A0=81=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 +++- .../processor/EndTransactionProcessor.java | 15 +++++++++++- .../processor/SendMessageProcessor.java | 1 + .../queue/TransactionalMessageBridge.java | 4 ++++ .../TransactionalMessageServiceImpl.java | 9 +++++++ .../impl/producer/DefaultMQProducerImpl.java | 9 +++++++ .../producer/TransactionMQProducer.java | 21 ++++++++++++++-- .../org/apache/rocketmq/common/MixAll.java | 9 +++++++ .../header/EndTransactionRequestHeader.java | 24 +++++++++++++++++-- .../rocketmq/example/quickstart/Consumer.java | 14 ++++++++++- 10 files changed, 104 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e4da68fbebd..b8100d77d59 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,11 @@ - 消息属性索引文件:org.apache.rocketmq.store.index.IndexFile - 消息刷盘机制:org.apache.rocketmq.store.CommitLog#handleDiskFlush - 消息存储流程:org.apache.rocketmq.store.DefaultMessageStore#putMessage - > 参考文章:[详解RocketMQ消息存储原理](https://blog.bigcoder.cn/archives/17b04280) +- 事务消息:org.apache.rocketmq.broker.transaction.TransactionalMessageService +> 参考文章:[RocketMQ事务消息源码解析](https://github.com/bigcoder84/study-notes/blob/master/%E5%88%86%E5%B8%83%E5%BC%8F%E4%B8%8E%E5%BE%AE%E6%9C%8D%E5%8A%A1/MessageQueue/RocketMQ/subfile/_13RocketMQ%E4%BA%8B%E5%8A%A1%E6%B6%88%E6%81%AF.md) + + ## 消息拉取与消费 diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/EndTransactionProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/EndTransactionProcessor.java index 1d5943d4313..426602fa5fa 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/processor/EndTransactionProcessor.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/EndTransactionProcessor.java @@ -122,29 +122,40 @@ public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand } } OperationResult result = new OperationResult(); + // 如果请求为提交事务,进入事务消息提交处理流程 if (MessageSysFlag.TRANSACTION_COMMIT_TYPE == requestHeader.getCommitOrRollback()) { + // 根据commitLogOffset从commitlog文件中查找消息 result = this.brokerController.getTransactionalMessageService().commitMessage(requestHeader); if (result.getResponseCode() == ResponseCode.SUCCESS) { + // 字段检查 RemotingCommand res = checkPrepareMessage(result.getPrepareMessage(), requestHeader); if (res.getCode() == ResponseCode.SUCCESS) { + // 恢复事务消息的真实的主题、队列,并设置事务ID MessageExtBrokerInner msgInner = endMessageTransaction(result.getPrepareMessage()); + // 设置消息的相关属性,取消事务相关的系统标记 msgInner.setSysFlag(MessageSysFlag.resetTransactionValue(msgInner.getSysFlag(), requestHeader.getCommitOrRollback())); msgInner.setQueueOffset(requestHeader.getTranStateTableOffset()); msgInner.setPreparedTransactionOffset(requestHeader.getCommitLogOffset()); msgInner.setStoreTimestamp(result.getPrepareMessage().getStoreTimestamp()); + // 发送最终消息,存储,被consumer消费 RemotingCommand sendResult = sendFinalMessage(msgInner); if (sendResult.getCode() == ResponseCode.SUCCESS) { + // 事务消息提交,删除Half消息。 Half消息不会真的被删除,通过写入Op消息来标记它被处理。 + // 其实是将消息存储在主题为:RMQ_SYS_TRANS_OP_HALF_TOPIC的主题中,代表这些消息已经被处理(提交或回滚)。 this.brokerController.getTransactionalMessageService().deletePrepareMessage(result.getPrepareMessage()); } return sendResult; } return res; } - } else if (MessageSysFlag.TRANSACTION_ROLLBACK_TYPE == requestHeader.getCommitOrRollback()) { + } + // 回滚处理 + else if (MessageSysFlag.TRANSACTION_ROLLBACK_TYPE == requestHeader.getCommitOrRollback()) { result = this.brokerController.getTransactionalMessageService().rollbackMessage(requestHeader); if (result.getResponseCode() == ResponseCode.SUCCESS) { RemotingCommand res = checkPrepareMessage(result.getPrepareMessage(), requestHeader); if (res.getCode() == ResponseCode.SUCCESS) { + // 删除半消息 this.brokerController.getTransactionalMessageService().deletePrepareMessage(result.getPrepareMessage()); } return res; @@ -192,7 +203,9 @@ private RemotingCommand checkPrepareMessage(MessageExt msgExt, EndTransactionReq private MessageExtBrokerInner endMessageTransaction(MessageExt msgExt) { MessageExtBrokerInner msgInner = new MessageExtBrokerInner(); + // 恢复消息的真实主题 msgInner.setTopic(msgExt.getUserProperty(MessageConst.PROPERTY_REAL_TOPIC)); + // 恢复消息的真实队列ID msgInner.setQueueId(Integer.parseInt(msgExt.getUserProperty(MessageConst.PROPERTY_REAL_QUEUE_ID))); msgInner.setBody(msgExt.getBody()); msgInner.setFlag(msgExt.getFlag()); diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java index 624296a8207..93d4fa722ff 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java @@ -381,6 +381,7 @@ private RemotingCommand sendMessage(final ChannelHandlerContext ctx, + "] sending transaction message is forbidden"); return response; } + // 如果是事务消息,则存储事务消息 putMessageResult = this.brokerController.getTransactionalMessageService().prepareMessage(msgInner); } else { putMessageResult = this.brokerController.getMessageStore().putMessage(msgInner); diff --git a/broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageBridge.java b/broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageBridge.java index 67f7a5f5628..801630608b4 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageBridge.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageBridge.java @@ -196,11 +196,13 @@ public PutMessageResult putHalfMessage(MessageExtBrokerInner messageInner) { } private MessageExtBrokerInner parseHalfMessageInner(MessageExtBrokerInner msgInner) { + // 备份原始topic 和 队列ID MessageAccessor.putProperty(msgInner, MessageConst.PROPERTY_REAL_TOPIC, msgInner.getTopic()); MessageAccessor.putProperty(msgInner, MessageConst.PROPERTY_REAL_QUEUE_ID, String.valueOf(msgInner.getQueueId())); msgInner.setSysFlag( MessageSysFlag.resetTransactionValue(msgInner.getSysFlag(), MessageSysFlag.TRANSACTION_NOT_TYPE)); + // 事务消息在提交之前,会放入同一的topic 和queueId中 msgInner.setTopic(TransactionalMessageUtil.buildHalfTopic()); msgInner.setQueueId(0); msgInner.setPropertiesString(MessageDecoder.messageProperties2String(msgInner.getProperties())); @@ -295,6 +297,7 @@ private TopicConfig selectTopicConfig(String topic) { } /** + * * Use this function while transaction msg is committed or rollback write a flag 'd' to operation queue for the * msg's offset * @@ -303,6 +306,7 @@ private TopicConfig selectTopicConfig(String topic) { * @return This method will always return true. */ private boolean addRemoveTagInTransactionOp(MessageExt messageExt, MessageQueue messageQueue) { + // “删除”半消息,实际上是给 op 队列存入一条新的消息,消息的body就是半消息的偏移量,标识这个半消息已经被消费或被回滚 Message message = new Message(TransactionalMessageUtil.buildOpTopic(), TransactionalMessageUtil.REMOVETAG, String.valueOf(messageExt.getQueueOffset()).getBytes(TransactionalMessageUtil.charset)); writeOp(message, messageQueue); diff --git a/broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImpl.java b/broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImpl.java index 71b575eec09..0100a80514b 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImpl.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImpl.java @@ -122,15 +122,19 @@ public void check(long transactionTimeout, int transactionCheckMax, AbstractTransactionalMessageCheckListener listener) { try { String topic = MixAll.RMQ_SYS_TRANS_HALF_TOPIC; + // 获取事务半消息topic下所有队列信息 Set msgQueues = transactionalMessageBridge.fetchMessageQueues(topic); if (msgQueues == null || msgQueues.size() == 0) { log.warn("The queue of topic is empty :" + topic); return; } log.debug("Check topic={}, queues={}", topic, msgQueues); + // 遍历每一个队列,查询需要会查事务状态的消息 for (MessageQueue messageQueue : msgQueues) { long startTime = System.currentTimeMillis(); + // 获取对应的op队列 MessageQueue opQueue = getOpQueue(messageQueue); + // 获取ConsumeQueue Offset long halfOffset = transactionalMessageBridge.fetchConsumeOffset(messageQueue); long opOffset = transactionalMessageBridge.fetchConsumeOffset(opQueue); log.info("Before check, the queue={} msgOffset={} opOffset={}", messageQueue, halfOffset, opOffset); @@ -181,7 +185,9 @@ public void check(long transactionTimeout, int transactionCheckMax, } } + // 判断是否达到回查次数, if (needDiscard(msgExt, transactionCheckMax) || needSkip(msgExt)) { + // 回查次数超过15,丢弃消息,扔到TRANS_CHECK_MAX_TIME_TOPIC listener.resolveDiscardMsg(msgExt); newOffset = i + 1; i++; @@ -260,6 +266,8 @@ private long getImmunityTime(String checkImmunityTimeStr, long transactionTimeou } /** + * 读取op消息,解析op消息,并填充removeMap + * * Read op message, parse op message, and fill removeMap * * @param removeMap Half message to be remove, key:halfOffset, value: opOffset. @@ -299,6 +307,7 @@ private PullResult fillOpRemoveMap(HashMap removeMap, if (queueOffset < miniOffset) { doneOpOffset.add(opMessageExt.getQueueOffset()); } else { + // 标识该半消息”已删除“ removeMap.put(queueOffset, opMessageExt.getQueueOffset()); } } else { diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java index 6404ae2afa1..7e038e84655 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java @@ -1248,6 +1248,7 @@ public void sendOneway(Message msg, MessageQueueSelector selector, Object arg) public TransactionSendResult sendMessageInTransaction(final Message msg, final LocalTransactionExecuter localTransactionExecuter, final Object arg) throws MQClientException { + // 判断检查本地事务Listener是否存在 TransactionListener transactionListener = getCheckListener(); if (null == localTransactionExecuter && null == transactionListener) { throw new MQClientException("tranExecutor is null", null); @@ -1258,12 +1259,15 @@ public TransactionSendResult sendMessageInTransaction(final Message msg, MessageAccessor.clearProperty(msg, MessageConst.PROPERTY_DELAY_TIME_LEVEL); } + // 检查消息内容 Validators.checkMessage(msg, this.defaultMQProducer); SendResult sendResult = null; + // 标识当前消息为事务消息 MessageAccessor.putProperty(msg, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true"); MessageAccessor.putProperty(msg, MessageConst.PROPERTY_PRODUCER_GROUP, this.defaultMQProducer.getProducerGroup()); try { + // 发送消息 sendResult = this.send(msg); } catch (Exception e) { throw new MQClientException("send message Exception", e); @@ -1284,6 +1288,7 @@ public TransactionSendResult sendMessageInTransaction(final Message msg, if (null != localTransactionExecuter) { localTransactionState = localTransactionExecuter.executeLocalTransactionBranch(msg, arg); } else if (transactionListener != null) { + // 发送消息成功,执行本地事务 log.debug("Used new transaction API"); localTransactionState = transactionListener.executeLocalTransaction(msg, arg); } @@ -1312,6 +1317,8 @@ public TransactionSendResult sendMessageInTransaction(final Message msg, } try { + // 执行endTransaction方法,如果半消息发送失败或本地事务执行失败告诉服务端是删除半消息, + // 半消息发送成功且本地事务执行成功则告诉broker提交半消息 this.endTransaction(sendResult, localTransactionState, localException); } catch (Exception e) { log.warn("local transaction execute " + localTransactionState + ", but end broker transaction failed", e); @@ -1350,6 +1357,7 @@ public void endTransaction( EndTransactionRequestHeader requestHeader = new EndTransactionRequestHeader(); requestHeader.setTransactionId(transactionId); requestHeader.setCommitLogOffset(id.getOffset()); + // 根据本地事务状态,映射不同消息事务操作 switch (localTransactionState) { case COMMIT_MESSAGE: requestHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_COMMIT_TYPE); @@ -1368,6 +1376,7 @@ public void endTransaction( requestHeader.setTranStateTableOffset(sendResult.getQueueOffset()); requestHeader.setMsgId(sendResult.getMsgId()); String remark = localException != null ? ("executeLocalTransactionBranch exception: " + localException.toString()) : null; + // 发送消息事务确认命令 this.mQClientFactory.getMQClientAPIImpl().endTransactionOneway(brokerAddr, requestHeader, remark, this.defaultMQProducer.getSendMsgTimeout()); } diff --git a/client/src/main/java/org/apache/rocketmq/client/producer/TransactionMQProducer.java b/client/src/main/java/org/apache/rocketmq/client/producer/TransactionMQProducer.java index 63b512df7d5..4197c823708 100644 --- a/client/src/main/java/org/apache/rocketmq/client/producer/TransactionMQProducer.java +++ b/client/src/main/java/org/apache/rocketmq/client/producer/TransactionMQProducer.java @@ -23,13 +23,30 @@ import org.apache.rocketmq.remoting.RPCHook; public class TransactionMQProducer extends DefaultMQProducer { + + /** + * 务回查监听 + */ private TransactionCheckListener transactionCheckListener; + /** + * 回查线程池最小线程数 + */ private int checkThreadPoolMinSize = 1; + /** + * 回查线程池最大线程数 + */ private int checkThreadPoolMaxSize = 1; + /** + * 最大回查请求数,阻塞队列容量 + */ private int checkRequestHoldMax = 2000; - + /** + * 执行本地事务/事务回查的线程池 + */ private ExecutorService executorService; - + /** + * 事务监听器:本地事务、事务回查逻辑 + */ private TransactionListener transactionListener; public TransactionMQProducer() { diff --git a/common/src/main/java/org/apache/rocketmq/common/MixAll.java b/common/src/main/java/org/apache/rocketmq/common/MixAll.java index e9a67bb5c00..e5b2b2840eb 100644 --- a/common/src/main/java/org/apache/rocketmq/common/MixAll.java +++ b/common/src/main/java/org/apache/rocketmq/common/MixAll.java @@ -85,8 +85,17 @@ public class MixAll { public static final String DEFAULT_TRACE_REGION_ID = "DefaultRegion"; public static final String CONSUME_CONTEXT_TYPE = "ConsumeContextType"; public static final String RMQ_SYS_TRANS_HALF_TOPIC = "RMQ_SYS_TRANS_HALF_TOPIC"; + /** + * 事务消息的半消息最初会放入该topic中 + */ public static final String RMQ_SYS_TRACE_TOPIC = "RMQ_SYS_TRACE_TOPIC"; + /** + * commit or rollback的消息最终会放入该topic,标识指定半消息已到达最终态,不需要回查本地事务状态了 + */ public static final String RMQ_SYS_TRANS_OP_HALF_TOPIC = "RMQ_SYS_TRANS_OP_HALF_TOPIC"; + /** + * 超过回查次数的半消息最终会放入该topic + */ public static final String TRANS_CHECK_MAX_TIME_TOPIC = "TRANS_CHECK_MAX_TIME_TOPIC"; public static final String CID_SYS_RMQ_TRANS = "CID_RMQ_SYS_TRANS"; public static final String ACL_CONF_TOOLS_FILE = "/conf/tools.yml"; diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/EndTransactionRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/EndTransactionRequestHeader.java index 87661c320ad..6934156f5fc 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/EndTransactionRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/EndTransactionRequestHeader.java @@ -24,23 +24,43 @@ import org.apache.rocketmq.remoting.exception.RemotingCommandException; public class EndTransactionRequestHeader implements CommandCustomHeader { + + /** + * 生产者组 + */ @CFNotNull private String producerGroup; + /** + * ConsumeQueue Offset + */ @CFNotNull private Long tranStateTableOffset; + /** + * 消息所在CommitLog偏移量 + */ @CFNotNull private Long commitLogOffset; + /** + * 事务状态 + */ @CFNotNull private Integer commitOrRollback; // TRANSACTION_COMMIT_TYPE // TRANSACTION_ROLLBACK_TYPE // TRANSACTION_NOT_TYPE + /** + * Broker是否发起的回查 + */ @CFNullable private Boolean fromTransactionCheck = false; - + /** + * 消息ID + */ @CFNotNull private String msgId; - + /** + * 事务ID + */ private String transactionId; @Override diff --git a/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java b/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java index 7023d90708a..990fbf13e22 100644 --- a/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java +++ b/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java @@ -59,7 +59,19 @@ public static void main(String[] args) throws InterruptedException, MQClientExce */ consumer.subscribe("TopicTest", "*"); - consumer.registerMessageListener(); + /* + * Register callback to execute on arrival of messages fetched from brokers. + */ + consumer.registerMessageListener(new MessageListenerConcurrently() { + + @Override + public ConsumeConcurrentlyStatus consumeMessage(List msgs, + ConsumeConcurrentlyContext context) { + System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs); + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + }); + /* * Register callback to execute on arrival of messages fetched from brokers. From 4c4f5ebaddc690825ba421babf08c1468051e9ef Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Thu, 9 Nov 2023 19:06:16 +0800 Subject: [PATCH 11/18] =?UTF-8?q?=E5=AE=8C=E5=96=84RocketMQ=E4=B8=BB?= =?UTF-8?q?=E4=BB=8E=E5=90=8C=E6=AD=A5=E4=BB=A3=E7=A0=81=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 +- .../rocketmq/broker/BrokerController.java | 6 + .../org/apache/rocketmq/store/CommitLog.java | 3 + .../rocketmq/store/DefaultMessageStore.java | 2 +- .../rocketmq/store/ha/HAConnection.java | 104 ++++++++++++++- .../apache/rocketmq/store/ha/HAService.java | 123 +++++++++++++++++- 6 files changed, 237 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b8100d77d59..6dcbf7ee6b4 100644 --- a/README.md +++ b/README.md @@ -32,4 +32,9 @@ - 消息过滤代码入口:org.apache.rocketmq.store.DefaultMessageStore.getMessage、org.apache.rocketmq.broker.filter.ExpressionMessageFilter - 顺序消息消费代码入口:org.apache.rocketmq.client.impl.consumer.ConsumeMessageOrderlyService -> 参考文章:[RocketMQ源码分析](https://github.com/bigcoder84/study-notes/blob/master/%E5%88%86%E5%B8%83%E5%BC%8F%E4%B8%8E%E5%BE%AE%E6%9C%8D%E5%8A%A1/MessageQueue/RocketMQ/index.md) \ No newline at end of file +> 参考文章:[RocketMQ源码分析](https://github.com/bigcoder84/study-notes/blob/master/%E5%88%86%E5%B8%83%E5%BC%8F%E4%B8%8E%E5%BE%AE%E6%9C%8D%E5%8A%A1/MessageQueue/RocketMQ/index.md) + +## 高可用 + +- broker主从同步启动入口:org.apache.rocketmq.store.ha.HAService.start + - 主服务器监听从服务器连接实现类:org.apache.rocketmq.store.ha.HAService.AcceptSocketService \ No newline at end of file diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java index c4a326f04a3..dc1eb01702c 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java @@ -420,9 +420,13 @@ public void run() { if (!messageStoreConfig.isEnableDLegerCommitLog()) { if (BrokerRole.SLAVE == this.messageStoreConfig.getBrokerRole()) { if (this.messageStoreConfig.getHaMasterAddress() != null && this.messageStoreConfig.getHaMasterAddress().length() >= 6) { + // 如果Broker角色为从服务器,则读取Broker 配置文件中的haMasterAddress属性并更新HAClient的 + // masterAddrees,如果角色为从服务器,但haMasterAddress为空,启动Broker并不会报错,但不会执行主从同步复制 this.messageStore.updateHaMasterAddress(this.messageStoreConfig.getHaMasterAddress()); this.updateMasterHAServerAddrPeriodically = false; } else { + // 如果slave broker配置文件中没有配置master broker地址,则salve broker向NameServer发送心跳时 + // NameServer会返回当前brokerName对应的主节点地址,这样就可以自动获取到主节点地址了,而不需要手动配置主节点的地址 this.updateMasterHAServerAddrPeriodically = true; } } else { @@ -978,6 +982,8 @@ private void doRegisterBrokerAll(boolean checkOrderConfig, boolean oneway, RegisterBrokerResult registerBrokerResult = registerBrokerResultList.get(0); if (registerBrokerResult != null) { if (this.updateMasterHAServerAddrPeriodically && registerBrokerResult.getHaServerAddr() != null) { + // 如果broker在启动时未指定master broker地址,则会在每次向NameServer发送线条是, + // 用NameServer返回的master broker地址更新主节点地址用于主从复制 this.messageStore.updateHaMasterAddress(registerBrokerResult.getHaServerAddr()); } diff --git a/store/src/main/java/org/apache/rocketmq/store/CommitLog.java b/store/src/main/java/org/apache/rocketmq/store/CommitLog.java index d624a3cad44..cf4f2d3675c 100644 --- a/store/src/main/java/org/apache/rocketmq/store/CommitLog.java +++ b/store/src/main/java/org/apache/rocketmq/store/CommitLog.java @@ -758,14 +758,17 @@ public void handleDiskFlush(AppendMessageResult result, PutMessageResult putMess } public void handleHA(AppendMessageResult result, PutMessageResult putMessageResult, MessageExt messageExt) { + // 判断是否是同步复制到从节点 if (BrokerRole.SYNC_MASTER == this.defaultMessageStore.getMessageStoreConfig().getBrokerRole()) { HAService service = this.defaultMessageStore.getHaService(); if (messageExt.isWaitStoreMsgOK()) { // Determine whether to wait if (service.isSlaveOK(result.getWroteOffset() + result.getWroteBytes())) { + // 提交主从同步任务 GroupCommitRequest request = new GroupCommitRequest(result.getWroteOffset() + result.getWroteBytes()); service.putRequest(request); service.getWaitNotifyObject().wakeupAll(); + // 等待同步复制任务完成,异步同步线程复制完毕后会唤醒当前线程,超时时间默认为5s,如果超时则返回刷盘错误,刷盘成功后正常返回给调用方。 boolean flushOK = request.waitForFlush(this.defaultMessageStore.getMessageStoreConfig().getSyncFlushTimeout()); if (!flushOK) { diff --git a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java index 4f59b16c0ac..42a4b228cfa 100644 --- a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java +++ b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java @@ -114,7 +114,7 @@ public class DefaultMessageStore implements MessageStore { private final ReputMessageService reputMessageService; /** - * 存储高可用机制 + * 主从同步机制实现类 */ private final HAService haService; diff --git a/store/src/main/java/org/apache/rocketmq/store/ha/HAConnection.java b/store/src/main/java/org/apache/rocketmq/store/ha/HAConnection.java index 11af1e2feb0..1eb437aeb5b 100644 --- a/store/src/main/java/org/apache/rocketmq/store/ha/HAConnection.java +++ b/store/src/main/java/org/apache/rocketmq/store/ha/HAConnection.java @@ -28,15 +28,35 @@ import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.store.SelectMappedBufferResult; +/** + * 主服务端 HA 连接对象的封装,当主服务器接收到从服务器发过来的消息后,会封装成一个 HAConnection 对象,其中里面又封装了读 Socket 连接实现与 写 Socket 连接实现: + */ public class HAConnection { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.STORE_LOGGER_NAME); private final HAService haService; + /** + * 网络socket通道 + */ private final SocketChannel socketChannel; + /** + * 客户端连接地址 + */ private final String clientAddr; + /** + * 服务端向从服务器写数据服务类 + */ private WriteSocketService writeSocketService; + /** + * 服务端从从服务器读数据服务类 + */ private ReadSocketService readSocketService; - + /** + * 从服务器请求拉取消息的偏移量。 + */ private volatile long slaveRequestOffset = -1; + /** + * 从服务器反馈已拉取完成的消息偏移量 + */ private volatile long slaveAckOffset = -1; public HAConnection(final HAService haService, final SocketChannel socketChannel) throws IOException { @@ -78,12 +98,34 @@ public SocketChannel getSocketChannel() { return socketChannel; } + /** + * 主服务器读取从服务器上报的本地同步进度的实现类 + */ class ReadSocketService extends ServiceThread { + + /** + * 网络读缓存区大小,默认为1MB + */ private static final int READ_MAX_BUFFER_SIZE = 1024 * 1024; + /** + * NIO网络事件选择器 + */ private final Selector selector; + /** + * 网络通道 + */ private final SocketChannel socketChannel; + /** + * 网络读写缓存区,默认为1MB。 + */ private final ByteBuffer byteBufferRead = ByteBuffer.allocate(READ_MAX_BUFFER_SIZE); + /** + * byteBuffer当前处理指针。 + */ private int processPosition = 0; + /** + * 从服务器最后一次上报时间 + */ private volatile long lastReadTimestamp = System.currentTimeMillis(); public ReadSocketService(final SocketChannel socketChannel) throws IOException { @@ -99,6 +141,7 @@ public void run() { while (!this.isStopped()) { try { + // 每隔1s处理一次读就绪事件 this.selector.select(1000); boolean ok = this.processReadEvent(); if (!ok) { @@ -148,35 +191,50 @@ public String getServiceName() { private boolean processReadEvent() { int readSizeZeroTimes = 0; + // 如果byteBufferRead没有剩余空间,说明该 + //position==limit==capacity,调用byteBufferRead.flip()方法,产 + //生的效果为position=0、limit=capacity并设置processPostion为0, + //表示从头开始处理,其实这里调用byteBuffer.clear()方法会更加容 + //易理解 if (!this.byteBufferRead.hasRemaining()) { this.byteBufferRead.flip(); this.processPosition = 0; } + // NIO网络读的常规方法,一般使用循环的方式进行读写, + //直到byteBuffer中没有剩余的空间 while (this.byteBufferRead.hasRemaining()) { try { + // 从SocketChannel中读取数据到缓冲区 int readSize = this.socketChannel.read(this.byteBufferRead); if (readSize > 0) { readSizeZeroTimes = 0; this.lastReadTimestamp = HAConnection.this.haService.getDefaultMessageStore().getSystemClock().now(); if ((this.byteBufferRead.position() - this.processPosition) >= 8) { int pos = this.byteBufferRead.position() - (this.byteBufferRead.position() % 8); + // 如果读取的字节大于0并且本次读取到的内容大于等于 + //8,表明收到了从服务器一条拉取消息的请求。由于有新的从服务器反 + //馈拉取偏移量 long readOffset = this.byteBufferRead.getLong(pos - 8); this.processPosition = pos; + // 同步从服务器偏移量 HAConnection.this.slaveAckOffset = readOffset; if (HAConnection.this.slaveRequestOffset < 0) { HAConnection.this.slaveRequestOffset = readOffset; log.info("slave[" + HAConnection.this.clientAddr + "] request offset " + readOffset); } + // 通知由于同步等待主从复制结果而阻塞的消息发送者线程 HAConnection.this.haService.notifyTransferSome(HAConnection.this.slaveAckOffset); } } else if (readSize == 0) { + // 如果读取到的字节数等于0,则重复执行三次读请求,否则结束本次读请求处理。 if (++readSizeZeroTimes >= 3) { break; } } else { + // 如果读取到的字节数小于0,表示连接处于半关闭状态,返回false,意味着消息服务器将关闭该链接 log.error("read socket[" + HAConnection.this.clientAddr + "] < 0"); return false; } @@ -190,15 +248,41 @@ private boolean processReadEvent() { } } + /** + * 主服务器写实现类 + */ class WriteSocketService extends ServiceThread { + + /** + * NIO网络事件选择器 + */ private final Selector selector; + /** + * 网络socket通道 + */ private final SocketChannel socketChannel; + /** + * 消息头长度,即消息物理偏移量+消息长度 + */ private final int headerSize = 8 + 4; + private final ByteBuffer byteBufferHeader = ByteBuffer.allocate(headerSize); + /** + * 下一次传输的物理偏移量 + */ private long nextTransferFromWhere = -1; + /** + * 根据偏移量查找消息的结果 + */ private SelectMappedBufferResult selectMappedBufferResult; + /** + * 上一次数据是否传输完毕 + */ private boolean lastWriteOver = true; + /** + * 上次写入消息的时间戳 + */ private long lastWriteTimestamp = System.currentTimeMillis(); public WriteSocketService(final SocketChannel socketChannel) throws IOException { @@ -216,11 +300,17 @@ public void run() { try { this.selector.select(1000); + // 如果slaveRequestOffset等于-1,说明主服务器还未收到从服务器的拉取请求,则放弃本次事件处理。 + // slaveRequestOffset在收到从服务器拉取请求时更新。 if (-1 == HAConnection.this.slaveRequestOffset) { Thread.sleep(10); continue; } + // 如果nextTransferFromWhere为-1,表示初次进行数据传 + // 输,计算待传输的物理偏移量,如果slaveRequestOffset为0,则从当 + // 前CommitLog文件最大偏移量开始传输,否则根据从服务器的拉取请求 + // 偏移量开始传输 if (-1 == this.nextTransferFromWhere) { if (0 == HAConnection.this.slaveRequestOffset) { long masterOffset = HAConnection.this.haService.getDefaultMessageStore().getCommitLog().getMaxOffset(); @@ -242,11 +332,15 @@ public void run() { + "], and slave request " + HAConnection.this.slaveRequestOffset); } + // 判断上次写事件是否已将信息全部写入客户端 if (this.lastWriteOver) { long interval = HAConnection.this.haService.getDefaultMessageStore().getSystemClock().now() - this.lastWriteTimestamp; + // 如果已全部写入,且当前系统时间与上次最后写入的时间间隔大于高可用心跳检测时间,则发送一个心跳包,心跳包的长度为12个 + //字节(从服务器待拉取偏移量+size),消息长度默认为0,避免长连接由于空闲被关闭。高可用心跳包发送间隔通过haSendHeartbeatInterval设置, + // 默认值为5s if (interval > HAConnection.this.haService.getDefaultMessageStore().getMessageStoreConfig() .getHaSendHeartbeatInterval()) { @@ -262,14 +356,18 @@ public void run() { continue; } } else { + // 如果上次数据未写完,则先传输上一次的数据,如果消息还是未全部传输,则结束此次事件处理 this.lastWriteOver = this.transferData(); if (!this.lastWriteOver) continue; } - + // 根据消息从服务器请求的待拉取消息偏移量,查找该偏移量之后所有的可读消息 SelectMappedBufferResult selectResult = HAConnection.this.haService.getDefaultMessageStore().getCommitLogData(this.nextTransferFromWhere); if (selectResult != null) { + // 如果匹配到消息,且查找到的消息总长度大于配置高可用传输一次同步任务的最大传输字节数,则通过设置ByteBuffer的limit来控 + // 制只传输指定长度的字节,这就意味着高可用客户端收到的消息会包含不完整的消息。高可用一批次传输消息最大字节通过 + // haTransferBatchSize设置,默认值为32KB int size = selectResult.getSize(); if (size > HAConnection.this.haService.getDefaultMessageStore().getMessageStoreConfig().getHaTransferBatchSize()) { size = HAConnection.this.haService.getDefaultMessageStore().getMessageStoreConfig().getHaTransferBatchSize(); @@ -290,7 +388,7 @@ public void run() { this.lastWriteOver = this.transferData(); } else { - + // 如果未查到匹配的消息,通知所有等待线程继续等待100ms。 HAConnection.this.haService.getWaitNotifyObject().allWaitForRunning(100); } } catch (Exception e) { diff --git a/store/src/main/java/org/apache/rocketmq/store/ha/HAService.java b/store/src/main/java/org/apache/rocketmq/store/ha/HAService.java index 3035c575cf1..c865fe38484 100644 --- a/store/src/main/java/org/apache/rocketmq/store/ha/HAService.java +++ b/store/src/main/java/org/apache/rocketmq/store/ha/HAService.java @@ -40,6 +40,9 @@ import org.apache.rocketmq.store.CommitLog; import org.apache.rocketmq.store.DefaultMessageStore; +/** + * RocketMQ主从同步核心实现类 + */ public class HAService { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.STORE_LOGGER_NAME); @@ -87,6 +90,7 @@ public boolean isSlaveOK(final long masterPutWhere) { public void notifyTransferSome(final long offset) { for (long value = this.push2SlaveMaxOffset.get(); offset > value; ) { + // 如果从服务器上报的复制进度大于 本地记录的最大进度,则更新该字段 boolean ok = this.push2SlaveMaxOffset.compareAndSet(value, offset); if (ok) { this.groupTransferService.notifyTransferSome(); @@ -154,11 +158,22 @@ public AtomicLong getPush2SlaveMaxOffset() { } /** + * 高可用主服务器监听从服务器连接实现类 * Listens to slave connections to create {@link HAConnection}. */ class AcceptSocketService extends ServiceThread { + + /** + * Broker服务监听套接字(本地IP+端口号) + */ private final SocketAddress socketAddressListen; + /** + * 服务端Socket通道,基于NIO + */ private ServerSocketChannel serverSocketChannel; + /** + * 事件选择器 基于NIO + */ private Selector selector; public AcceptSocketService(final int port) { @@ -166,6 +181,9 @@ public AcceptSocketService(final int port) { } /** + * 创建ServerSocketChannel和Selector、设置TCP reuseAddress、 + * 绑定监听端口、设置为非阻塞模式,并注册OP_ACCEPT(连接事件) + * * Starts listening to slave connections. * * @throws Exception If fails. @@ -174,8 +192,11 @@ public void beginAccept() throws Exception { this.serverSocketChannel = ServerSocketChannel.open(); this.selector = RemotingUtil.openSelector(); this.serverSocketChannel.socket().setReuseAddress(true); + // 监听端口 this.serverSocketChannel.socket().bind(this.socketAddressListen); + // 设置为非阻塞模式 this.serverSocketChannel.configureBlocking(false); + // 注册连接事件 this.serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT); } @@ -202,12 +223,15 @@ public void run() { while (!this.isStopped()) { try { + // 在一秒钟时间,尝试获取事件 this.selector.select(1000); + // 获取这一段时间发生的事件 Set selected = this.selector.selectedKeys(); if (selected != null) { for (SelectionKey k : selected) { if ((k.readyOps() & SelectionKey.OP_ACCEPT) != 0) { + // 调用accept方法执行连接,并生成与客户端通信的SocketChannel SocketChannel sc = ((ServerSocketChannel) k.channel()).accept(); if (sc != null) { @@ -215,7 +239,9 @@ public void run() { + sc.socket().getRemoteSocketAddress()); try { + // 为连接对象创建 HAConnection,该HAConnection将负责主从数据同步逻辑 HAConnection conn = new HAConnection(HAService.this, sc); + // 启动HAConnection conn.start(); HAService.this.addConnection(conn); } catch (Exception e) { @@ -248,6 +274,19 @@ public String getServiceName() { } /** + * 主从同步通知类,实现同步复制和异步复制的功能 + * + * GroupTransferService负责在主从同步复制结束后,通知由于等 + * 待同步结果而阻塞的消息发送者线程。 + * + * 判断主从同步是否完成的依据 + * 是从服务器中已成功复制的消息最大偏移量是否大于、等于消息生产 + * 者发送消息后消息服务端返回下一条消息的起始偏移量,如果是则表 + * 示主从同步复制已经完成,唤醒消息发送线程,否则等待1s再次判 + * 断,每一个任务在一批任务中循环判断5次。消息发送者返回有两种情 + * 况:等待超过5s或GroupTransferService通知主从复制完成。可以通 + * 过syncFlushTimeout来设置发送线程的等待超时时间。 + * * GroupTransferService Service */ class GroupTransferService extends ServiceThread { @@ -279,7 +318,10 @@ private void doWaitTransfer() { synchronized (this.requestsRead) { if (!this.requestsRead.isEmpty()) { for (CommitLog.GroupCommitRequest req : this.requestsRead) { + // 判断主从同步是否完成的依据是从服务器中已成功复制的消息最大偏移量是否大于、等于消息生产 + //者发送消息后消息服务端返回下一条消息的起始偏移量 boolean transferOK = HAService.this.push2SlaveMaxOffset.get() >= req.getNextOffset(); + // 默认同步有5s的超时时间 long waitUntilWhen = HAService.this.defaultMessageStore.getSystemClock().now() + HAService.this.defaultMessageStore.getMessageStoreConfig().getSyncFlushTimeout(); while (!transferOK && HAService.this.defaultMessageStore.getSystemClock().now() < waitUntilWhen) { @@ -290,7 +332,7 @@ private void doWaitTransfer() { if (!transferOK) { log.warn("transfer messsage to slave timeout, " + req.getNextOffset()); } - + // 同步完成,唤醒消息发送处理线程 req.wakeupCustomer(transferOK); } @@ -304,6 +346,7 @@ public void run() { while (!this.isStopped()) { try { + // 每10ms执行一次 this.waitForRunning(10); this.doWaitTransfer(); } catch (Exception e) { @@ -325,17 +368,51 @@ public String getServiceName() { } } + /** + * 从服务器连接主服务实现类 + */ class HAClient extends ServiceThread { private static final int READ_MAX_BUFFER_SIZE = 1024 * 1024 * 4; + /** + * 主服务器地址 + * + * 如果Broker角色为从服务器,则在broker启动时读取Broker + * 配置文件中的haMasterAddress属性并更新HAClient的 + * masterAddrees,如果角色为从服务器,但haMasterAddress为空,启 + * 动Broker并不会报错,但不会执行主从同步复制 + */ private final AtomicReference masterAddress = new AtomicReference<>(); + /** + * 从服务器向主服务器发起主从同步的拉取偏移量 + */ private final ByteBuffer reportOffset = ByteBuffer.allocate(8); + /** + * 网络传输通道 + */ private SocketChannel socketChannel; + /** + * NIO事件选择器 + */ private Selector selector; + /** + * 上一次写入消息的时间戳 + */ private long lastWriteTimestamp = System.currentTimeMillis(); - + /** + * 反馈从服务器当前的复制进度,即CommitLog文件的最大偏移量。 + */ private long currentReportedOffset = 0; + /** + * 本次已处理读缓存区的指针。 + */ private int dispatchPosition = 0; + /** + * 读缓存区,大小为4MB + */ private ByteBuffer byteBufferRead = ByteBuffer.allocate(READ_MAX_BUFFER_SIZE); + /** + * 读缓存区备份,与BufferRead进行交换。 + */ private ByteBuffer byteBufferBackup = ByteBuffer.allocate(READ_MAX_BUFFER_SIZE); public HAClient() throws IOException { @@ -350,6 +427,12 @@ public void updateMasterAddress(final String newAddr) { } } + /** + * 判断是否需要向主服务器反馈当前待拉取消息的偏移 + * 量,主服务器与从服务器的高可用心跳发送时间间隔默认为5s,可通 + * 过配置haSendHeartbeatInterval来改变间隔时间 + * @return + */ private boolean isTimeToReportOffset() { long interval = HAService.this.defaultMessageStore.getSystemClock().now() - this.lastWriteTimestamp; @@ -359,6 +442,15 @@ private boolean isTimeToReportOffset() { return needHeart; } + /** + * 向主服务器反馈拉取消息偏移量。这里有两重含义,对 + * 于从服务器来说,是发送下次待拉取消息的偏移量,而对于主服务器 + * 来说,既可以认为是从服务器本次请求拉取的消息偏移量,也可以理 + * 解为从服务器的消息同步ACK确认消息 + * + * @param maxOffset + * @return + */ private boolean reportSlaveMaxOffset(final long maxOffset) { this.reportOffset.position(0); this.reportOffset.limit(8); @@ -368,6 +460,10 @@ private boolean reportSlaveMaxOffset(final long maxOffset) { for (int i = 0; i < 3 && this.reportOffset.hasRemaining(); i++) { try { + // 调用网络通道的write() + //方法是在一个for循环中反复判断byteBuffer是否全部写入通道中, + //这是由于NIO是一个非阻塞I/O,调用一次write()方法不一定能将 + //ByteBuffer可读字节全部写入 this.socketChannel.write(this.reportOffset); } catch (IOException e) { log.error(this.getServiceName() @@ -403,19 +499,30 @@ private void swapByteBuffer() { this.byteBufferBackup = tmp; } + /** + * 处理网络读请求,即处理从主服务器传回的消息数据,将读取到的消息全部追加到消息内存映射文件中 + * @return + */ private boolean processReadEvent() { int readSizeZeroTimes = 0; + // 循环判断readByteBuffer是否还有剩余空间,如果存在剩余空间,则调用 + // SocketChannel#read(ByteBuffer readByteBuffer)方法,将通道中 + // 的数据读入读缓存区。 while (this.byteBufferRead.hasRemaining()) { try { + // 读取通道中的数据到缓冲区,并返回读取到的字节数 int readSize = this.socketChannel.read(this.byteBufferRead); if (readSize > 0) { + // 如果读取到的字节数大于0,则重置读取到0字节的次数 readSizeZeroTimes = 0; + // 然后调用dispatchReadRequest方法将读取到的所有消息全部追加到消息内存映射文件中,再次反馈拉取进度给主服务器。 boolean result = this.dispatchReadRequest(); if (!result) { log.error("HAClient, dispatchReadRequest error"); return false; } } else if (readSize == 0) { + // 如果连续3次从网络通道读取到0个字节,则结束本次读任务 if (++readSizeZeroTimes >= 3) { break; } @@ -457,6 +564,7 @@ private boolean dispatchReadRequest() { this.byteBufferRead.position(this.dispatchPosition + msgHeaderSize); this.byteBufferRead.get(bodyData); + // 将读取到的消息,写入CommitLog中 HAService.this.defaultMessageStore.appendToCommitLog(masterPhyOffset, bodyData); this.byteBufferRead.position(readSocketPos); @@ -496,24 +604,29 @@ private boolean reportSlaveMaxOffsetPlus() { } private boolean connectMaster() throws ClosedChannelException { + // 如果socketChannel为空,则尝试连接主服务器 if (null == socketChannel) { String addr = this.masterAddress.get(); if (addr != null) { - SocketAddress socketAddress = RemotingUtil.string2SocketAddress(addr); if (socketAddress != null) { + // 则建立到主服务器的TCP连接 this.socketChannel = RemotingUtil.connect(socketAddress); if (this.socketChannel != null) { + // 注册OP_READ(网络读事件) this.socketChannel.register(this.selector, SelectionKey.OP_READ); } } } + // 从节点本地的CommitLog最大偏移量 this.currentReportedOffset = HAService.this.defaultMessageStore.getMaxPhyOffset(); + // 记录当前时间为最后写入时间 this.lastWriteTimestamp = System.currentTimeMillis(); } + // 如果主服务器地址为空,返回false return this.socketChannel != null; } @@ -550,17 +663,21 @@ public void run() { while (!this.isStopped()) { try { + // 主动连接主服务器,获取socketChannel对象 if (this.connectMaster()) { if (this.isTimeToReportOffset()) { + // 上报本地节点偏移量到主服务器 boolean result = this.reportSlaveMaxOffset(this.currentReportedOffset); if (!result) { this.closeMaster(); } } + // 进行事件选择,执行间隔时间为1s。 this.selector.select(1000); + // 处理网络读请求,即处理从主服务器传回的消息数据。 boolean ok = this.processReadEvent(); if (!ok) { this.closeMaster(); From b604b69cfb30ce1f075e1e58028fd7a9f0e72731 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sun, 12 Nov 2023 15:51:44 +0800 Subject: [PATCH 12/18] =?UTF-8?q?'=E5=AE=8C=E5=96=84RocketMQ=E4=B8=BB?= =?UTF-8?q?=E4=BB=8E=E5=90=8C=E6=AD=A5=E4=BB=A3=E7=A0=81=E6=B3=A8=E9=87=8A?= =?UTF-8?q?'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/rocketmq/store/CommitLog.java | 5 ++ .../rocketmq/store/DefaultMessageStore.java | 4 ++ .../rocketmq/store/ha/HAConnection.java | 28 +++++---- .../apache/rocketmq/store/ha/HAService.java | 60 ++++++++++++++----- 4 files changed, 69 insertions(+), 28 deletions(-) diff --git a/store/src/main/java/org/apache/rocketmq/store/CommitLog.java b/store/src/main/java/org/apache/rocketmq/store/CommitLog.java index cf4f2d3675c..c556be8ef02 100644 --- a/store/src/main/java/org/apache/rocketmq/store/CommitLog.java +++ b/store/src/main/java/org/apache/rocketmq/store/CommitLog.java @@ -761,17 +761,22 @@ public void handleHA(AppendMessageResult result, PutMessageResult putMessageResu // 判断是否是同步复制到从节点 if (BrokerRole.SYNC_MASTER == this.defaultMessageStore.getMessageStoreConfig().getBrokerRole()) { HAService service = this.defaultMessageStore.getHaService(); + // 如果是同步复制,也可以在发送消息时手动设置不等待同步成功就返回,这样增加了同步复制场景下的灵活性。在小部分不需要的同步复制, + // 但是RocketMQ又配置为主从同步复制的场景下,也使得消息异步复制 if (messageExt.isWaitStoreMsgOK()) { // Determine whether to wait if (service.isSlaveOK(result.getWroteOffset() + result.getWroteBytes())) { // 提交主从同步任务 GroupCommitRequest request = new GroupCommitRequest(result.getWroteOffset() + result.getWroteBytes()); + // 添加请求 service.putRequest(request); + // 唤醒GroupTransferService中在等待的线程 service.getWaitNotifyObject().wakeupAll(); // 等待同步复制任务完成,异步同步线程复制完毕后会唤醒当前线程,超时时间默认为5s,如果超时则返回刷盘错误,刷盘成功后正常返回给调用方。 boolean flushOK = request.waitForFlush(this.defaultMessageStore.getMessageStoreConfig().getSyncFlushTimeout()); if (!flushOK) { + // 达到超时时间不再继续等待消息同步,返回错误码 log.error("do sync transfer other node, wait return, but failed, topic: " + messageExt.getTopic() + " tags: " + messageExt.getTags() + " client address: " + messageExt.getBornHostNameString()); putMessageResult.setPutMessageStatus(PutMessageStatus.FLUSH_SLAVE_TIMEOUT); diff --git a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java index 42a4b228cfa..9d51afa8433 100644 --- a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java +++ b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java @@ -331,7 +331,10 @@ public void start() throws Exception { } if (!messageStoreConfig.isEnableDLegerCommitLog()) { + // 启动主从同步 this.haService.start(); + // 主节点启动延迟消息实现,从节点关闭Slave消息实现,主节点将延迟消息从延迟队列转移到真实的topic队列时,也会由主从同步同步至从节点, + // 所以不需要从节点开启延迟队列 this.handleScheduleMessageService(messageStoreConfig.getBrokerRole()); } @@ -1591,6 +1594,7 @@ public BrokerStatsManager getBrokerStatsManager() { public void handleScheduleMessageService(final BrokerRole brokerRole) { if (this.scheduleMessageService != null) { if (brokerRole == BrokerRole.SLAVE) { + // 如果是从节点,则关闭定时消息扫描线程 this.scheduleMessageService.shutdown(); } else { this.scheduleMessageService.start(); diff --git a/store/src/main/java/org/apache/rocketmq/store/ha/HAConnection.java b/store/src/main/java/org/apache/rocketmq/store/ha/HAConnection.java index 1eb437aeb5b..f2667e73ca9 100644 --- a/store/src/main/java/org/apache/rocketmq/store/ha/HAConnection.java +++ b/store/src/main/java/org/apache/rocketmq/store/ha/HAConnection.java @@ -116,7 +116,7 @@ class ReadSocketService extends ServiceThread { */ private final SocketChannel socketChannel; /** - * 网络读写缓存区,默认为1MB。 + * 网络读缓存区,默认为1MB。 */ private final ByteBuffer byteBufferRead = ByteBuffer.allocate(READ_MAX_BUFFER_SIZE); /** @@ -201,31 +201,35 @@ private boolean processReadEvent() { this.processPosition = 0; } - // NIO网络读的常规方法,一般使用循环的方式进行读写, - //直到byteBuffer中没有剩余的空间 + // NIO网络读的常规方法,一般使用循环的方式进行读写,直到byteBuffer中没有剩余的空间 while (this.byteBufferRead.hasRemaining()) { try { - // 从SocketChannel中读取数据到缓冲区 + // 从socketChannel读取数据到byteBufferRead中,返回读取到的字节数 int readSize = this.socketChannel.read(this.byteBufferRead); if (readSize > 0) { + // 重置readSizeZeroTimes readSizeZeroTimes = 0; + // 获取上次处理读事件的时间戳 this.lastReadTimestamp = HAConnection.this.haService.getDefaultMessageStore().getSystemClock().now(); + // 判断剩余可读取的字节数是否大于等于8 if ((this.byteBufferRead.position() - this.processPosition) >= 8) { + // 获取偏移量内容的结束位置 int pos = this.byteBufferRead.position() - (this.byteBufferRead.position() % 8); - // 如果读取的字节大于0并且本次读取到的内容大于等于 - //8,表明收到了从服务器一条拉取消息的请求。由于有新的从服务器反 - //馈拉取偏移量 + // 从结束位置向前读取8个字节得到从点发送的同步偏移量 long readOffset = this.byteBufferRead.getLong(pos - 8); + // 更新处理位置 this.processPosition = pos; - // 同步从服务器偏移量 + // 更新slaveAckOffset为从节点发送的同步进度 HAConnection.this.slaveAckOffset = readOffset; + // 如果记录的从节点的同步进度小于0,表示还未进行同步 if (HAConnection.this.slaveRequestOffset < 0) { + // 更新为从节点发送的同步进度 HAConnection.this.slaveRequestOffset = readOffset; log.info("slave[" + HAConnection.this.clientAddr + "] request offset " + readOffset); } - // 通知由于同步等待主从复制结果而阻塞的消息发送者线程 + // 通知由于同步等待主从复制结果而阻塞的消息发送者处理线程 HAConnection.this.haService.notifyTransferSome(HAConnection.this.slaveAckOffset); } } else if (readSize == 0) { @@ -307,10 +311,8 @@ public void run() { continue; } - // 如果nextTransferFromWhere为-1,表示初次进行数据传 - // 输,计算待传输的物理偏移量,如果slaveRequestOffset为0,则从当 - // 前CommitLog文件最大偏移量开始传输,否则根据从服务器的拉取请求 - // 偏移量开始传输 + // 如果nextTransferFromWhere为-1,表示初次进行数据传输,计算待传输的物理偏移量,如果slaveRequestOffset为0,则从当 + // 前CommitLog文件最大偏移量开始传输,否则根据从服务器的拉取请求偏移量开始传输 if (-1 == this.nextTransferFromWhere) { if (0 == HAConnection.this.slaveRequestOffset) { long masterOffset = HAConnection.this.haService.getDefaultMessageStore().getCommitLog().getMaxOffset(); diff --git a/store/src/main/java/org/apache/rocketmq/store/ha/HAService.java b/store/src/main/java/org/apache/rocketmq/store/ha/HAService.java index c865fe38484..d322319b437 100644 --- a/store/src/main/java/org/apache/rocketmq/store/ha/HAService.java +++ b/store/src/main/java/org/apache/rocketmq/store/ha/HAService.java @@ -50,13 +50,22 @@ public class HAService { private final List connectionList = new LinkedList<>(); + /** + * 主从同步 主服务器监听从服务器连接实现类 + */ private final AcceptSocketService acceptSocketService; private final DefaultMessageStore defaultMessageStore; private final WaitNotifyObject waitNotifyObject = new WaitNotifyObject(); + /** + * 传输到从节点最大偏移量 + */ private final AtomicLong push2SlaveMaxOffset = new AtomicLong(0); + /** + * 主从同步通知类,实现同步复制和异步复制的功能 + */ private final GroupTransferService groupTransferService; private final HAClient haClient; @@ -89,8 +98,9 @@ public boolean isSlaveOK(final long masterPutWhere) { } public void notifyTransferSome(final long offset) { + // 如果传入的偏移大于push2SlaveMaxOffset记录的值,进行更新 for (long value = this.push2SlaveMaxOffset.get(); offset > value; ) { - // 如果从服务器上报的复制进度大于 本地记录的最大进度,则更新该字段 + // 更新向从节点推送的消息最大偏移量 boolean ok = this.push2SlaveMaxOffset.compareAndSet(value, offset); if (ok) { this.groupTransferService.notifyTransferSome(); @@ -158,7 +168,7 @@ public AtomicLong getPush2SlaveMaxOffset() { } /** - * 高可用主服务器监听从服务器连接实现类 + * 主从同步 主服务器监听从服务器连接实现类 * Listens to slave connections to create {@link HAConnection}. */ class AcceptSocketService extends ServiceThread { @@ -189,14 +199,16 @@ public AcceptSocketService(final int port) { * @throws Exception If fails. */ public void beginAccept() throws Exception { + // 创建ServerSocketChannel this.serverSocketChannel = ServerSocketChannel.open(); + // 获取selector this.selector = RemotingUtil.openSelector(); this.serverSocketChannel.socket().setReuseAddress(true); // 监听端口 this.serverSocketChannel.socket().bind(this.socketAddressListen); // 设置为非阻塞模式 this.serverSocketChannel.configureBlocking(false); - // 注册连接事件 + // 注册 OP_ACCEPT (客户端连接)事件 this.serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT); } @@ -318,14 +330,16 @@ private void doWaitTransfer() { synchronized (this.requestsRead) { if (!this.requestsRead.isEmpty()) { for (CommitLog.GroupCommitRequest req : this.requestsRead) { - // 判断主从同步是否完成的依据是从服务器中已成功复制的消息最大偏移量是否大于、等于消息生产 - //者发送消息后消息服务端返回下一条消息的起始偏移量 + // 判断主从同步是否完成,判断传输到从节点最大偏移量是否超过了请求中设置的偏移量 boolean transferOK = HAService.this.push2SlaveMaxOffset.get() >= req.getNextOffset(); // 默认同步有5s的超时时间 long waitUntilWhen = HAService.this.defaultMessageStore.getSystemClock().now() + HAService.this.defaultMessageStore.getMessageStoreConfig().getSyncFlushTimeout(); + // 如果从节点还未同步完毕并且未超过截止时间 while (!transferOK && HAService.this.defaultMessageStore.getSystemClock().now() < waitUntilWhen) { + // 等待 this.notifyTransferObject.waitForRunning(1000); + // 判断从节点同步的最大偏移量是否超过了请求中设置的偏移量 transferOK = HAService.this.push2SlaveMaxOffset.get() >= req.getNextOffset(); } @@ -395,7 +409,7 @@ class HAClient extends ServiceThread { */ private Selector selector; /** - * 上一次写入消息的时间戳 + * 更新上次心跳发送时间 */ private long lastWriteTimestamp = System.currentTimeMillis(); /** @@ -434,8 +448,10 @@ public void updateMasterAddress(final String newAddr) { * @return */ private boolean isTimeToReportOffset() { + // 获取距离上一次主从同步的间隔时间 long interval = HAService.this.defaultMessageStore.getSystemClock().now() - this.lastWriteTimestamp; + // 判断是否超过了配置的发送心跳包时间间隔 boolean needHeart = interval > HAService.this.defaultMessageStore.getMessageStoreConfig() .getHaSendHeartbeatInterval(); @@ -453,7 +469,9 @@ private boolean isTimeToReportOffset() { */ private boolean reportSlaveMaxOffset(final long maxOffset) { this.reportOffset.position(0); + // 设置数据传输大小为8个字节 this.reportOffset.limit(8); + // 设置同步偏移量 this.reportOffset.putLong(maxOffset); this.reportOffset.position(0); this.reportOffset.limit(8); @@ -472,6 +490,7 @@ private boolean reportSlaveMaxOffset(final long maxOffset) { } } + // 更新发送时间 lastWriteTimestamp = HAService.this.defaultMessageStore.getSystemClock().now(); return !this.reportOffset.hasRemaining(); } @@ -540,18 +559,25 @@ private boolean processReadEvent() { } private boolean dispatchReadRequest() { + // 消息头大小 final int msgHeaderSize = 8 + 4; // phyoffset + size int readSocketPos = this.byteBufferRead.position(); - + // 开启循环不断地读取数据 while (true) { + // 获可读取的字节数 int diff = this.byteBufferRead.position() - this.dispatchPosition; + // 如果字节数大于一个消息头的字节数 if (diff >= msgHeaderSize) { + // 获取消息在master节点的物理偏移量 long masterPhyOffset = this.byteBufferRead.getLong(this.dispatchPosition); + // 获取消息体大小 int bodySize = this.byteBufferRead.getInt(this.dispatchPosition + 8); + // 获取从节点当前CommitLog的最大物理偏移量 long slavePhyOffset = HAService.this.defaultMessageStore.getMaxPhyOffset(); if (slavePhyOffset != 0) { + // 如果不一致结束处理 if (slavePhyOffset != masterPhyOffset) { log.error("master pushed offset not equal the max phy offset in slave, SLAVE: " + slavePhyOffset + " MASTER: " + masterPhyOffset); @@ -559,15 +585,19 @@ private boolean dispatchReadRequest() { } } + // 如果可读取的字节数大于一个消息头的字节数 + 消息体大小 if (diff >= (msgHeaderSize + bodySize)) { + // 将度缓冲区的数据转为字节数组 byte[] bodyData = new byte[bodySize]; + // 计算消息体在读缓冲区中的起始位置 this.byteBufferRead.position(this.dispatchPosition + msgHeaderSize); this.byteBufferRead.get(bodyData); - // 将读取到的消息,写入CommitLog中 + // 从读缓冲区中根据消息的位置,读取消息内容,将消息追加到从节点的CommitLog中 HAService.this.defaultMessageStore.appendToCommitLog(masterPhyOffset, bodyData); this.byteBufferRead.position(readSocketPos); + // 更新dispatchPosition的值为消息头大小+消息体大小 this.dispatchPosition += msgHeaderSize + bodySize; if (!reportSlaveMaxOffsetPlus()) { @@ -608,9 +638,10 @@ private boolean connectMaster() throws ClosedChannelException { if (null == socketChannel) { String addr = this.masterAddress.get(); if (addr != null) { + // 将地址转为SocketAddress SocketAddress socketAddress = RemotingUtil.string2SocketAddress(addr); if (socketAddress != null) { - // 则建立到主服务器的TCP连接 + // 建立与Master的连接 this.socketChannel = RemotingUtil.connect(socketAddress); if (this.socketChannel != null) { // 注册OP_READ(网络读事件) @@ -619,10 +650,9 @@ private boolean connectMaster() throws ClosedChannelException { } } - // 从节点本地的CommitLog最大偏移量 + // 获取从节点本地的CommitLog最大偏移量 this.currentReportedOffset = HAService.this.defaultMessageStore.getMaxPhyOffset(); - - // 记录当前时间为最后写入时间 + // 更新上次写入时间 this.lastWriteTimestamp = System.currentTimeMillis(); } @@ -663,9 +693,9 @@ public void run() { while (!this.isStopped()) { try { - // 主动连接主服务器,获取socketChannel对象 + // 主动连接Master节点,获取socketChannel对象 if (this.connectMaster()) { - + // 是否需要报告消息同步偏移量 if (this.isTimeToReportOffset()) { // 上报本地节点偏移量到主服务器 boolean result = this.reportSlaveMaxOffset(this.currentReportedOffset); @@ -677,7 +707,7 @@ public void run() { // 进行事件选择,执行间隔时间为1s。 this.selector.select(1000); - // 处理网络读请求,即处理从主服务器传回的消息数据。 + // 处理读事件,即处理从主服务器传回的消息数据。 boolean ok = this.processReadEvent(); if (!ok) { this.closeMaster(); From 6679543054b61698e38a63d0fec0453daaaf8995 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Wed, 15 Nov 2023 19:16:58 +0800 Subject: [PATCH 13/18] =?UTF-8?q?RocketMQ=E6=B6=88=E6=81=AF=E8=BD=A8?= =?UTF-8?q?=E8=BF=B9=E4=BB=A3=E7=A0=81=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + .../consumer/DefaultMQPushConsumer.java | 1 + .../client/impl/factory/MQClientInstance.java | 7 +++ .../client/producer/DefaultMQProducer.java | 1 + .../client/trace/AsyncTraceDispatcher.java | 45 +++++++++++++++++++ .../rocketmq/client/trace/TraceBean.java | 23 ++++++++++ .../rocketmq/client/trace/TraceContext.java | 9 ++++ .../client/trace/TraceDispatcher.java | 1 + .../rocketmq/client/trace/TraceType.java | 9 ++++ .../hook/ConsumeMessageTraceHookImpl.java | 3 +- .../trace/hook/SendMessageTraceHookImpl.java | 14 ++++++ .../apache/rocketmq/common/BrokerConfig.java | 3 ++ .../rocketmq/store/DefaultMessageStore.java | 3 ++ 13 files changed, 119 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6dcbf7ee6b4..dee36ef52f2 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ - 定时消息代码入口:org.apache.rocketmq.store.schedule.ScheduleMessageService - 消息过滤代码入口:org.apache.rocketmq.store.DefaultMessageStore.getMessage、org.apache.rocketmq.broker.filter.ExpressionMessageFilter - 顺序消息消费代码入口:org.apache.rocketmq.client.impl.consumer.ConsumeMessageOrderlyService +- 消息轨迹:org.apache.rocketmq.client.trace.hook.SendMessageTraceHookImpl、org.apache.rocketmq.client.trace.hook.ConsumeMessageTraceHookImpl > 参考文章:[RocketMQ源码分析](https://github.com/bigcoder84/study-notes/blob/master/%E5%88%86%E5%B8%83%E5%BC%8F%E4%B8%8E%E5%BE%AE%E6%9C%8D%E5%8A%A1/MessageQueue/RocketMQ/index.md) diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultMQPushConsumer.java b/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultMQPushConsumer.java index ce9da315262..afc7ac9250b 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultMQPushConsumer.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultMQPushConsumer.java @@ -423,6 +423,7 @@ public DefaultMQPushConsumer(final String namespace, final String consumerGroup, this.namespace = namespace; this.allocateMessageQueueStrategy = allocateMessageQueueStrategy; defaultMQPushConsumerImpl = new DefaultMQPushConsumerImpl(this, rpcHook); + // 如果开启了消息轨迹跟踪,则注册消息轨迹记录钩子 if (enableMsgTrace) { try { AsyncTraceDispatcher dispatcher = new AsyncTraceDispatcher(customizedTraceTopic, rpcHook); diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java index 4f47cbed79c..1c06d6373fa 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java @@ -1049,6 +1049,13 @@ public String findBrokerAddressInPublish(final String brokerName) { return null; } + /** + * 是否必须返回与brokerId的Broker对应的服务器信息 + * @param brokerName + * @param brokerId + * @param onlyThisBroker + * @return + */ public FindBrokerResult findBrokerAddressInSubscribe( final String brokerName, final long brokerId, diff --git a/client/src/main/java/org/apache/rocketmq/client/producer/DefaultMQProducer.java b/client/src/main/java/org/apache/rocketmq/client/producer/DefaultMQProducer.java index 62ca705d2ea..0a3d80febbd 100644 --- a/client/src/main/java/org/apache/rocketmq/client/producer/DefaultMQProducer.java +++ b/client/src/main/java/org/apache/rocketmq/client/producer/DefaultMQProducer.java @@ -253,6 +253,7 @@ public DefaultMQProducer(final String namespace, final String producerGroup, RPC defaultMQProducerImpl = new DefaultMQProducerImpl(this, rpcHook); //if client open the message trace feature if (enableMsgTrace) { + // 开启了消息追踪 try { AsyncTraceDispatcher dispatcher = new AsyncTraceDispatcher(customizedTraceTopic, rpcHook); dispatcher.setHostProducer(this.getDefaultMQProducerImpl()); diff --git a/client/src/main/java/org/apache/rocketmq/client/trace/AsyncTraceDispatcher.java b/client/src/main/java/org/apache/rocketmq/client/trace/AsyncTraceDispatcher.java index 06a28e44cad..72509dca38e 100644 --- a/client/src/main/java/org/apache/rocketmq/client/trace/AsyncTraceDispatcher.java +++ b/client/src/main/java/org/apache/rocketmq/client/trace/AsyncTraceDispatcher.java @@ -54,22 +54,55 @@ public class AsyncTraceDispatcher implements TraceDispatcher { private final static InternalLogger log = ClientLogger.getLog(); + /** + * 异步转发队列长度,默认为2048 + */ private final int queueSize; + /** + * 批量消息条数,消息轨迹一次消息发送请求包含的数据条数,默认为100,当前版本不能修改 + */ private final int batchSize; + /** + * 消息轨迹一次发送的最大消息大小,默认为128KB,当前版本不能修改 + */ private final int maxMsgSize; + /** + * 用来发送消息轨迹的消息发送者 + */ private final DefaultMQProducer traceProducer; + /** + * 线程池,用来异步执行消息发送 + */ private final ThreadPoolExecutor traceExecutor; // The last discard number of log + /** + * 整个运行过程中丢弃的消息轨迹数据,这里要说明一点,如果消息TPS发送过大,异步转发线程处理不过来就会主动丢弃消息轨迹数据 + */ private AtomicLong discardCount; + /** + * 工作线程,主要负责从追加队列中获取一批待发送的消息轨迹数据,将其提交到线程池中执行 + */ private Thread worker; + /** + * 消息轨迹TraceContext队列,用来存放 待发送 到服务端的Trace消息 + */ private ArrayBlockingQueue traceContextQueue; + /** + * 线程池内部队列,默认长度为1024 + */ private ArrayBlockingQueue appenderQueue; private volatile Thread shutDownHook; private volatile boolean stopped = false; private DefaultMQProducerImpl hostProducer; + /** + * 消费者信息,记录消息消费时的轨迹信息 + */ private DefaultMQPushConsumerImpl hostConsumer; private volatile ThreadLocalIndex sendWhichQueue = new ThreadLocalIndex(); private String dispatcherId = UUID.randomUUID().toString(); + /** + * 用于跟踪消息轨迹的topic名称 + */ private String traceTopicName; private AtomicBoolean isStarted = new AtomicBoolean(false); private AccessChannel accessChannel = AccessChannel.LOCAL; @@ -134,12 +167,14 @@ public void setHostConsumer(DefaultMQPushConsumerImpl hostConsumer) { } public void start(String nameSrvAddr, AccessChannel accessChannel) throws MQClientException { + // 乐观锁,防止start重复执行 if (isStarted.compareAndSet(false, true)) { traceProducer.setNamesrvAddr(nameSrvAddr); traceProducer.setInstanceName(TRACE_INSTANCE_NAME + "_" + nameSrvAddr); traceProducer.start(); } this.accessChannel = accessChannel; + // 然后启动一个后台线程,其执行逻辑被封装在AsyncRunnable中 this.worker = new Thread(new AsyncRunnable(), "MQ-AsyncTraceDispatcher-Thread-" + dispatcherId); this.worker.setDaemon(true); this.worker.start(); @@ -163,6 +198,7 @@ private DefaultMQProducer getAndCreateTraceProducer(RPCHook rpcHook) { public boolean append(final Object ctx) { boolean result = traceContextQueue.offer((TraceContext) ctx); if (!result) { + // 如果入队失败,说明阻塞队列已经阻塞严重,则丢弃消息,将discardCount加1 log.info("buffer full" + discardCount.incrementAndGet() + " ,context is " + ctx); } return result; @@ -231,6 +267,12 @@ class AsyncRunnable implements Runnable { public void run() { while (!stopped) { List contexts = new ArrayList(batchSize); + /** + * AsyncRunnable为了提高消息的发送效率引入批量机制,即一次从 + * 队列中获取一批消息,然后封装成AsyncAppenderRequest任务并提交 + * 到线程池中异步执行,即真正的发送消息轨迹数据的逻辑被封装在 + * AsyncAppenderRequest的run()方法中 + */ for (int i = 0; i < batchSize; i++) { TraceContext context = null; try { @@ -285,11 +327,13 @@ public void sendTraceData(List contextList) { if (!StringUtils.isBlank(regionId)) { key = key + TraceConstants.CONTENT_SPLITOR + regionId; } + // 按照topic将消息轨迹进行分组 List transBeanList = transBeanMap.get(key); if (transBeanList == null) { transBeanList = new ArrayList(); transBeanMap.put(key, transBeanList); } + // 对消息进行编码 TraceTransferBean traceData = TraceDataEncoder.encoderFromContextBean(context); transBeanList.add(traceData); } @@ -301,6 +345,7 @@ public void sendTraceData(List contextList) { dataTopic = key[0]; regionId = key[1]; } + // 批量发送消息 flushData(entry.getValue(), dataTopic, regionId); } } diff --git a/client/src/main/java/org/apache/rocketmq/client/trace/TraceBean.java b/client/src/main/java/org/apache/rocketmq/client/trace/TraceBean.java index f93aa38b829..0224aca620c 100644 --- a/client/src/main/java/org/apache/rocketmq/client/trace/TraceBean.java +++ b/client/src/main/java/org/apache/rocketmq/client/trace/TraceBean.java @@ -22,15 +22,38 @@ public class TraceBean { private static final String LOCAL_ADDRESS = UtilAll.ipToIPv4Str(UtilAll.getIP()); private String topic = ""; + /** + * 消息唯一ID + */ private String msgId = ""; + /** + * 消息偏移量ID,该ID中包含了Broker的IP以及偏移量 + */ private String offsetMsgId = ""; + /** + * 消息标志 + */ private String tags = ""; + /** + * 消息索引key,根据该key可快速检索消息 + */ private String keys = ""; + /** + * 跟踪类型为Pub时存储该消息的Broker服务器IP,跟踪类型为subBefore、subAfter时存储消费者IP + */ private String storeHost = LOCAL_ADDRESS; private String clientHost = LOCAL_ADDRESS; private long storeTime; private int retryTimes; + /** + * 消息体的长度 + */ private int bodyLength; + /** + * 消息的类型,可选值为Normal_Msg(普通消息)、 + * Trans_Msg_Half(预提交消息)、Trans_msg_Commit(提交消息)、 + * Delay_Msg(延迟消息) + */ private MessageType msgType; diff --git a/client/src/main/java/org/apache/rocketmq/client/trace/TraceContext.java b/client/src/main/java/org/apache/rocketmq/client/trace/TraceContext.java index f61ba888cb3..7b6e5596796 100644 --- a/client/src/main/java/org/apache/rocketmq/client/trace/TraceContext.java +++ b/client/src/main/java/org/apache/rocketmq/client/trace/TraceContext.java @@ -25,8 +25,14 @@ */ public class TraceContext implements Comparable { + /** + * 跟踪类型 + */ private TraceType traceType; private long timeStamp = System.currentTimeMillis(); + /** + * broker所在的区域ID,取自BrokerConfig#regionId + */ private String regionId = ""; private String regionName = ""; private String groupName = ""; @@ -34,6 +40,9 @@ public class TraceContext implements Comparable { private boolean isSuccess = true; private String requestId = MessageClientIDSetter.createUniqID(); private int contextCode = 0; + /** + * 消息具体信息 + */ private List traceBeans; public int getContextCode() { diff --git a/client/src/main/java/org/apache/rocketmq/client/trace/TraceDispatcher.java b/client/src/main/java/org/apache/rocketmq/client/trace/TraceDispatcher.java index 51cc0deb87d..ce27a7e37ed 100644 --- a/client/src/main/java/org/apache/rocketmq/client/trace/TraceDispatcher.java +++ b/client/src/main/java/org/apache/rocketmq/client/trace/TraceDispatcher.java @@ -22,6 +22,7 @@ /** * Interface of asynchronous transfer data + * 消息轨迹转发处理器,其默认实现类为AsyncTraceDispatcher,异步实现消息轨迹数据的发送 */ public interface TraceDispatcher { diff --git a/client/src/main/java/org/apache/rocketmq/client/trace/TraceType.java b/client/src/main/java/org/apache/rocketmq/client/trace/TraceType.java index 79b19c17e4e..24f1ebc01e6 100644 --- a/client/src/main/java/org/apache/rocketmq/client/trace/TraceType.java +++ b/client/src/main/java/org/apache/rocketmq/client/trace/TraceType.java @@ -17,7 +17,16 @@ package org.apache.rocketmq.client.trace; public enum TraceType { + /** + * 消息生产轨迹 + */ Pub, + /** + * 消息消费前轨迹 + */ SubBefore, + /** + * 消息消费后轨迹 + */ SubAfter, } diff --git a/client/src/main/java/org/apache/rocketmq/client/trace/hook/ConsumeMessageTraceHookImpl.java b/client/src/main/java/org/apache/rocketmq/client/trace/hook/ConsumeMessageTraceHookImpl.java index f30b1211f94..70a91a4157a 100644 --- a/client/src/main/java/org/apache/rocketmq/client/trace/hook/ConsumeMessageTraceHookImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/trace/hook/ConsumeMessageTraceHookImpl.java @@ -62,7 +62,7 @@ public void consumeMessageBefore(ConsumeMessageContext context) { String traceOn = msg.getProperty(MessageConst.PROPERTY_TRACE_SWITCH); if (traceOn != null && traceOn.equals("false")) { - // If trace switch is false ,skip it + // 如果未开启消息轨迹跟踪,则退出 continue; } TraceBean traceBean = new TraceBean(); @@ -79,6 +79,7 @@ public void consumeMessageBefore(ConsumeMessageContext context) { if (beans.size() > 0) { traceContext.setTraceBeans(beans); traceContext.setTimeStamp(System.currentTimeMillis()); + // 异步发送消息轨迹信息至broker localDispatcher.append(traceContext); } } diff --git a/client/src/main/java/org/apache/rocketmq/client/trace/hook/SendMessageTraceHookImpl.java b/client/src/main/java/org/apache/rocketmq/client/trace/hook/SendMessageTraceHookImpl.java index 80c7babdaa6..2f76dbfc6d6 100644 --- a/client/src/main/java/org/apache/rocketmq/client/trace/hook/SendMessageTraceHookImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/trace/hook/SendMessageTraceHookImpl.java @@ -27,6 +27,9 @@ import org.apache.rocketmq.client.trace.TraceType; import org.apache.rocketmq.common.protocol.NamespaceUtil; +/** + * 消息发送时用于记录消息轨迹的钩子函数,与此对应的消息发送用于消息轨迹跟踪的钩子函数实现类为ConsumeMessageTraceHookImpl + */ public class SendMessageTraceHookImpl implements SendMessageHook { private TraceDispatcher localDispatcher; @@ -40,6 +43,12 @@ public String hookName() { return "SendMessageTraceHook"; } + /** + * sendMessageBefore()方法是在发送消息之前被调用的,在消息发送之前先收集消息的topic、tag、key、存储Broker的IP地址、消息体 + * 的长度等基础信息,并将消息轨迹数据先存储在调用上下文中 + * + * @param context + */ @Override public void sendMessageBefore(SendMessageContext context) { //if it is message trace data,then it doesn't recorded @@ -74,6 +83,7 @@ public void sendMessageAfter(SendMessageContext context) { return; } + // 如果broker服务端未开启消息轨迹跟踪配置,则直接返回,即不记录消息轨迹数据 if (context.getSendResult().getRegionId() == null || !context.getSendResult().isTraceOn()) { // if switch is false,skip it @@ -81,7 +91,9 @@ public void sendMessageAfter(SendMessageContext context) { } TraceContext tuxeContext = (TraceContext) context.getMqTraceContext(); + // 从MqTraceContext中获取跟踪的TraceBean,虽然设计成List结构体,但在消息发送场景,这里的数据永远只有一条,即使是批量发送也不例外 TraceBean traceBean = tuxeContext.getTraceBeans().get(0); + // 设置costTime(消息发送耗时) int costTime = (int) ((System.currentTimeMillis() - tuxeContext.getTimeStamp()) / tuxeContext.getTraceBeans().size()); tuxeContext.setCostTime(costTime); if (context.getSendResult().getSendStatus().equals(SendStatus.SEND_OK)) { @@ -92,7 +104,9 @@ public void sendMessageAfter(SendMessageContext context) { tuxeContext.setRegionId(context.getSendResult().getRegionId()); traceBean.setMsgId(context.getSendResult().getMsgId()); traceBean.setOffsetMsgId(context.getSendResult().getOffsetMsgId()); + // 注意这个存储时间并没有取消息的实际存储时间,而是取一个估算值,即客户端发送时间一半的耗时来表示消息的存储时间 traceBean.setStoreTime(tuxeContext.getTimeStamp() + costTime / 2); + // 使用AsyncTraceDispatcher异步将消息轨迹数据发送到消息服务器(Broker)上 localDispatcher.append(tuxeContext); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java b/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java index 2d5794df014..7c8251ef5f2 100644 --- a/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java +++ b/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java @@ -53,6 +53,9 @@ public class BrokerConfig { private String messageStorePlugIn = ""; @ImportantField private String msgTraceTopicName = MixAll.RMQ_SYS_TRACE_TOPIC; + /** + * 是否开启消息轨迹记录 + */ @ImportantField private boolean traceTopicEnable = false; /** diff --git a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java index 42a4b228cfa..c10132fcbaa 100644 --- a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java +++ b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java @@ -718,9 +718,12 @@ public GetMessageResult getMessage(final String group, final String topic, final nextBeginOffset = offset + (i / ConsumeQueue.CQ_STORE_UNIT_SIZE); + // diff:是 maxOffsetPy 和 maxPhyOffsetPulling 两者的差值,表示还有多少消息没有拉取 long diff = maxOffsetPy - maxPhyOffsetPulling; + // StoreUtil.TOTAL_PHYSICAL_MEMORY_SIZE:表示当前 Master Broker 全部的物理内存大小。 long memory = (long) (StoreUtil.TOTAL_PHYSICAL_MEMORY_SIZE * (this.messageStoreConfig.getAccessMessageInMemoryMaxRatio() / 100.0)); + // 如果消息堆积大于内存 40% 则建议从Slave Broker拉取消息(实现读写分离) getResult.setSuggestPullingFromSlave(diff > memory); } finally { From 5f09442ade439b422f8399dc434694eca40bfdf7 Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sun, 4 Aug 2024 11:05:12 +0800 Subject: [PATCH 14/18] =?UTF-8?q?=E5=AE=8C=E5=96=84RocketMQ=20DLedger?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E6=BA=90=E7=A0=81=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- .../rocketmq/broker/BrokerController.java | 33 +++++--- .../dledger/DLedgerRoleChangeHandler.java | 10 +++ .../broker/slave/SlaveSynchronize.java | 3 + .../rocketmq/store/DefaultMessageStore.java | 1 + .../store/dledger/DLedgerCommitLog.java | 84 +++++++++++++++++-- 6 files changed, 119 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 6dcbf7ee6b4..732ddec95dc 100644 --- a/README.md +++ b/README.md @@ -37,4 +37,6 @@ ## 高可用 - broker主从同步启动入口:org.apache.rocketmq.store.ha.HAService.start - - 主服务器监听从服务器连接实现类:org.apache.rocketmq.store.ha.HAService.AcceptSocketService \ No newline at end of file + - 主服务器监听从服务器连接实现类:org.apache.rocketmq.store.ha.HAService.AcceptSocketService + +## 基于Raft协议的主从同步和故障切换 diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java index dc1eb01702c..840ff0cda2f 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java @@ -982,7 +982,7 @@ private void doRegisterBrokerAll(boolean checkOrderConfig, boolean oneway, RegisterBrokerResult registerBrokerResult = registerBrokerResultList.get(0); if (registerBrokerResult != null) { if (this.updateMasterHAServerAddrPeriodically && registerBrokerResult.getHaServerAddr() != null) { - // 如果broker在启动时未指定master broker地址,则会在每次向NameServer发送线条是, + // 如果broker在启动时未指定master broker地址,则会在每次向NameServer发送心跳时, // 用NameServer返回的master broker地址更新主节点地址用于主从复制 this.messageStore.updateHaMasterAddress(registerBrokerResult.getHaServerAddr()); } @@ -1147,14 +1147,21 @@ public Map getAccessValidatorMap() { private void handleSlaveSynchronize(BrokerRole role) { if (role == BrokerRole.SLAVE) { + // 当节点是从节点时,开启定时任务从主节点同步元数据,即从节点向主节点主动同步topic的路由信息、消费进度、延迟队列处理队列、消费组订阅配置等信息 if (null != slaveSyncFuture) { + // 如果当前节点的角色为从节点,且上次同步的future不为空, 则先取消 slaveSyncFuture.cancel(false); } + // 设置slaveSynchronize的主节点地址为空。不知大家 是否有疑问,既然节点为从节点,那为什么将主节点地址设置为空呢? + // 如何同步元数据,这个值会在什么时候设置呢?其实大家大可不必担心,Broker向NameServere发送心跳包的响应结果中, + // 包含当前该复制组的Leader节点,即主节点的地址信息。开启定时同步任务后,每10s从主节点同步一次元数据。 this.slaveSynchronize.setMasterAddr(null); + slaveSyncFuture = this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { try { + // 同步元数据 BrokerController.this.slaveSynchronize.syncAll(); } catch (Throwable e) { @@ -1167,6 +1174,7 @@ public void run() { if (null != slaveSyncFuture) { slaveSyncFuture.cancel(false); } + // 如果当前节点的角色为主节点,则取消定时同步任务并设置主节点的地址为空。 this.slaveSynchronize.setMasterAddr(null); } } @@ -1174,31 +1182,34 @@ public void run() { public void changeToSlave(int brokerId) { log.info("Begin to change to slave brokerName={} brokerId={}", brokerConfig.getBrokerName(), brokerId); - //change the role + // 如果之前brokerId=0 也就是Master节点,则将brokerId改成1 brokerConfig.setBrokerId(brokerId == 0 ? 1 : brokerId); //TO DO check + // 将节点角色改为SLAVE messageStoreConfig.setBrokerRole(BrokerRole.SLAVE); //handle the scheduled service try { + // 如果是从节点,则关闭定时消息扫描线程;如果是主节点,则打开该扫描器 this.messageStore.handleScheduleMessageService(BrokerRole.SLAVE); } catch (Throwable t) { log.error("[MONITOR] handleScheduleMessageService failed when changing to slave", t); } - //handle the transactional service try { + // 关闭事务状态会查处理器 this.shutdownProcessorByHa(); } catch (Throwable t) { log.error("[MONITOR] shutdownProcessorByHa failed when changing to slave", t); } - //handle the slave synchronise + // 从节点需要启动元数据同步处理器,用于从节点向主节点主动同步topic的路由信息、消费进度、延迟队列处理队列、消费组订阅配置等信息 handleSlaveSynchronize(BrokerRole.SLAVE); try { + // 立即向集群内所有NameServer告知Broker信息状态的变更。 this.registerBrokerAll(true, true, brokerConfig.isForceRegister()); } catch (Throwable ignored) { - + // 此处忽略异常,因为此次心跳发送即使失败也没有问题,Broker会每隔30s发送发送心跳,所以NameServer是最终一致的。 } log.info("Finish to change to slave brokerName={} brokerId={}", brokerConfig.getBrokerName(), brokerId); } @@ -1211,37 +1222,39 @@ public void changeToMaster(BrokerRole role) { } log.info("Begin to change to master brokerName={}", brokerConfig.getBrokerName()); - //handle the slave synchronise + // 关闭元数据同步器 handleSlaveSynchronize(role); - //handle the scheduled service try { + // 打开定时消息扫描线程 this.messageStore.handleScheduleMessageService(role); } catch (Throwable t) { log.error("[MONITOR] handleScheduleMessageService failed when changing to master", t); } - //handle the transactional service try { + // 开启事务状态回查处理器 this.startProcessorByHa(BrokerRole.SYNC_MASTER); } catch (Throwable t) { log.error("[MONITOR] startProcessorByHa failed when changing to master", t); } - //if the operations above are totally successful, we change to master + // 设置brokerId=0,代表当前节点为Master brokerConfig.setBrokerId(0); //TO DO check messageStoreConfig.setBrokerRole(role); try { + // 立即向集群内所有NameServer告知Broker信息状态的变更。 this.registerBrokerAll(true, true, brokerConfig.isForceRegister()); } catch (Throwable ignored) { - + // 此处忽略异常,因为此次心跳发送即使失败也没有问题,Broker会每隔30s发送发送心跳,所以NameServer是最终一致的。 } log.info("Finish to change to master brokerName={}", brokerConfig.getBrokerName()); } private void startProcessorByHa(BrokerRole role) { if (BrokerRole.SLAVE != role) { + // 该方法的作用是开启事务状态回查处理器,即当节点切换为主节点时,需要开启对应的事务状态回查处理器,对PREPARE状态的消息发起事务状态回查请求。 if (this.transactionalMessageCheckService != null) { this.transactionalMessageCheckService.start(); } diff --git a/broker/src/main/java/org/apache/rocketmq/broker/dledger/DLedgerRoleChangeHandler.java b/broker/src/main/java/org/apache/rocketmq/broker/dledger/DLedgerRoleChangeHandler.java index 09bf10c327d..4b4ce5eb32b 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/dledger/DLedgerRoleChangeHandler.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/dledger/DLedgerRoleChangeHandler.java @@ -34,6 +34,9 @@ public class DLedgerRoleChangeHandler implements DLedgerLeaderElector.RoleChangeHandler { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME); + /** + * 单线程线程池,目的是让所有事件一个一个按顺序执行 + */ private ExecutorService executorService = Executors.newSingleThreadExecutor(new ThreadFactoryImpl("DLegerRoleChangeHandler_")); private BrokerController brokerController; private DefaultMessageStore messageStore; @@ -55,24 +58,31 @@ public DLedgerRoleChangeHandler(BrokerController brokerController, DefaultMessag log.info("Begin handling broker role change term={} role={} currStoreRole={}", term, role, messageStore.getMessageStoreConfig().getBrokerRole()); switch (role) { case CANDIDATE: + // 变成 CANDIDATE 状态,表示正处于Leader选举阶段 if (messageStore.getMessageStoreConfig().getBrokerRole() != BrokerRole.SLAVE) { + // 如果之前是主节点,则切换为从节点模式 brokerController.changeToSlave(dLedgerCommitLog.getId()); } break; case FOLLOWER: + // 变成Follower,表示Leader选举已完成 brokerController.changeToSlave(dLedgerCommitLog.getId()); break; case LEADER: + // 自己晋升为Leader节点,在切换到主节点之前,需要等待当前节点追加的数据都被提交后,才可以将状态变为Master while (true) { if (!dLegerServer.getMemberState().isLeader()) { succ = false; break; } if (dLegerServer.getdLedgerStore().getLedgerEndIndex() == -1) { + // 表示当前节点还没有数据转发,直接跳出循环 break; } if (dLegerServer.getdLedgerStore().getLedgerEndIndex() == dLegerServer.getdLedgerStore().getCommittedIndex() && messageStore.dispatchBehindBytes() == 0) { + // 如果ledgerEndIndex不为-1,则必须等待数据全部提交,即ledgerEndIndex与committedIndex必须相等, + // 并且需要等待CommitLog日志全部转发到ConsumeQueue文件中,即ReputMessageService中的reputFromOffset与CommitLog的maxOffset相等 break; } Thread.sleep(100); diff --git a/broker/src/main/java/org/apache/rocketmq/broker/slave/SlaveSynchronize.java b/broker/src/main/java/org/apache/rocketmq/broker/slave/SlaveSynchronize.java index 7b5e5645a0b..4b3ecfc18ec 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/slave/SlaveSynchronize.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/slave/SlaveSynchronize.java @@ -46,9 +46,12 @@ public void setMasterAddr(String masterAddr) { } public void syncAll() { + // 同步topic配置 this.syncTopicConfig(); + // 同步消费进度 this.syncConsumerOffset(); this.syncDelayOffset(); + // 同步消费组配置 this.syncSubscriptionGroupConfig(); } diff --git a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java index 9d51afa8433..4705959ebe2 100644 --- a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java +++ b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java @@ -167,6 +167,7 @@ public DefaultMessageStore(final MessageStoreConfig messageStoreConfig, final Br this.brokerStatsManager = brokerStatsManager; this.allocateMappedFileService = new AllocateMappedFileService(this); if (messageStoreConfig.isEnableDLegerCommitLog()) { + // 开启了DLedger模式,该模式为Raft写一下的强一致性主从结构 this.commitLog = new DLedgerCommitLog(this); } else { this.commitLog = new CommitLog(this); diff --git a/store/src/main/java/org/apache/rocketmq/store/dledger/DLedgerCommitLog.java b/store/src/main/java/org/apache/rocketmq/store/dledger/DLedgerCommitLog.java index 13da48bfe9f..8123f81c2a5 100644 --- a/store/src/main/java/org/apache/rocketmq/store/dledger/DLedgerCommitLog.java +++ b/store/src/main/java/org/apache/rocketmq/store/dledger/DLedgerCommitLog.java @@ -51,40 +51,81 @@ import org.apache.rocketmq.store.schedule.ScheduleMessageService; /** - * Store all metadata downtime for recovery, data protection reliability + * DLedgerCommitlog集成在CommitLog类中,主要实现基于DLedger的日志存储 */ public class DLedgerCommitLog extends CommitLog { + + /** + * 基于Raft协议实现的集群内的一个节点,用DLedgerServer实例表示 + */ private final DLedgerServer dLedgerServer; + /** + * DLedger的配置信息 + */ private final DLedgerConfig dLedgerConfig; + /** + * DLedger基于文件映射的存储实现 + */ private final DLedgerMmapFileStore dLedgerFileStore; + /** + * DLedger管理的存储文件集合,对标RocketMQ中的MappedFileQueue + */ private final MmapFileList dLedgerFileList; - //The id identifies the broker role, 0 means master, others means slave + /** + * 节点ID,0表示主节点,非0表示从节点 + */ private final int id; + /** + * 消息序列器 + */ private final MessageSerializer messageSerializer; + /** + * 用于记录消息追加的耗时(日志追加所持有锁时间) + */ private volatile long beginTimeInDledgerLock = 0; - //This offset separate the old commitlog from dledger commitlog + /** + * 记录旧的CommitLog文件中的最大偏移量,如果访问的偏移量大于它,则访问Dledger管理的文件 + */ private long dividedCommitlogOffset = -1; + /** + * 是否正在恢复旧的CommitLog文件 + */ private boolean isInrecoveringOldCommitlog = false; public DLedgerCommitLog(final DefaultMessageStore defaultMessageStore) { + // 调用父类,即CommitLog的构造函数,加载${ROCKETMQ_HOME}/store/ comitlog下的CommitLog文件,即开启主从切换后需要兼容之前的消息 super(defaultMessageStore); + // 构建DLedgerConfig相关配置属性 dLedgerConfig = new DLedgerConfig(); + // 是否强制删除文件,取自Broker配置属性cleanFileForcibly Enable,默认为true dLedgerConfig.setEnableDiskForceClean(defaultMessageStore.getMessageStoreConfig().isCleanFileForciblyEnable()); + // DLedger存储类型,固定为基于文件的存储模式 dLedgerConfig.setStoreType(DLedgerConfig.FILE); + // 节点的ID名称,示例配置为n0,配置要求是第二个字符后必须是数字 dLedgerConfig.setSelfId(defaultMessageStore.getMessageStoreConfig().getdLegerSelfId()); + // DLegergroup的名称,即一个复制组的组名称, 建议与Broker配置属性brokerName保持一致 dLedgerConfig.setGroup(defaultMessageStore.getMessageStoreConfig().getdLegerGroup()); + // DLegergroup中所有的节点信息,其配置显示为n0-127.0.0.1:40911; n1-127.0.0.1:40912; n2-127.0.0.1:40913。多个节点使用分号隔开 dLedgerConfig.setPeers(defaultMessageStore.getMessageStoreConfig().getdLegerPeers()); + // 设置DLedger日志文件的根目录,取自Borker 配件文件中的storePath RootDir,即RocketMQ的数据存储根路径 dLedgerConfig.setStoreBaseDir(defaultMessageStore.getMessageStoreConfig().getStorePathRootDir()); + // 设置DLedger单个日志文件的大小,取自Broker配置文件中的mapedFileSizeCommitLog dLedgerConfig.setMappedFileSizeForEntryData(defaultMessageStore.getMessageStoreConfig().getMappedFileSizeCommitLog()); + // DLedger日志文件的过期删除时间,取自Broker 配置文件中的deleteWhen,默认为凌晨4点 dLedgerConfig.setDeleteWhen(defaultMessageStore.getMessageStoreConfig().getDeleteWhen()); + // DLedger日志文件保留时长,取自Broker 配置文件中的fileReserved Hours,默认为72h。 dLedgerConfig.setFileReservedHours(defaultMessageStore.getMessageStoreConfig().getFileReservedTime() + 1); id = Integer.valueOf(dLedgerConfig.getSelfId().substring(1)) + 1; + // 使用DLedger相关的配置创建DLedgerServer,即每一个Broker节点为Raft集群中的一个节点,同一个复制组会使用Raft协议进行日志复制 dLedgerServer = new DLedgerServer(dLedgerConfig); + dLedgerFileStore = (DLedgerMmapFileStore) dLedgerServer.getdLedgerStore(); + // 添加消息Append事件的处理钩子,主要是完成CommitLog 文件的物理偏移量在启用主从切换后与未开启主从切换的语义保持一致性, + // 即如果启用了主从切换机制,消息追加时返回的物理偏移量并不是DLedger日志条目的起始位置,而是其body字段的开始位置。 DLedgerMmapFileStore.AppendHook appendHook = (entry, buffer, bodyOffset) -> { assert bodyOffset == DLedgerEntry.BODY_OFFSET; buffer.position(buffer.position() + bodyOffset + MessageDecoder.PHY_POS_POSITION); @@ -98,6 +139,7 @@ public DLedgerCommitLog(final DefaultMessageStore defaultMessageStore) { @Override public boolean load() { + // DLedgerCommitLog在加载时先调用其父类CommitLog文件的load() 方法,即启用主从切换后依然会加载原CommitLog中的文件 return super.load(); } @@ -248,31 +290,51 @@ public SelectMappedBufferResult getData(final long offset, final boolean returnF } private void recover(long maxPhyOffsetOfConsumeQueue) { + // 加载DLedger相关的存储文件,并逐一构建对应的MmapFile。初始化三个重要的指针wrotePosition、 flushedPosition、committedPosition表示文件的大小 dLedgerFileStore.load(); if (dLedgerFileList.getMappedFiles().size() > 0) { + // 如果已存在DLedger的数据文件,则只需要恢复DLedger 相关的数据文件,因为在加载旧的CommitLog文件时已经将重要的数据指针设置为最大值 + + // 调用DLedger文件存储实现类DLedgerFileStore的recover()方法,恢复管辖的MMapFile对象(一个文件对应一个MMapFile实例)的相关指针, + // 其实现方法与RocketMQ的DefaultMessageStore恢复过程类似。 dLedgerFileStore.recover(); + + // 设置dividedCommitlogOffset的值为DLedger中物理文件的最小偏移量。消息的物理偏移量如果小于该值,则从CommitLog文件中查找消息, + // 消息的物理偏移量如果大于或等于该值,则从DLedger相关的文件中查找消息 dividedCommitlogOffset = dLedgerFileList.getFirstMappedFile().getFileFromOffset(); + + // 如果存在旧的CommitLog文件,则禁止删除DLedger文件,具体做法就是禁止强制删除文件,并将文件的有效存储时间设置为10年。 MappedFile mappedFile = this.mappedFileQueue.getLastMappedFile(); if (mappedFile != null) { disableDeleteDledger(); } + + // 如果ConsumeQueue中存储的最大物理偏移量大于DLedger中最大的物理偏移量,则删除多余的ConsumeQueue文件 long maxPhyOffset = dLedgerFileList.getMaxWrotePosition(); // Clear ConsumeQueue redundant data if (maxPhyOffsetOfConsumeQueue >= maxPhyOffset) { - log.warn("[TruncateCQ]maxPhyOffsetOfConsumeQueue({}) >= processOffset({}), truncate dirty logic files", maxPhyOffsetOfConsumeQueue, maxPhyOffset); + log.warn("[TruncateCQ]maxPhyOffsetOfConsumeQueue({}) >= processOffset({}), truncate dirty logic files", + maxPhyOffsetOfConsumeQueue, maxPhyOffset); this.defaultMessageStore.truncateDirtyLogicFiles(maxPhyOffset); } + // 如果已存在DLedger的数据文件,只需要恢复DLedger 相关的数据文件,直接返回 return; } + // 从这里开始,只针对开启主从切换并且是初次启动(并没有生成DLedger相关的数据文件)的相关流程, + // 调用CommitLog 的recoverNormally文件恢复旧的CommitLog文件 //Indicate that, it is the first time to load mixed commitlog, need to recover the old commitlog isInrecoveringOldCommitlog = true; //No need the abnormal recover super.recoverNormally(maxPhyOffsetOfConsumeQueue); isInrecoveringOldCommitlog = false; + // 获取最后一个CommitLog文件 MappedFile mappedFile = this.mappedFileQueue.getLastMappedFile(); if (mappedFile == null) { + // 如果不存在旧的CommitLog文件,直接结束日志文件的恢复流程 return; } + // 从最后一个文件的最后写入点(原CommitLog文件的待写入位 点),尝试查找写入的魔数, + // 如果存在魔数并等于CommitLog.BLANK_MAGIC_CODE,则无须写入魔数,在升级DLedger第一次启动时,魔数为空,故需要写入魔数 ByteBuffer byteBuffer = mappedFile.sliceByteBuffer(); byteBuffer.position(mappedFile.getWrotePosition()); boolean needWriteMagicCode = true; @@ -285,14 +347,20 @@ private void recover(long maxPhyOffsetOfConsumeQueue) { log.info("Recover old commitlog found a illegal magic code={}", magicCode); } dLedgerConfig.setEnableDiskForceClean(false); + // 初始化dividedCommitlogOffset,等于最后一个文件的起始偏移量加上文件的大小,即该指针指向最后一个文件的结束位置。 dividedCommitlogOffset = mappedFile.getFileFromOffset() + mappedFile.getFileSize(); - log.info("Recover old commitlog needWriteMagicCode={} pos={} file={} dividedCommitlogOffset={}", needWriteMagicCode, mappedFile.getFileFromOffset() + mappedFile.getWrotePosition(), mappedFile.getFileName(), dividedCommitlogOffset); + log.info("Recover old commitlog needWriteMagicCode={} pos={} file={} dividedCommitlogOffset={}", + needWriteMagicCode, mappedFile.getFileFromOffset() + mappedFile.getWrotePosition(), + mappedFile.getFileName(), dividedCommitlogOffset); if (needWriteMagicCode) { + // 将最后一个未写满数据的CommitLog文件全部写满,其方法为设置消息体的大小与魔数。 byteBuffer.position(mappedFile.getWrotePosition()); byteBuffer.putInt(mappedFile.getFileSize() - mappedFile.getWrotePosition()); byteBuffer.putInt(BLANK_MAGIC_CODE); mappedFile.flush(0); } + // 设置最后一个文件的wrotePosition、flushedPosition、committedPosition为文件的大小, + // 同样意味着最后一个文件已经写满,下一条消息将写入DLedger。 mappedFile.setWrotePosition(mappedFile.getFileSize()); mappedFile.setCommittedPosition(mappedFile.getFileSize()); mappedFile.setFlushedPosition(mappedFile.getFileSize()); @@ -414,10 +482,15 @@ public PutMessageResult putMessage(final MessageExtBrokerInner msg) { request.setGroup(dLedgerConfig.getGroup()); request.setRemoteId(dLedgerServer.getMemberState().getSelfId()); request.setBody(encodeResult.data); + // DLedger模式下不在写入RocketMQ自带的CommitLog,而是调用DLedgerServer的handleAppend进行消息追加,然后将消息实时转发到从节点, + // 只有超过集群内的半数节点成功写入消息后才会返回写入成 功。如果追加成功,将返回本次追加成功后的起始偏移量,即pos属性,类似RocketMQ中CommitLog文件的物理偏移量。 dledgerFuture = (AppendFuture) dLedgerServer.handleAppend(request); if (dledgerFuture.getPos() == -1) { return new PutMessageResult(PutMessageStatus.OS_PAGECACHE_BUSY, new AppendMessageResult(AppendMessageStatus.UNKNOWN_ERROR)); } + // 根据DLedger的起始偏移量计算真正的消息物理偏移量。DLedger自身有存储协议,body字段存储真实的消息,即CommitLog条目的存储结构, + // 返回给客户端的消息偏移量为body字段的开始偏移量,即通过putMessage返回的物理偏移量与不使用Dledger方式返回的物理偏移量含义是一样的。 + // 从偏移量开始,可以正确读取消息,这样DLedger就完美地兼容了RocketMQ CommitLog long wroteOffset = dledgerFuture.getPos() + DLedgerEntry.BODY_OFFSET; int msgIdLength = (msg.getSysFlag() & MessageSysFlag.STOREHOSTADDRESS_V6_FLAG) == 0 ? 4 + 4 + 8 : 16 + 4 + 8; @@ -492,6 +565,7 @@ public PutMessageResult putMessages(final MessageExtBatch messageExtBatch) { @Override public SelectMappedBufferResult getMessage(final long offset, final int size) { if (offset < dividedCommitlogOffset) { + // 如果查找的消息小于 dividedCommitlogOffset,则从原先的CommitLog文件中查找 return super.getMessage(offset, size); } int mappedFileSize = this.dLedgerServer.getdLedgerConfig().getMappedFileSizeForEntryData(); From a91860af5766e752740b3d84f2f112be2dc4a8e6 Mon Sep 17 00:00:00 2001 From: jindongtian Date: Fri, 23 Aug 2024 20:06:50 +0800 Subject: [PATCH 15/18] =?UTF-8?q?=E5=AE=8C=E5=96=84=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 +++++++ .../apache/rocketmq/broker/client/ConsumerManager.java | 1 + .../transaction/TransactionalMessageCheckService.java | 10 ++++++++++ .../queue/TransactionalMessageServiceImpl.java | 2 +- .../client/impl/consumer/RebalanceService.java | 1 + .../rocketmq/client/impl/factory/MQClientInstance.java | 1 + .../client/producer/TransactionMQProducer.java | 6 ++++++ 7 files changed, 27 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dee36ef52f2..559b82fab55 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,17 @@ - 消息消费进度存储接口:org.apache.rocketmq.client.consumer.store.OffsetStore - 集群模式消息消费进度存储:org.apache.rocketmq.client.consumer.store.RemoteBrokerOffsetStore + - 集群模式下消费进度存储在broker中 - 广播模式消息消费进度存储: org.apache.rocketmq.client.consumer.store.LocalFileOffsetStore + - 广播模式下消费进度存储在消费者实例本地 - 定时消息代码入口:org.apache.rocketmq.store.schedule.ScheduleMessageService - 消息过滤代码入口:org.apache.rocketmq.store.DefaultMessageStore.getMessage、org.apache.rocketmq.broker.filter.ExpressionMessageFilter - 顺序消息消费代码入口:org.apache.rocketmq.client.impl.consumer.ConsumeMessageOrderlyService +- 事务消息代码入口: + - 生产者入口:org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendMessageInTransaction + - broker处理事务消息入口:org.apache.rocketmq.broker.transaction.queue.TransactionalMessageServiceImpl.prepareMessage + - broker处理事务消息确认/回滚入口:org.apache.rocketmq.broker.processor.EndTransactionProcessor.processRequest + - broker事务状态定时回查入口:org.apache.rocketmq.broker.transaction.TransactionalMessageCheckService.onWaitEnd - 消息轨迹:org.apache.rocketmq.client.trace.hook.SendMessageTraceHookImpl、org.apache.rocketmq.client.trace.hook.ConsumeMessageTraceHookImpl > 参考文章:[RocketMQ源码分析](https://github.com/bigcoder84/study-notes/blob/master/%E5%88%86%E5%B8%83%E5%BC%8F%E4%B8%8E%E5%BE%AE%E6%9C%8D%E5%8A%A1/MessageQueue/RocketMQ/index.md) diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java index cb6065540af..7b0357fa82b 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java @@ -106,6 +106,7 @@ public boolean registerConsumer(final String group, final ClientChannelInfo clie consumerGroupInfo = prev != null ? prev : tmp; } + // 消费者实例是否变化 boolean r1 = consumerGroupInfo.updateChannel(clientChannelInfo, consumeType, messageModel, consumeFromWhere); diff --git a/broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionalMessageCheckService.java b/broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionalMessageCheckService.java index a2cc0baa9e7..cf9902ea7a5 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionalMessageCheckService.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionalMessageCheckService.java @@ -22,6 +22,13 @@ import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; +/** + * 事务消息回查任务 + * Half消息写入成功,可能因为种种原因没有收到Producer的事务状态提交请求。此时,Broker会主动发起事务回查请求给Producer,以决定最终将消息Commit还是Rollback。 + * + * Half消息最终状态有没有被确认,是通过Op队列里的消息判断的。Broker服务启动时,会开启TransactionalMessageCheckService线程,每隔60秒进行一次消息回查。 + * 为了避免消息被无限次的回查,RocketMQ通过transactionCheckMax属性设置消息回查的最大次数,默认是15次。 + */ public class TransactionalMessageCheckService extends ServiceThread { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.TRANSACTION_LOGGER_NAME); @@ -48,10 +55,13 @@ public void run() { @Override protected void onWaitEnd() { + // 回查超时时间,首先要检查的事务性消息的最小时间间隔,只有一个消息超过这个时间间隔才可以检查。 long timeout = brokerController.getBrokerConfig().getTransactionTimeOut(); + // 最大的回查次数 int checkMax = brokerController.getBrokerConfig().getTransactionCheckMax(); long begin = System.currentTimeMillis(); log.info("Begin to check prepare message, begin time:{}", begin); + // 开始事务回查 this.brokerController.getTransactionalMessageService().check(timeout, checkMax, this.brokerController.getTransactionalMessageCheckListener()); log.info("End to check prepare message, consumed time:{}", System.currentTimeMillis() - begin); } diff --git a/broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImpl.java b/broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImpl.java index 0100a80514b..02497ba4625 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImpl.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImpl.java @@ -129,7 +129,7 @@ public void check(long transactionTimeout, int transactionCheckMax, return; } log.debug("Check topic={}, queues={}", topic, msgQueues); - // 遍历每一个队列,查询需要会查事务状态的消息 + // 遍历每一个队列,查询需要回查事务状态的消息 for (MessageQueue messageQueue : msgQueues) { long startTime = System.currentTimeMillis(); // 获取对应的op队列 diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceService.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceService.java index a427adf67f2..8b47d2a5b1b 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceService.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceService.java @@ -24,6 +24,7 @@ /** * 消息队列负载与重新分布机制的实现。 * 问题一:集群内多个消费者如何负载topic下多个消息队列的呢? + * * 问题二:如果有新的消费者加入,消息队列又会如何分布? * */ diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java index 1c06d6373fa..bdd449018cd 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java @@ -87,6 +87,7 @@ /** * MQClientInstance封装了RocketMQ的网络处理API,是消息生产者、消息消费者与NameServer、Broker打交道的网络通道。 + * JVM中的所有消费者、生产者持有同一个MQClientInstance,MQClientInstance只会启动一次 */ public class MQClientInstance { private final static long LOCK_TIMEOUT_MILLIS = 3000; diff --git a/client/src/main/java/org/apache/rocketmq/client/producer/TransactionMQProducer.java b/client/src/main/java/org/apache/rocketmq/client/producer/TransactionMQProducer.java index 4197c823708..0e92b80c5c0 100644 --- a/client/src/main/java/org/apache/rocketmq/client/producer/TransactionMQProducer.java +++ b/client/src/main/java/org/apache/rocketmq/client/producer/TransactionMQProducer.java @@ -22,6 +22,12 @@ import org.apache.rocketmq.common.protocol.NamespaceUtil; import org.apache.rocketmq.remoting.RPCHook; +/** + * TransactionMQProducer 支持事务消息的生产者,继承自 DefaultMQProducer, + * 在默认生产者上进行了扩展,支持发送事务消息。它拥有一个线程池 executorService + * 用来异步执行本地事务和回查事务,还需要注册 TransactionListener 事务监听器, + * 里面包含了执行本地事务和回查事务的逻辑。 + */ public class TransactionMQProducer extends DefaultMQProducer { /** From b3232c17634f340ed13fbc63930a54e61236f97d Mon Sep 17 00:00:00 2001 From: jindongtian Date: Fri, 6 Sep 2024 20:57:12 +0800 Subject: [PATCH 16/18] =?UTF-8?q?=E5=AE=8C=E5=96=84=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 +++++++----- .../broker/offset/ConsumerOffsetManager.java | 16 ++++++++++++++++ .../rocketmq/broker/slave/SlaveSynchronize.java | 4 ++++ .../broker/topic/TopicConfigManager.java | 3 +++ .../apache/rocketmq/common/ConfigManager.java | 3 +++ 5 files changed, 33 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 559b82fab55..d0d6080a240 100644 --- a/README.md +++ b/README.md @@ -25,11 +25,13 @@ ![](./images/RocketMQ消息拉取和消费流程.png) -- 消息消费进度存储接口:org.apache.rocketmq.client.consumer.store.OffsetStore - - 集群模式消息消费进度存储:org.apache.rocketmq.client.consumer.store.RemoteBrokerOffsetStore - - 集群模式下消费进度存储在broker中 - - 广播模式消息消费进度存储: org.apache.rocketmq.client.consumer.store.LocalFileOffsetStore - - 广播模式下消费进度存储在消费者实例本地 +- 消息消费进度 + - client端存储接口:org.apache.rocketmq.client.consumer.store.OffsetStore + - 集群模式消息消费进度存储:org.apache.rocketmq.client.consumer.store.RemoteBrokerOffsetStore + - 集群模式下消费进度存储在broker中 + - 广播模式消息消费进度存储: org.apache.rocketmq.client.consumer.store.LocalFileOffsetStore + - 广播模式下消费进度存储在消费者实例本地 + - broker端存储接口:org.apache.rocketmq.broker.offset.ConsumerOffsetManager - 定时消息代码入口:org.apache.rocketmq.store.schedule.ScheduleMessageService - 消息过滤代码入口:org.apache.rocketmq.store.DefaultMessageStore.getMessage、org.apache.rocketmq.broker.filter.ExpressionMessageFilter - 顺序消息消费代码入口:org.apache.rocketmq.client.impl.consumer.ConsumeMessageOrderlyService diff --git a/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java b/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java index ebc9dd8acce..88ab403097c 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java @@ -33,10 +33,26 @@ import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.remoting.protocol.RemotingSerializable; +/** + * broker端消息消费进度管理类 + * + * 消费者client每次拉取消息时都会在请求头中携带其本地的消费进度, + * broker收到拉取请求后会调用 commitOffset 方法更新broker的消费进度 + * + * 消费者Client,携带本地消费进度拉取消息的入口:org.apache.rocketmq.client.impl.consumer.DefaultMQPushConsumerImpl#pullMessage(org.apache.rocketmq.client.impl.consumer.PullRequest) + * broker处理拉取请求,并存储消费进度的入口:org.apache.rocketmq.broker.processor.PullMessageProcessor#processRequest(io.netty.channel.Channel, + * org.apache.rocketmq.remoting.protocol.RemotingCommand, boolean) + * + * broker存储消费进度的思路和客户端类似,先将消费进度存储在内存中,然后通过JOB每隔10s调用 + * ConfigManager#persist() 刷盘,broker在启动时会创建这个JOB:org.apache.rocketmq.broker.BrokerController#initialize() + */ public class ConsumerOffsetManager extends ConfigManager { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME); private static final String TOPIC_GROUP_SEPARATOR = "@"; + /** + * 消息消费进度, + */ private ConcurrentMap> offsetTable = new ConcurrentHashMap>(512); diff --git a/broker/src/main/java/org/apache/rocketmq/broker/slave/SlaveSynchronize.java b/broker/src/main/java/org/apache/rocketmq/broker/slave/SlaveSynchronize.java index 7b5e5645a0b..13eb7b3613a 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/slave/SlaveSynchronize.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/slave/SlaveSynchronize.java @@ -28,6 +28,10 @@ import org.apache.rocketmq.common.protocol.body.TopicConfigSerializeWrapper; import org.apache.rocketmq.store.config.StorePathConfigHelper; +/** + * 元数据同步线程 + * 用于 + */ public class SlaveSynchronize { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME); private final BrokerController brokerController; diff --git a/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java b/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java index a215cde69c0..7550a9a0cab 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java @@ -40,6 +40,9 @@ import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; +/** + * Topic元数据存储类 + */ public class TopicConfigManager extends ConfigManager { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME); private static final long LOCK_TIMEOUT_MILLIS = 3000; diff --git a/common/src/main/java/org/apache/rocketmq/common/ConfigManager.java b/common/src/main/java/org/apache/rocketmq/common/ConfigManager.java index 99b5f0c667b..9c6ee1fdad3 100644 --- a/common/src/main/java/org/apache/rocketmq/common/ConfigManager.java +++ b/common/src/main/java/org/apache/rocketmq/common/ConfigManager.java @@ -21,6 +21,9 @@ import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; +/** + * 元数据管理抽象实现类,内部定义着如何从本地磁盘加载配置,以及如何将内存中的配置写入磁盘 + */ public abstract class ConfigManager { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.COMMON_LOGGER_NAME); From a9fc4607200944ae16976c429f379f0dddddd88c Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sun, 8 Sep 2024 21:14:13 +0800 Subject: [PATCH 17/18] =?UTF-8?q?'=E5=AE=8C=E5=96=84=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=B3=A8=E9=87=8A'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + .../longpolling/PullRequestHoldService.java | 8 ++++++++ .../broker/processor/PullMessageProcessor.java | 11 +++++++++++ .../consumer/DefaultMQPushConsumerImpl.java | 13 +++++++++++-- .../client/impl/consumer/RebalanceImpl.java | 3 ++- .../impl/consumer/RebalancePushImpl.java | 2 +- ...10\350\264\271\346\250\241\345\274\217.png" | Bin 0 -> 591621 bytes .../rocketmq/store/DefaultMessageStore.java | 1 + 8 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 "images/RocketMQ\347\232\204\346\266\210\346\201\257\346\213\211\345\217\226\344\270\216\346\266\210\350\264\271\346\250\241\345\274\217.png" diff --git a/README.md b/README.md index f25f09bfb88..8d44b6acbcb 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ - 消息消费代码入口:org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService.ConsumeRequest.run ![](./images/RocketMQ消息拉取和消费流程.png) +![](./images/RocketMQ的消息拉取与消费模式.png) - 消息消费进度 - client端存储接口:org.apache.rocketmq.client.consumer.store.OffsetStore diff --git a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java index 417ec0dfd67..dce3f4059c7 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java @@ -29,6 +29,11 @@ import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.store.ConsumeQueueExt; +/** + * RocketMQ长轮询机制的实现类 + * + * 该类是一个broker线程,默认情况下每5s会检查当前broker hold住的长连接是否有消息到达,如果有则将消息返回给客户端。 + */ public class PullRequestHoldService extends ServiceThread { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME); private static final String TOPIC_QUEUEID_SEPARATOR = "@"; @@ -128,6 +133,7 @@ public void notifyMessageArriving(final String topic, final int queueId, final l newestOffset = this.brokerController.getMessageStore().getMaxOffsetInQueue(topic, queueId); } + if (newestOffset > request.getPullFromThisOffset()) { boolean match = request.getMessageFilter().isMatchedByConsumeQueue(tagsCode, new ConsumeQueueExt.CqExtUnit(tagsCode, msgStoreTime, filterBitMap)); @@ -138,6 +144,7 @@ public void notifyMessageArriving(final String topic, final int queueId, final l if (match) { try { + // 如果消息匹配,则调用executeRequestWhenWakeup方法,将消息返回给客户端 this.brokerController.getPullMessageProcessor().executeRequestWhenWakeup(request.getClientChannel(), request.getRequestCommand()); } catch (Throwable e) { @@ -148,6 +155,7 @@ public void notifyMessageArriving(final String topic, final int queueId, final l } if (System.currentTimeMillis() >= (request.getSuspendTimestamp() + request.getTimeoutMillis())) { + // 如果挂起超时,则不继续等待,直接返回客户端消息未找到 try { this.brokerController.getPullMessageProcessor().executeRequestWhenWakeup(request.getClientChannel(), request.getRequestCommand()); diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java index 0455608efb6..626868b35c8 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java @@ -90,6 +90,14 @@ public boolean rejectRequest() { return false; } + /** + * 处理消息拉取请求 + * @param channel 请求对应网络连接通道 + * @param request 请求的内容 + * @param brokerAllowSuspend Broker端是否支持挂起,处理消息拉取时默认传入true,表示如果未找到消息则挂起,如果该参数为false,未找到消息时直接返回客户端消息未找到。 + * @return + * @throws RemotingCommandException + */ private RemotingCommand processRequest(final Channel channel, RemotingCommand request, boolean brokerAllowSuspend) throws RemotingCommandException { RemotingCommand response = RemotingCommand.createResponseCommand(PullMessageResponseHeader.class); @@ -124,6 +132,7 @@ private RemotingCommand processRequest(final Channel channel, RemotingCommand re return response; } + // 客户端传过来的是否支持挂起,默认为true final boolean hasSuspendFlag = PullSysFlag.hasSuspendFlag(requestHeader.getSysFlag()); final boolean hasCommitOffsetFlag = PullSysFlag.hasCommitOffsetFlag(requestHeader.getSysFlag()); final boolean hasSubscriptionFlag = PullSysFlag.hasSubscriptionFlag(requestHeader.getSysFlag()); @@ -569,12 +578,14 @@ public void executeRequestWhenWakeup(final Channel channel, @Override public void run() { try { + // 拉取磁盘消息,并生成response final RemotingCommand response = PullMessageProcessor.this.processRequest(channel, request, false); if (response != null) { response.setOpaque(request.getOpaque()); response.markResponseType(); try { + // 将response写入连接channel中 channel.writeAndFlush(response).addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java index bfe86f935a8..ec915b847b9 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java @@ -346,7 +346,7 @@ public void onSuccess(PullResult pullResult) { // 将消息存入processQueue boolean dispatchToConsume = processQueue.putMessage(pullResult.getMsgFoundList()); - // 然后将拉取到的消息提交到Consume MessageService中供消费者消费 + // 然后将拉取到的消息提交到ConsumeMessageService中供消费者消费 DefaultMQPushConsumerImpl.this.consumeMessageService.submitConsumeRequest( pullResult.getMsgFoundList(), processQueue, @@ -372,6 +372,7 @@ public void onSuccess(PullResult pullResult) { break; case NO_NEW_MSG: + // 如果返回NO_NEW_MSG(没有新消息)、NO_MATCHED_MSG(没有匹配消息),则直接使用服务器端校正的偏移量进行下一次消息的拉取 pullRequest.setNextOffset(pullResult.getNextBeginOffset()); DefaultMQPushConsumerImpl.this.correctTagsOffset(pullRequest); @@ -386,6 +387,11 @@ public void onSuccess(PullResult pullResult) { DefaultMQPushConsumerImpl.this.executePullRequestImmediately(pullRequest); break; case OFFSET_ILLEGAL: + // 如果拉取结果显示偏移量非法,首先将ProcessQueue的dropped设为true,表示丢弃该消费队列,意味着ProcessQueue中拉取的消息将停止消费, + // 然后根据服务端下一次校对的偏移量尝试更新消息消费进度(内存中),然后尝试持久化消息消费进度,并将该消息队列从RebalacnImpl的处理队列 + // 中移除,意味着暂停该消息队列的消息拉取,等待下一次消息队列重新负载。OFFSET_ILLEGAL对应服务端GetMessageResult状态的 + // NO_MATCHED_LOGIC_QUEUE、NO_MESSAGE_IN_QUEUE、OFFSET_OVERFLOW_BADLY、OFFSET_TOO_SMALL,这些状态服务端偏移量校正基 + // 本上使用原偏移量,在客户端更新消息消费进度时只有当消息进度比当前消费进度大才会覆盖,以此保证消息进度的准确性。 log.warn("the pull request offset illegal, {} {}", pullRequest.toString(), pullResult.toString()); pullRequest.setNextOffset(pullResult.getNextBeginOffset()); @@ -474,6 +480,7 @@ public void onException(Throwable e) { commitOffsetValue, BROKER_SUSPEND_MAX_TIME_MILLIS, CONSUMER_TIMEOUT_MILLIS_WHEN_SUSPEND, + // 异步拉取消息 CommunicationMode.ASYNC, pullCallback ); @@ -615,7 +622,7 @@ public synchronized void start() throws MQClientException { this.defaultMQPushConsumer.changeInstanceNameToPID(); } - // 创建MQClientInstance实例。同一个clientId只会创建一个MQClientInstance实例 + // 创建MQClientInstance实例。单例模式:同一个clientId只会创建一个MQClientInstance实例 this.mQClientFactory = MQClientManager.getInstance().getOrCreateMQClientInstance(this.defaultMQPushConsumer, this.rpcHook); this.rebalanceImpl.setConsumerGroup(this.defaultMQPushConsumer.getConsumerGroup()); @@ -874,6 +881,7 @@ private void copySubscription() throws MQClientException { final String subString = entry.getValue(); SubscriptionData subscriptionData = FilterAPI.buildSubscriptionData(this.defaultMQPushConsumer.getConsumerGroup(), topic, subString); + // 构建主题订阅信息SubscriptionData并加入RebalanceImpl的订阅消息中 this.rebalanceImpl.getSubscriptionInner().put(topic, subscriptionData); } } @@ -882,6 +890,7 @@ private void copySubscription() throws MQClientException { this.messageListenerInner = this.defaultMQPushConsumer.getMessageListener(); } + // 如果是集群消费模式下,还需要将重试Topic的消息放入RebalanceImpl的订阅消息中 switch (this.defaultMQPushConsumer.getMessageModel()) { case BROADCASTING: break; diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java index 68f573b49ae..f69840e39a9 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java @@ -227,6 +227,7 @@ public void lockAll() { } public void doRebalance(final boolean isOrder) { + // 一个consumerGroup可以同时消费多个topic,所以此处返回的是一个Map,key 是 topic 名称 Map subTable = this.getSubscriptionInner(); if (subTable != null) { for (final Map.Entry entry : subTable.entrySet()) { @@ -396,7 +397,7 @@ private boolean updateProcessQueueTableInRebalance(final String topic, final Set log.warn("doRebalance, {}, add a new mq failed, {}, because lock failed", consumerGroup, mq); continue; } - // 从内存中移除消息进度 + // 从内存中移除消息进度(脏数据) this.removeDirtyOffset(mq); ProcessQueue pq = new ProcessQueue(); // 计算消息消费的起始偏移量 diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java index 6690bd4ae3d..8bb2e812a7e 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java @@ -158,7 +158,7 @@ public long computePullFromWhere(MessageQueue mq) { case CONSUME_FROM_MIN_OFFSET: case CONSUME_FROM_MAX_OFFSET: case CONSUME_FROM_LAST_OFFSET: { - // 集群模式下获取broker中的消费进度 + // 集群模式下获取broker中的消费进度、广播模式下从本地读取消费进度 long lastOffset = offsetStore.readOffset(mq, ReadOffsetType.READ_FROM_STORE); if (lastOffset >= 0) { result = lastOffset; diff --git "a/images/RocketMQ\347\232\204\346\266\210\346\201\257\346\213\211\345\217\226\344\270\216\346\266\210\350\264\271\346\250\241\345\274\217.png" "b/images/RocketMQ\347\232\204\346\266\210\346\201\257\346\213\211\345\217\226\344\270\216\346\266\210\350\264\271\346\250\241\345\274\217.png" new file mode 100644 index 0000000000000000000000000000000000000000..5c5b039f3086401a50ae960b1abbfc0f7bd768a6 GIT binary patch literal 591621 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%0DeG$zeLZ6 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ϟ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

67^}#Au?q2l;#trJh$c6mHdeS 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�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

F)VXt!7BD>HI*&7z=yv=OWwGQSl~ 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 z zsEzTva8!sr`~HZMQZ39ikXmkh{k7w!P$OG-^=U`JqVU6Dd}++_vBB}q6(0OKOkQB|+b@9N4})O6LbZo4*Mp!Eo>&Gw z-&4~sr#v5pfd_wTVN6GV7EHpq&j4t!pf%#Y6St{QzE*YA4KCW;5u8xCE#F>s(#}=P zK$t$@4mMI`MG0p3nOBh1=TJ?`yR&?Q975*?1}2%>1R5fAY#Oh8x?y zy8K#sq+qPmkMb6n3dSh|VmoBWH03A+XdNEW*;xHd>_k=Z>EMmq?G#L!s?1G z^cU)3<gd9>GaYb$jcg~gC)pZ1J*^C^m3=O!4mf={r0nPE-aBW@B|1h+qS0oQ*a*NRU&14_ zE7+$IN%f)l3h4Hy#G%f@!7f%<9_dlv(Y-}OCH32_v9pfKB9q{Ap z@O2$)KyT#Ls|yhiAJi(x3kT|mMXm5@*t7%ijvh>Yuqc@;#0PT!c#YlfeC#x55I!Bs z(MvaGnr(4{GM{+*p4WrSkR@HaMZc4Y3GS{88Bbk{8w{y_NQ|Q8ehYD{{ePb58+O2cHMhFe@gH z?z_)KAPGXA{6WuFP<}N_OVzfvQyu!9jn++LMZQ7c(`Q3N=SnqK+x2(4#hqPTQ=b_0FB|e%KZtZNu=}Ws?!z$Z zK96xTe!+G7u%}>#Tz`&#-Y1^{y>H-=p~9D1cjo@frmSG6J10pCXB_#*ckwM|B&SG{ zF{Boz%ss1aA2f-XM*1r4=zMEK$YNpi1$CrucFHvP$nFT)4$VZE&p>oF2kc(MdLi2t7etz5g!&JoMU{TIfIS7a z&^wtGx@*B`89`;d-s;M7=`;t%az6fyxc57I2eG}Af+K}LWMKo{vN(n^?TxJFuLmzH z&I!ktU+iwPH2QQoGgyui-47`!^Rlba4_0D9~K57}`U#Syor_#4U zhRi0?$hdUhRC?YN;>6cqFO6KwdfroZkNdEb7mVX~C-GzW5kK}A*^L)AM4#n|<=vUK zhMtjh$>Pq)72X{R_68UbR=#;cVitE0`B}`~x{Jj5l{OHOX+i~D{q(Qm_3(b*d~Rz) zJ}v&mvF^Rc-a}?uBvGg;r9&54VaMkm7qrLfjEduiQd9PDsaO%n(tIu4#G6tVSr5|0 zMaW7RP1c0X13)`}J1=Q5kZkv5C1A5%fw0!S?`(i|#mJOWn|fI#nA}^C$P~Tkkwaie z8S7D(;@&G$hySuA)>fQ=apQw}WX`OTsulFh#$Sb?ZrOv@+m{_NAo!Z`%n|2WVUe!8 zw^}8}`M4VAIGJ;!+o}R^|suiAnw@RuYFwN|DI=iDAX%%C8v{h)fh-~+d z#gJ?mV_3J3AT7-UxMd@V1{X-@s4@NM|I3QSk4KkxSJam~C;tUUs`dXNnDEe;PqJ@$ ze{MbaJh+_k zmUkH(-~2RYg2YlxB}?TD*3;|K^T+0cL0uK~8=6W|W-w5>l@Q|xbOaz5FXnVRK{iod z$kKt-utbN*^FYJY6yeH1bat%N{8}ulEXj~f305Kc6$+}7#km5Lu^HWd&5GT0he#NzTo;Bg-T4VGOcF{YWp;ZbvOcct=fhq%_HJ{eFZvbGCEIkO zg3lNGhGArSo!!1Vsg_Av(+A|AG^y_hRYwNyVnW6jc9cd z``MI}e>}SBi!}S;+5oJRmYL;jqNA>|t0BAsmaT?;)LCz4nMU@>jwrc|=8GO!=e;fT^y>-pxU0}hZ6W=`!;MVI0$#A?e=7D}e7-~bzBA(6Fet2aO{%WB6~M~f;RIUlQsmAO7d(Z&sB@vO;sGy!`lEqAO4 ziBk!6cEzB?a4u_ejDl(C|03)NaxT%>m5I6MJ>iG_--VHkbG;8GoYaR{4jky`!VarH ztgdjDdgt9q=4H=6a1%ctGiD|%Xf?jtHB-{j>Bafp;mUMbG_v>y*aQ^GvylUE3WQD$*H`lmSsmA$XMx<) zOopwT@z06t|I{t}h7hk8BDID5YB6h0Y?^$QZWXHNi6qR;Q$@T;;wFYaVI7{;Z3**k z3ctxT?XOg-1jzTMb)>r&GyN;#xShFh#|am^*LcEOk)ZMBpM(#SG_QmdU-OA#BSQa^ z*G4!Zv{0hrJy4+O{EZ3XpDBEeaCnP23PjSg6;pg(}gD03(z&h1)Y@9z3syO-3m5vAgYVFl~fK5~QDpbDJaS>qp4v0=}|vC)LOf z`L;Zvs8q=z3bY$aDb=Cxo~Qg-Eyw2M3Z?MMgk1mNu5!o(dH<`y%gI{ld9>2;F$SuS z;C|Hy3y6CO#~=HmX`2Qs@zi`LM{zW6vDH#mc>zn}pn z`V*$|`i+w(rbXk7qy|~EyBjG+XwEEzz6_{B|9ifB%#68o==4NrFU#Es_WWBZHAJ4`+7a!2m&$(kTOPWQsTdrIt0=itvAXfKm@clP zk-EXW6yiAPmQUifsOUxmr>3%wOb^_{eJrU+)Eg->tVU_?Z-}@NEtfXQB^VZqf3^sPB)M9gx>B=HEl^3#HED zUeL`tVicER2(s@LTs7Aw&i20z#$KF0*1@T6nAg8jp~4IObjWR}#+qw_pbj-&!f zwgi}W4_7;rr!DK`EoeJm1pI6wC$mjYYa*75#A}coFExw^p&&C%7kyt&<;F-9jfq13hH>A%kjn7|FCXq#+v{c$weu8dIIkh`U%Hr?+T=tLc zffRkqkC2e6+{{S3RuD!Vv#M$1+g{uauW~j;<;7M4b@JKE_a2*IBIivp>pC{sag&Gy zVC*%~8gV$Hw~kS9q zp>XgnJE*Tkk@-Fma!f%G(rc3>$8FAKGOxDSci_K{Im#*A$x5T_ zFY;%wcJi?Q3_qBt)ag>L{%*B`gpmn{@e)fxrIRA)kq%qT-7=1xg#)KuNB;H1d|q2y zja^pe_i(%jr22*0de~cPJ$(-d#-|ER3;D9wD@fhdO84 z2Wjfo1XJa|FEzy~B@P}>+~vDCy5^taSYexv49)eA(2_omx^atm63+BSv?*yG8Qf-& z)f^inX{HxC@LbxsoFsV66jDiM@#vL8$M58$VP}hTBWSZWsVCnU#~_dyV%g~gKf`2C z845BcrGf;`_4ktcq&)AYVvsk-;DGQ2e7>r?V3BY{%O4AZnt(+mBZmL?MkMRJ-7;t)L6A>yhGOSg46d0PZtwM>h7U4LB(ygmYz&Uk%)%sUXK_ue6Qb(N{9)mEiS4 zn9|&SLjxov^6h(XKe(0%^o@3-Y=PJ*_r>KMi`Z$~!$;FWowM@OMUY*;ZV~<5PY6ff zZ%@6&CP^2aov{WlI4fy)Ko=BLxSCxeBV>Ue;?i^2_|I zs}((qH7Y-S4KCaQ8~aq$6!Xc&cI>j zB7q%W+!;hmgVAKpkKEt!sk#w&I#|0^zkvr_;>oh?W(3n~(p`yyhKil`-3;eA?hqSv zp(%66uiSsu??2f+rNJEW)l$K%M$QI08Sr6QxTpyVpClP`|D*DbyrXOPN*STQ5mBkh zhQPMY2=!sG-PARIU|5#0kDbo2ZzS8Q%Il-~0VIO{2nZAb?L$0<%O*^tGSA6A#WR;E z=f9Ls{7AZ&U;td`!i~F-mZAsAW^bJxsu>zcb4yQ1M`0uW_3H%LEh^*PxE&?>Lt^)c zm>{+OrWb1;Y9yqf&y{)cY^4*APG(MM%sNhESmLlFY*D698sz#d?Vox#3z!kt)6`qe z7?qESuJ9}D2T!q;wm_%3j4jjW4N0EjHk1U8z`++a%2IMzI;=U<|j zqQT;k`pfDOk`8hu@ZkzCmM!qHcO^Bx=*sovr4&sJfY{oT@Nv9%`oCNFCsNwZxcFx_ zwxLS$)eenaFt_vYjmLML)#~tdSMK*@VPl8ywJu5+H28|UmIfP`HNlczgd%ov*EHVU za#3ssK~Tv-NlSpDw7XgGUBe*}`fdkYka<0_^?{W{IFc{}L9*;xwUn?UBzbhuDH_v| zuEr@T#f>b428o*j9kX+ocUbD*Cg~%*8DyNl8NX7R1camC-r@Rrh+I!VzL)@x1IZLvnACjjHQL3>u~u-cD1yZ2L-hNQW@f9R4S@W3jF? zeZ7M13r0*YV?vM%r;qX&+bVNkAM}M!1RiYnqnr*^B zDrKow4^|E}p=hXs2YSk_}%)l9R=R$ zaN65q_FF?|s4KEj6NFN#xREan6s?a%4!DHeL#Xm+dz@ZwyO-KVs+$5bx5rf1(DlI51>X?G2L8HU*t_aX5U z_`Gn^yh|zsF;218u%p==eYnVPM4tu|DNY5U+qf3mEm11a%Hv@s#aDl$rPmy#t`Sa1 zkKYP*u9%c;mLf=WqAPDREKWN!7$NrbwJ&3F%81}SNztB89wM%eczi@ZnnIgc34{WIyAg!h%1ZiTfkls^SsZV~t%gg>p*()wf>MR&wZIov)0W%z9Oy*k zq!@CasROB|O<(D;dr9+rDv9MRw@FeNE~rF4a@V6Ojjt@kmA?iG(JaIy=jlPhq@jv1 zShdUX#FB?7tuDJsb;TXoGR+62_DrNyywOMNBUbQKt@5RPVD8|r*{GIKTZ%7xe%U3q z0wqgTO^DKaaBjpxei`!5mZUU3=C3YJDaqa4pMP9kT|Z z&5SvJvI8I@d5~9x*Oov?=&xqcR_`4@y!s=EqMMKY+*^WSwxA~u_?6@C8J#yF8^*J3 ziQ;qP>T%wGqxAdn_NvSH0t5P@k#rxHdF-@*T0&aQCoAdBqY3G$l{rzW(;=zF6d6zp zC$vlZ$%NS*dUY~iOexE)AS_8(6ZTYFeu_h;Aw9poMY{<#v^ zLiIE{0TvayJ*%z{XrIIW{S6hnll<)W|Ce!^gMVtyv?L~c`hYCR+%GU-pD?bz{Vs4lNdUci(%v7d=|SyHZM#Zt{A8(732lVvQ(fZ1&M~ZBZLx6-vBRa!QZVi_ z1#zREYUnwh7pt#uvp+&r6h_C1x^srR%+k?Q;Aiv5l_5@lH`DQde64gOH}*u|eBt8R zi~@Z}z2?4R{`_fMd?=q^_wJ!vUoe!t^9>%KwI%Ft6z;sB(D$#&kWX(Bl9?le8}}H6 zRdz5(wQzCAbj}PR7kw!tfl;V%Z$!Z{@fY}A-rFp>IPE`{0@ohNo5K( z^=)IhK|x+IFh^OcPuTcq-C+7a+p_R<<)j%*!0B^$Na93OTqn zVL_6s>n9smaA<@~j}nG9|CAxGJheUiKv6h$o^LGMtdn*o)i>%TJF^`h8fC?fZbWmY6=a|(yQG^50f``y{PjDsq?89QGi20vCQSkhRTrJo*-1CWL2THwMJTZ-}m1ZJ9SZlz^>t` zc4c;U_%l)Fm8i@r79Iw@-JL7aCe`e4X!W)^&XaH;i&W8x?0thNWk5f42VvDu)h&@L zd-^ywCh`B~dj(W$TalQJP>2U+^lfNPU9Fn2W(MVxg&b2u>S&=OuXcEx!Z?!6=qy{+ zohg!ZE!?T2!v}+71@S+`Up`*%8lP(=y_x>f45AKV+maJ1fUD&gfzK=jciR)=#RVfg z+g?PcH^c~2bToc(^Tzl=ypoS7zYaZli^a>7XGIEM1$<|(Ssqx)w|qkGR8U^lapAWt z&Eg^0;x1Uw-Ag@&-rn`hMS7fb^`$e0_}3r%tDf@H?`65(g$m5d&P(jYw<9LFiynaA-3y3a6+6vIhUgY7Vw zcorj-o0Snu8NhdZW$1+KS7{e??1Ui{r*`2j;XbXC#C(y2L1Okew0azD&W70@#una@ ztsR%Bo&g`cU=-D7q@=~y*a5q*I>3|+KFOIvPQ&d5Uf&d_&^4Mx$tqv+rFvF-{pMh~ z@J-vw54#iJtQXrTk!?7Pyu#lAb4SKsW)!V_c5z|Vu2JM7;K^|Im=j_gw1|1*0a&!5 zskhdV<3!>EyH387>~}E*F=RzQv=+RF>zyLRRBFOA5b{-+CX6sY@!5hQ`Wm zYHjq!#7v4)WFkngR5@X;w_>B%gbts7G0Er@^e+_rSq$5nT(gb-6@FKoBy{+6VZ?Tn zE#M-J@fS`--HcnWV)s!KQK@Fay_p!V?~Uqp^quk$+eqkrG$BhPVNuvC0xV97Y zXepH+fd{s;RA6qW;{&C}Wk0Sg6Gx$gsy+;wxs6YT-LXMn_th7Q9{@%`W+ydoCn0!J_kJovhMg!E=|6p*2TsZ zFNgiytxru+QEuX$EzlBB&mdzaEPnq{uX&JsJX5!zFC~EeGu(1dy#+ga1OA#aD3r;` zM;Efs(^hP^vgaa+Rq{uG!EX(#yUYe9L2l>$VN#4F@(Mr5&WZNrkSHls#8x>$4s-J0 zlt+;q#){n_76&CcUCkdWl|0bMaFb{G*ij?;E6Hh8Td7GI@WTs>7`AwY?XsXnQtYY1 z&KvJLdT-fENw?hA#Zf$21Swhnb_N>Ddi(-(t%aBn#%QM4YkNxJmqL*@I}3s)1tH5= zHdHx#_uOD)j0}QWwYBNoXNGp6CtNr-2}IvgNG=crB99{I5#eC%jdGt>iQDv&>wHLyoUm6tY%BOfMxauXL9m0tC>=vw+i6;3BOv6h1(mr@?^?2`F{KO>_&R!x;6G6E+ z9XOL{0GIZ6;oZ41TmyhTpF*+rdB(oqhd@(dkq;Va22Ri+f3KEfK{SM~w`IyRb>>y^ zh3L<}Sj$J8XIj}~izwD+%`2LVnEDEc35`+LVxk9STGRZ&epk9J-|o*Kl>DeTj!F9LdhxctVi0vDLBkMZk=adVQYl zjeEY76k##&yZmbJ&Xm!^2A^q+m_rT8us;p<)T>R^Rw#B^?tS-!M>4lca) zN%`(vCQu2Hk>PCn2vm%v<-EZPagKC*`qWr%nuTv})5~$`O&VbC7Dh3c%?`GiytxS^ z$_wT_nl)tlzGHjC_HO3<6f<09BV4DkP*ysgFvo;uh8(vUXLv8-DvKEaqfukkiA~i# zsrs4w7uNKRP-I!1i3XGk*I&aHDV)?h?ZUli)%R z1>~ZatF)#W1RIrE4L2l&4GXb}fK$G`If9n7+q1#y6FhFbNmsa0caE7w-QfjGCdAF+ zdW24NzmB0G!HZ%)GP5_N^0m;_G+wcwHL0ih4~yTDpa!+}&IWWwG1xHGM+nCPBb zOoNnBaeB*|gE-O$FE-;Bgs~bbKkiAKQ8fgh^7P!(IqQryMbykn!FQqRMUDeR9~|4SuLRK}lk z-wE_KhUMr@r!J%ty6WdKqHuo!vK2W0``%shCIy9YJtO^T|KUPluKQD?{&l|JNLuS+ zzL4L=)-AiPY$QNSwXNReh>7t6!1?E{`V7E1bi2{NH-=}6!SzvHUtVZ8 zdHu+i%#{HJ4z2)tgMMq2CY`b)AkQHl{h&O?p%5gen!tpNDxh^^`r4vtPJLKw2Kr8* zkS?h`4`czx{lAiFEIbtV{c<&6e?ZLb(@1H^PJO@+GCX`FEeAPt)u6}V(>~` z`bRA(PvxOASr)wk%NHK#esoUjmph3*n=b-Ulb%mkIQt?Gla~eUha(;vl~30ZgofQO zxKYkK#>JWHt#?87_>X-}ZKa96!s$zFt*nkV)ejoN*J;&m!>zmd? z{DdLPAg)~7sjpC7*V3<-6#3dtAp{<=&Hh+jk^fId9I-yWlIEQjs2}^?CEdrIF?FEB zz+1otE4`RtsDVvu>b3uCu4bs=R3d^K)!6&JT+tpm102g@%xZl0`v`WKUc75KiV6Gp3zL_<0JJ7WMP)tQR;47gwiZ)MnV+X$Pb_+#1vd%@97Y;iyTt|Gtvm$)jWN;ubx- zh(Xgi>D-{)|LWG)xj6i$yZuJaOeE*i1^fQaTl|QJLVL-{5ew=BRUdBJm9`r9KoK-H{Vu1bmV}pPiQfRQFigD9VNg z7CFBpT&?^?JY5T+Mx7+P|G%U8pAgl5bN%8NO=bV21Tq6kp3MI6S2kRY-WP2{7k^Al zcn28FQ2}el)T#x?_;~akZn(_fWfZm*Ag-r1xlXDQIu}HFGXzH=bP>68a7ipHD*)MY z{$}$j7F!E0(&~%Y<}&aBfI_z59P|fcG6}&@On1wdj!^VsE6Lkfwa-v9C30oH;Gjvq zq;rmQMHJN|I=P;?vr=^fCu*{puGmx~scvtt?}14=gHDkG!de z|E&6{en1N@*`nRrVs8hNAO7>T-gP`>SmVufgcQDqrl{r#uhB{zK1hTZmjJ~0{{B*( zs(c>Nr(n&Z|HI=5L2%TF&?dW=B|aMs@Uz+xA;-8fAT%m~a6Dq+ZZtnZ%48vTx;ceNq7Fa^*XJE5(V=TXLim@8m z`RI$UWS|@Hzl2}Phsq0BYeUVJ-d+(}a6(jo`FoUTS<*}ZfORYf1Bva_H-yF1S3IH7 zi%efNIXA+pRDI7CQY+s*#>OnMyBG2k9ySJ2&@Icf*t!czg}F9MCY0Y=}Mam=MtuY0>(Y_KfDWFZ^%~AKTDHg z>UokrxII&%tL7=A(+&nEIVb@lyhtYqlb10F%Z+3S&m>6MB9QX@tx5*NR^vHL>+bNO#v;_G zb{ke_zIK%Qj|!9r4Xid1P9|iIqApR{PKQ{MXOP#Y9(Q23qCdBAmN+qU1M)T{7e+!Esr7G5JD9f zuxkp$70uXY*cl7b{0RMya1Yx#m9T#0>%Tv2QDQBja8t{^Y)Qj+1kd=Zy{blNFEvNF zUk**N+BBd5`fbSyjDBEH#b$zTHM>51d-cB(X~guO5^2isgqgNOxd-E=V!J2g4EdRL zdNS!e4S2s%gcKe*rO3hJCa}+K2#D(6XqrlowWO!fC`)ab!m_a5P`@!>`WguQ>ZAne z6KKctr!=HApEtB_Zp+;btt*`ko;^4gjkJLXa4IS|%J)<9(~?`1EP_-p$v7?9jzR+; z4*0o7%!ShBjaV4~Yt?2EJL4ad(8wOHG%e9TeJb;8sP8X6Q5}5+Tgk{uYGl!{d&Bo- zGZG(hA*D%==bNlnDstg*M+U?WT~e%BS~b68_7CBAr1G?TgyaUTWMOA0{O7MmW(8|3 zajE}gAe)E6!>Q1eWp)8+L11F7oXqx7#(V;I*DAdMKeR}C4BD(d3&HZGf;yn?aAB6` z1wB>vYWwguza$*wt0~i$SxwKgQh9QuV7*GH8Hm~)6SG9vXchfJ!efnT;;vf^Wx;}Vo~X-H(W9i@ui-4Sp%8~_(E7+Nm-{YO1&Li`#=WjBSz_<^ ztuYSSz&`t*J8Mxu_zK?phT$EQxY&9hGk#jT}p0*==BD*aA{~PaNE4lZLgQ){E>P5Nu}i@auhb}%U?m?*Hba@!wBvG zmm-10Vt94c;sw%A zXkGN3neXdKuy?oc@c}H=XD4}M>yP>x*VxWW=%I?#S&do?u*w$e&s>>*|6vU+Wo+j;J%{3qt_q4^QWipbrB3pdXPEm}A!fh=6lh5-U%rt?+mZj%0St zNjHcY=6mN3g^d)a7a!~Hh}>*>mZ>7$6D%(sEh;*FQ*0`-Klru|8mg+dj4}e zR~Q5umHdYzq$I=~naV0Cg}5;^(C$H^yWW$KYH7dm&0t^`pa>3(!k(_>=j)CUi_Q{` zdSZu^)jnFm+^T?(ghtvX`QmfV`AwFkPXv;P?kJDqVZ1Qh9Xpu&2r4t<6M`R~%(QbQ z6XQi)u8+2-WDIYWDJKlxNSzb9!hbOvwkMrUkKe!#&@$BMAKtpDEO9OPEWW=7J41e} zW`p7FdPgFlJSvgHr^M7dIPBFxOnN;vJ@$Vs;RxyDyx=wJ=!v7yEy%`6C>$Q?^UDz+ ze@)KcHFjM2M4&B(ijbAhGsSy}vsBDU4qLGkiPFe=jYWT95B}pf8OFS6z1+<>jR6WR@@s4 zJ;;2;4y*XF&=Ega)p5NOBm{yhGf>a&F=GEdd{u9=X zP%Hn_r5S>M!#&MX`u3XzjSt4^ITgKHKVOM{zUMML^mklqdXu|jLdoC8al$Vou|c7$ ze_q)l9~+&&AsNbGOqZh#;Uh9Z=&wu_hl{LgoV`1h2w4?zq@496K^#dSi<(gCW6~d! z*j>vj&Aj5I3?Q2EqI>OB#LgtiVoS{{u+4eFZFQ(~8q(aeGP!Z9tI=dK&Uw=$hf|ZY zF8?lUbfFGD!gzh`?5T{jIWd@Ufo@r5`|pEMHN<|?XdzGYVRe6587y@6^eF>xMhE0v zg)J(x)mv|Jl!N6#H0BXmqH=l~`^E-8X&#OJEZ0IKbmiX2xc=0euUm->%smEL0zQ)~ z{lr=_v((v1w|97Wcr^Ak+c(yhq9cQ#t$3pO`Ta~j^qL11Sa7hUE8!+Rl zh*to#Cj6`&BQ+J;G!AU!|IIu=P(a|`7k z?BXNCs3mqbn^-?5keg-%AGa^7zy%AgSIm@n;HI~KuR8~Ryl#)DXP=*5gL0)jUUv&1 zfePR1XkjOA9+)1+wVf?4&I#COD1MQCBLbTIwU%oc;)b}cC2fCUw;UJZ;a;xBx2;0( zC=1?u#-f|Jf<&~HdLRHBD*_F5AI_721PYW}c2upNacn7#0g%^3RV&cGkYHvX#*}3r z`qm{y+b$QczR|4rcBnBMzO?oIotraL^gZQ#PjP7E|=X{vQT zz++{Q?u3xS{iEFZGw`F*1OsZJPc+IiWq)Oq?fT;0_Tpy9H_%PVA;HJ`IV7f1g&#uf zUtO*=gJFj;E{79NO4IY}(IqHmo0ddQcJ*}eWM|^wOlNfAD5aP;`c6fGZY{nd+RLsFIf@k9++_KW$E$3N+MGH83RNh2Fsp0VhmXa7!sX+Eg7YMi-UujO;@+`9cOtUusBWEDfEdT4w7lF5 zRVChDENddfTX)guW2f=~F+}j{397d}&yvj5>fI-Ln|D*E<)1O+n!v^^a*A( z-{>B@C$G9{kKd5UgzH3T#6J=U>ntZ8eX4f{iaNG=I4_}>4JFs($_2cl%8d=X{hS*$ z9!ym=`=PEX{g|30{CPEWp$>oLA?eZkp5~3>Y1f3JgwFDDxjhkJwKMYj%|Cy{b~ncS z{&DU!;rex0BhV*(`A;O?aNGx=)JUNFQAc4^M%6>9{6#4DQfnRB1gH(JvCkGHm3Duz z(Jo*?ao~DkpB6)C6{NX1AAA!SX)p;B(~3d$0MDhy3!2}x(Nxf^lOY#D`x#_&T}p_N zww@};YX5|72#b?Tf?P@L&A;kfI1)tOogU@zk*q7<+!3O{G0xR#KVJ)FA51fL)780u zIx#Hyb)wCU`Rx)o_6)5mE+=&yk;tfP_<=FMuyDoh=YliV=2F-f3A26ON+dR6w&1ov z7@LZ@_)}f$uHy7qoA|!i25jH?V1&f?+)WLliU?E#T9KHadZKyPlRXse7^DZJC~a|_ zzLl-nL5rY%=!iD-0TUiqQ+n93e6#}*?b*nW(l zgpsvuC2czw913V=MQa?c%)j2Fx>co`eQ$~thyrXGyLsSP^jLyZyv5a~_3jxu^S?(F z@H+s;YQLC2QV0M`TpP$8*^Lu479#}ww?VK7mX7vtPPDBoOvj;`%>&^RZdk2K|9Fm4 z1+F$nVveyxcg{q3S6)nd@FPbg@+k9P8Z~_weYeEne*%|xj(P9<1EY{6=_$S%L$*SO z<93eS7QwAfO1#$A7yhN4pJ9mK7ptYcsLkb7;OTPnx^h+!+cnhJnP^UJBiMGdTR`o# zB1b=X$89lOpnX^QvHP>Th&^|j7uR5HwkEz5Q#mSCoXL36YKtL`@?$NF#fn1nB2R-{r8Hm zbSoDL#5US6P!qDjPx}iQ(w|QNg${J$u8H}?3o6zqJx+9R&sX&F{EP(UvyHtOqsU{b zcVr~p3UeD_`*g$yEH5Vr(#C`b;c)jusybL4NBT4!;|lbz%ywXNc|+gaRPbOgS0(ZI zNAjgq*ncn*fs#_TfBRmtAnwo#tnj`Ct2)@|c4RR3lgSRrq5kl(1reM8=$Ud56tTK{o=OPHj!kKM6<^E~mlmW^jO1zmr}!fO9dmg=Xq<>!X3R}O+1I~$>Gse$mQ-uKIy@W}@RL12!OG<0 zd7_wn8Zvl2dj-;aVK0G)Uh>}s>6D3KcC>bNeenwjv(-5H!l_o&hHUV2ZCGFEbu|Kz z0fFDKpX?oGeij?2MkB_D35}2Waa+lq~6C8=Nz|9 z`}zekH+g2C=sBM%0&{4iHRQ#QSxM3|WHNPb6ntIuh8w^+o0%z;SN9YDO|sholZ+=o4zvEqnwhnLngm*0RJsaUkcAUh?W>8I&V}w0lf+eV+ z%y472Z;+Psod?|9tty07em2u~|6^V^p49(Fk<+4)44$7Oug>-(%lH1NY7(ONUblP*1DdiI2s;w69Su4oX12{_v+a@$zYpk-xj98ih;0!#Ie zwMTKQ`Fi@9Fsl1kYaK`4<1@7xl`r6n+ZSdkH!{TbH~wKV44C6&(TfE(=D=0>I5Al6 z57?!xj=Lh|AFWl!6oiwu2%d^Xo|0Xpc2WCrH(+U|MBBIY zLATR_X0pUcTy9I0LLVOOkDMc2EB+71+$T3%Fqk!TkIg? z%(%a{GBR;w1@~KQY@SoaQ-_9PTTOgd{PMo|ivSz?;T4Y(Bi|&0rXcqj0Q4PgTBN zU+sd%$3yY6=U)>bQT2Dgg#aOamiZfF*#%%RT`1-1kBJzZf0WS~y@Oy2DzO=!@0xPg zwE*FH`72<`BG|5NITCBJA;&^zcU6H#AEaGG_ z-fZmpiS?E)kEblY@nyy5m+dqq-TBcg`4>-2$?A^T4227Bk9>Zvc{gO|D6&kWMw>Zr z#z+P<^xmCkIj2{OV^s~Bi~4oLd~>`?A(KUL`tmO`kh*<3!F;P0|K2gOfd2t!E_ird z_mA-KDF7g&?`1Lb)QA;SsQGAIRYZ(+}0QfkbVU!_y3JOvruD(n%w zhliVwrb!?We>a|^(lG>p=Xc#P0z+)IvlPqL zpRJDiSUftiGD&qdr3ZLBfsRs(sIf(~xa&x`?Wz9*E+*n7nD`R#t_b!LSI;=85Zq@B zn(uA`tFp%;a$EgL@#cC|Y`eEsJV6JLNzkRFJ*5OP`ZE}Fyrq4eOGoO;7^Gy^j zLeb3cZx7S1ov~YhgXx*2m+-m)zyG4p~Ot6B8j>Mp=Zbc){0F6Rwv_9u_nomTJwj zE#(QOTf_>Q4|1mGakq@6wOA3*H9Q_37+p7458mAyE0#U#wX6y>v@y$LcKZR?Tj$`-WB_Sv&-yUMH+aqlPXjuBea4pyIV zCX8tvdWm<)cE~PD=&Tm5b|hf`oTHAR8XzweOHsne}JAeG=Bx2cIk(Af({L%^} z^w4|Ru!}W6*FmrftVqi$;6i3zv@nvgm&`%)AKS{rP|?%=An8>($kqI;WSg#$v0_|# z+Z!?92*Qtc4@m>DtA#4fk+WW6fl-UKc9Dzq$GNKPeaIDd%)Cg~l99g^0$#Kv6vt^= zh5#oRFOL=?Lr%X6K<`4;*YYr(N3kK1Jl9blEhA4D|ELAq4UOZ-phipPQ_>ZR{&FB2 zyF!>sW3e0OQn2kMLyyzvmB;6*EC&=esocdg3CJtrY?iUCs0_CTveghRTTTt}Bt=^| zXxPA|dHVGFM_b^Fabpa8*wjA>ZVCcilaYohy-QLa-s#fRa#+7!i>F5I#v|KgQ~StH zKW#Vqx2?K^INC|p!ks!bvs_jDRt8H5rTv`+Rs zkF6|Jm-Anri>O@&?6;p=5n>qGmd0Wg+84*A1HoL-Vu2kF@Ikr01=%)Wx%;tHF z%2JyCYot*LbFqr+vDr9{{PgF2>h_nBBh9n-Y4gFEt@D0a>j2o1(O!Df3$$6{kjwM9 zk>lB=N9)-&v>X`h_`dh(u<-{EMEE`|2inxpJB-)upyj(7^*we!_H)eVxoR-#VgGmZ z^6A!&h+8Y@`;hb)Gf2qrKwQ|1UDy3(v1ZE=Q?{+OZZQ$tq}e5Zh8*eh8gq5!m&zCQ z#A~F_@d+W1r@P3eF526>GaOVXJ-!%1^B?8dO7XF*FFUSG+bJvj&0IB5;(^OcyKLeD zf(H-km1fM(%q?dTL=^Zvbj{6rx*7DdeJyIPZT`ClaCj`?PAl}~D;Ko7{A$o>I)HR1 zO%xI=^z%T!DYoEWG?w`z?~4an9{9UT=OI{%w!Du3a(kllD{KH)@7Zr6&m68uCVD*+ zm>p)@8MhbT$cX^XwEH!@l(EN7$N8}OCod6H=)Hnax2(SDKRT}4#uvecZSSt+dq&0+ zH5~~dgKDjsukKqQrmp>SSH`J}{e)9G>0q9Lp~Y50nrw3>#vD)Fv(+9Tz2MfS@Xh}1 zZ9zlua7a#8L0n8Z|B;S$YWd{^EUHmUm0M8L3olm1UrE0%XDb~{6u4b7a}#2vg&Ed} z+ip3hKz z`=N{HP@;+28Fv&1P4 zv}-Vu(?f;YgI8;Jd$AwBKZKj?@O^D)yd(YJ;=@BvQrf^Dea&V6x$f7ZCQWTLGQyLUF7pdu+YEKPOs>E3~?#yeF(L z4KDWAxBp^lqFiwtX%fSXP5ct|ZH0PY9M>0MiAm3xi~M#Di*3<-j5A5ADG0hjXY?rY z2|KH-9CMzFp0{>;&ue8-2o{p@_(CK!ReI4{@=|~?Lcd#tss6aLLad+ncx_6nnZ70Y zSQY2`aX}~)mbQu!@z9=jX$c#86x{7hmo0*NBN^(nfcK8Sby|4|Dwp~pbV+1SELCG_ zeo7hs5;dFkIs^2H=C2_%6uECv5UH^f-$7G|-Y+&U{T0L_(Em$l2KH;8$4CMXpRQiCd&%~`8B#>3T_Y@53;=*(?4)gJ6&@}yFJf}4@+?t zy#HTUUmX`^(=`lI(kPNkilj()!_pm#gpx{kmq>@CbT8fA-3o$IOE*aEvUE4!`o7=e zeLwI1=C7UWIz4CRoS8Y-txdW85@C7O%fk2DoHs8Y?~lZMM6_GpNQ5v79x-kg7Z_d1 z&VOMjvX{hgIWcUZkXT@GE3J1IYrIym!)(m2rzo*?GHAEjE97&CfyJskjEAR%-MZ{}>`e8t1osF# z;%uS|!@$Po_@2X24{eP;!7-e(%)nRlflT3;RxfIyJkaw!Wg>13B(yAM_t(zE0k~Mv zQdHK?1f{W9B&1u;YfzAS*htGa#P#8;E0J|wZ?SuMfOAFhJ@S6>YpqI{C*?;cj6$Fg z{!Q1e#B3U_RAUCj5d*_pmSoZ%>@*%a6NmQ{lr((hG(E4cO^HrQcH8o%n5&Ual+0`mzB2>P?7ne52y= z^_&2qoz}gENoz+#SxXR;%5@0nF<=MwWWfyf9zo~07>=paa%dH=p3$LLAzyk>vjw4o zWp)&BC$!;~C+n?|MweAtwen(9k%b7_t@eTQn8r=C6MoI)gE^A6R+ihvn9b~ZJnELy z_%p|kaJ~oKva_ABJNJ$H!Eu+*ghaPA2}7!*Va{uMe!!$uNw<~^Fzm-IQ?cB8baIRO zOa3rri7mFJR^Fxi>6CSUTVk~wZ+)qhD>8!(8kTq8e=(EPTxQZB!XkD^UVs(CZFXb0 zK14B-94SBV>ka^zkF&T|$btavok?$SHR*Hnc93)moM)N#dZ-nev?tzgx>IT;%xq9UXI=SXRwosW-hXnJLeZ*;!xvp*Gw&OOKwXdO3Mr z@0ZYRj8_V3xQgUFXrNDT);o9Bi$sEV_J9kig8i!G%eGIA=RulF3-Ni&n{mL118E^Y zYHF_8Z6BO`PesdOz2L!7+ie)oin=K5s&o6ekR>_AFg6FD!EXQfj-ZMpnO#8pwQ#_T z7RL0;0*&iK8v07!EI8w}%Nu>ZM!You`;k&dovI3AqVvi~`FxTZH(NBWCl|E$zxB+UB6 zHUJ%8J2xZwQQd335~5K6evq)?H`6^F$f=BbzO&a^;JvymQYG_!81ac*x2%nD{w<5_ zTxUbYh=b+|%wq6-xs&xqL^D_zIl42$bs6KNo}lY$`;H2l@pGbV_JmsSSKbzO6{@4J z2(@44WvGp7hEA5~6n6$byx{f||FrM=i3i-=nAcryD@zS)E3M)6tF4=gv;+noFKJ9f zW=J?q3O;Mkl1e|U+-D3EW9K10?nI56?lDj zMYWFGnc;Xf{6|!tWE9EFMHUff?5mX ztxj7~Lu?q}x~q8cm8K(zFK7|!K+;+6d!rkB+jX$bIun{(R%~+&^M%{sRzgXwe`|-k zQdxKFjk?r3Wz6_fyv5R%*ne^()_{l7*e|FpW9N~B6r?NV!KI%T>U|eHOo(JEv2#EX z30LKvK2Q@8iH;WJTrJQ~f+hfVmj~UZuP{5?QCNU;xe5G<3p)j% zXPoWLixxKUB?dEE+eyr}l*H6HVfQ&iI-{qNd`g4w>FWLjw^zQ~?)`Lm|20dE2~Nk+ z(Z;XVT2hK;Gdah_Cf+oa62kT4PL*!mCv2Ruq5>~Teny0qn?*ec8o(Sbx#lXFvZZD{ z!kg>Yc5{IM;b4R&3`W5%uyapsu^H3NfW4*fi5HhXUa$&Q-|&OW>@a@7!2oa>nl5L_ zqjf^b6`3qPo3hZ`F12MZR6qZXgXlH!lC+u7RO{M6N3;9)6SRa9d+!45qcE@KqTl;y zbes(&xzydP;?mhcV}K9TSQ?!Td$BO*F@}zw#r;b$S}eNpgL;qUC|icg%8PsZ<&hds z3Uu40;QDfRblzc!3SS?np04F+NoDWWV)LR}V}Hve%S2P9;Iyap<8anNB~4^9I99q2 z$@^>7qF92vaG<&wbY3AqgB~4$@Bs!2>2!TIxQf_;4O20unJhM!fiw6~MKVsJ8L23`vk#GB zTbGc-lM=*&6@SZy%eWj9B;kQCP!)Nv^h^PJfq;Hr?K(mUK+1SY%1pn$YXbE@`{26BjU?yZNp-RHLHrJ-U%0TY0$3S>0MG`8tQgqt#AtqX7 zwRS|T$*ukd;#uGxelQe#5Nq^_A`x+7*|)B0@}YKSfAN-3r!%3IvbQBwm4wWNev!NBr6Rx30xK&NVg zs+h1-CLcTUCSXz(X0*71x(D<$QZ32NdNk;65025x5fk4QbZH{(+|$jl)C@7dB*i}w zy#2LZ1^=n&CwY0?iHNN4SQ%fUHS8hX*rrx#p^1xa%yE+kb$9E1PM`546a_bLhUq%S zo+EB^X6HqDY-X=uDZveVSr3R(H@wr~4R5pF`lWZWXE~K*DNMXkru5d`i>b`$^D4NT z9cPqeNz*jYZ|2P3g*&>bB;7&+6vtiCX=KiMyt&HcyV5>WD+p=7+%9K3+lL5cd{^|2 z;l1~6ArVq=%g!;v5g$C;_dnBx#IK!jwo>bbqGmvW(4@2k#`kfH^oV7GUlPDV%$Fq( zAhl27<3&Z$cy$+(*FEqex|(T0ZUhPb1Sfb2T}yEWJCl!~c&08snkn(+35$t=1i;KT zT>GqTBlfJ~LOW_DVF>-ARPr3tY#|33p1_RQMJmjOa0UQLYSxQ49#$@`-CNDh&)w@a z833`Zp0h!BU(zb{yS(hK0M@lA)+<4twa4wQM{GC0Pk*uQ1C2BB+Nck4V+Ys8`5Z!Q z_$!nSSu0dfCyTO(5MQ6aHW>|R^aA2&)jIcnD8TRF?wAGR(H5D?%#Xm_sK>~K-Mv4a zg_~abUkZ#B401B$OH0o$npK)2M^VlnRt&o2g(I?R2V@f#dj(78sQ6mVU?&Uk+?+XA z;sGYcL5N1@?looR3hOq}pjE+OiK9;2!A+!UCsP)o z3&yW8o1ndsoh=c+x$>+RfsFD>?d@KJ0Ln*FQIBlM^`+{(p17oz%IKuZ^}*| z(HPh~(IW@~nlX%C$An&^l@-fHO~6CXR|py7!x|?>=@L`2c;r4B|Z+xeCf;k-nvD<;^XgK{yPWtkNTD!+@ z22ECBmf(wm!wak@zk&-|A@xQQ-INe|8gj7W%?_cZF`w0J7L43)GcS#(erJi>Y|Quh zAMeSVF4pl7&&-|uIpjsa^BW|179r+iO3QWt<2#ZC>A3!yANtyRHU`jf;=I0>nip8| zKR>2yz9>yWoANJ`2dKnfC@9IR(`6JeBqkI1Mon@$wN*N4s(+ZO8Gz|pgJ2u)0@OS* ze27ur%EJUMDlqjp&18~rWnH5R?`@Uy%%&pA$eKMByiVgm7!TQ+wYNO?a>L|bN|ANc zl^~f?ziK-4!r6!YA1$`%7K#$auk)12Jy3QEc(;COE>v3$p+8X^K!LKV)hicoD|^il z8}b#c)6;V##`}QY$(;P~HHfoS(;rRTbWQ(ZJXm!+QkC%FnUNx>2cn)hms>|{PmhlZ$!pKoC4zZ=$UOmw{Zw{kyN z4!Myg`R^u&VIO_I;cuf(eB(#%WUq3>a=0^HqTb3g5%VeQxc>VrqLzWI)=Eavz9kg7 z5EGg!4>>f&*jG3eQ=FB6?cTR=Ny^&g06^%soZy~n96+g(Fp@lCqu8@3H^@BHXg zs4z>Cci|->TU1h{v~>oH4sibyKDW0ZVm^Fjq3~(171_eM7>!J27I7F?`ZpmMvg0kd zfwTbXn_9ppu24Ofs3j!n@c60|lE7MgX&qtM*q{Peq=(Uyzk!+kgi|zgGFqUB?&p7k zrlNblo}K(0Gxmc!OIB%R+oNJ;s!OmS);`CTRi}X(0R6r!!R{xd%Bwr2aRX93FLUUb z<=MsIZ6yn4?etcW9qfquIb#-m&VBs*qpY3IJZusmYVkltQSWf2kRqMnf9G+u30GrC z2Ut9477!O3VWS8>> z{6TjLAM1^ZK(D!5w!@@*6-T+O3+!^iCQa2d{#NVVrQf==iC<6jO?w+Bh!=D#7vjw) zlEK|gQy0zoJGGRe-TMlKmTF?`&R+ro2-STvQw$CazpEhkR;o zX@N<3k6*&(y3PP4FU??SWLgZ;y+{AEH$mN6-QB$%n&v`0iQUp4HMF5N{3ZBtT{&ww z)PL}KnzYILcPTXtQNsJ*MQfZ;3FY9>1WHp&H;RUcIA^jqrRy;P&YXp`+lcJw1yLKR zl^Eyncrp57vFvKGY<6euC+miMH;E&T9X7SGc)44F&jH2qqe_~1dGyTntdRrvTI47_ z133EeQ75_dfC%}S7TYMYaZBCbuAr#QxTk<#184~;Y!^@8mS z^=E=A_8aUupzBpEpKq=OpvCJBknCuD-SC#IutM#+2}bg_O#18qojlh}|Cq^+NG^I& z(fG;cC)h9ZbvJmAcxA{=&uePK4rE<@KiNqPeh5vD%Y@YOlT%wTH~+wn=E|p+23vzp z)r7aWLd962i3OkF z=q$Pi`Ka}4lY=t;dc~aOSwpEGSrM^J{g+T(^P2{2!R~H@Uc@P)zDMq=&T1aL3Q!&G zk0OG=0t}%qcO+z0Gzz%R5R=qAVn#Bu`j>|j9k~(7Yk96ysx?lLVpm=RS`ffj;no*} z%n=id;N*sAf_z^mYr2-xz)rQgDFR2Iuj_6LgZpGYhHy#aA9suBo@0RJLb%^o9EK;4TAS>=*g8MxM;8uu$X2F3DW_F_r>_VTK1ZqOKUF;)|6NB0QfL zeG@MDz9NFcr;nYR;^~hOh!jL+PAuf!LX~WloAG(@nh2R6U}Ww6r` zZD_z3fTL4^cnC{q&c^j9Tcu~#Cb{VpsTO&7y@nDkpek=|F^&^Epb0i-X|yq3LJF%F zi4r=2+AnRdtt=tS!dwhjTq!(~or?ASDX_7=2D$Cb+luFvr4AA82g8k<(ySq|gDA14<4q<z1}3{ zhqC2{D!v2i=%~oO)ygeLQcfCPD6{as?rK02vN7P)4Hv>`z@GC=7lThGY1pTEK5AU8lw zH9BTEPd?A^&7A%M64Q}s6hsx(#60Sp%atDH*~XVY zwcX(9`^U2V6e7`!0On$i{tI0P+zhdYafFzCVq=?RE|+w^2d^vlIX#U0GkmyktXR#16>+Z$BpT0u*Gb>L=#xBng~77o2EZ z3Io-DqyCZD|2C-@VqE!&xjhFS3CzAOxfvN`X~}m9Ltp*_fdJJcyLgM%dHDFnwyE*+ zU~^Kl*!6L<(W`U8xc|UFkaF5!EAfPq=}Ygcr#>dVe${$>i+>_Y5b(}i8MWxa^N`5zO5qdJ=Z^!NLu~|n6gSf&G{Cj zK#;x;NO*#jviRbk{s7DQo=s5rb42e&pOA8n6lVw4Ujn4K^<#QbNdx0a5uhnhGdA@$ z|9Mk#4)~KZRRXQ#2oO4skOKxyktJ<6_CJEOl#Qew9+i~GzWz!aY%VZPvFW2@uk}~X z1gLptDDeXl3SS*0=dkl@i0+vbi&Wo4ZvD3a@&dku{g?=A@Z`Xh;?8^$onz};CIlw@ zqyPVHePU`q(F+KGiIxL_HT+Q19GZrKhyaCu@HjVE8bf3)h$1i&X!dZwB}&=Y#^J;f z{^cZ?;tk*{5^ycRIgo}&vOApgC8}!JZ-iF}$D?Afd3YF|7BceaV25M0&9Qt1v zybu_yIP|_E1Z=|YFCjf<bKx7hd`o#?AyZ;Rq@4V5p;EB^GPo{ELaN2mpkhLj6Gj z&KZF;1SK56N6)8hzy8~(5jflkn8;`u5n~VK-i!88>>m;&!!0LzHbYWn(qvQ#E}k@0 z0nxxt`u~L@AAw@vzC!Ac$&W~W)4!SJ?jlY72LvrblMD%?5pD=$M3>N>JnZuv4gbHY zbk@sALfB&s|5^=}WEwf8Ji>ndviWE5GMmNg>4%5>F?Svi3upk}_t^MP*z>;)p>6Wi zT{|E{Gs{ycyl8V0_UE|me-!supMSJn$nS1~&mc*VZj!Z(_AQxB@&EEMxi=4_!!N2I z9#(#ZfQ-hLwPt1#ZB6tqok${v){6k^!Csrm=B*}#iWs-)?F(1GH>I+Oa4`OhB44lr zA4h;UE&;2UlBOfNzY1) z=P@^2_hNaH(e<2SCE@5^iG}5}9wGg&}jjC-#4M9=U3#QdZ7mGnA#C&8F=^ubh_S|CQ?EW!v*VI4Vm+ z572Ejo^x#R()4xBS8@)|KGKy@`dG+oP&+aEXY>1>+#P%>fvY<=u*++!*`rXJTTX}i z4$gC>&KyE=&-a5`%g!%(jiIfB_@rD9l*2o*t^>D3QWi&3KT*Om z9|!ztcdFO!TMHh`5gQB#x@D_BlloHB*XiG;0bJVuF;B@K$3`c{rdL1!&%+CeXiYo@ z+LA;6J_}2|t?f!eE6L1Hgpn!QR-#9>^2Zr)*W3)Ij)eV~{fKHzd1XzVq>i)f;2XUpjGN0vf0nNW9SR<6SXy!)oIt&)acu=D-)6E z5D_<5jq*%=pQ(O0g9dq1+^VLIcmrlXx!cYHV?8b4ZS45sYe#fCWMd9jzk@uwr<;^g zVoNdsOc?|{sKWdXQ2nX4{UYTy+9tPt9pC3eQv>PC?XeN`&jF@Go5?76@COEMCHYI% zJMU#342RX4hYmIjkBrJr&&E0v2{-ECv*zW_WYM?2g|FRoKHC@gKMRoYRZKG z<{)2BQxYQOOo6yj1>RfnuQrE19nsXUZpVY1_(Zktd7)t?c*VH`PTY(tU$2z@4(Grl z5^40rM;0yf(N;C&%y8l=O#&e#7g~Q)wNw;Oao=D%JK>Nu%b&TL$xXloJSz|RMdUa2 zNU2-&Sz^Gjk4!4*O_PZ+$#W8L+>#vR7c-OByUz?nnY84nZ}ref^S-MC*d@05EZ@P# z{jp)e$+)l5lV@_LW0GYj;%7ux2EXL-;L$od<-BO1(vM6GJN*#v0Rm zfb;3@AY+zhp$UBGOKx6&PXx8iYq=Uq)u=M}IG-Qjw)rsB=YcQ!@J%IGMd$H)UpqzE zMwm?eVuvFGrZhWFfG)}2#>N*#^hAPpT4XERGvB9Li>hR`v%R3m+@m<_9iQRU)*6r+ zlPfLo=BDkwl$aO#;}=@GHQ#j6`OSsF#iDxS2aDTA>TW-b>8xsXGWKmh-=1f3qIFIq zyOATie=&^7r9Wu#8U+~ zIj=gWIO{YBVZ(uZSJ3Dgvi}1iWkTM0ZQ>TbxiXniuhqZ&!(4{nkDhOToaS@i0V5To z-*zy-XMW#L-8o4r@uYb^mkdasbx&@3tzE^hTaVy@X=2730JJ}o4t3b~cN-LXQtbK-~4XJO)Xo9Kj=iLii`C=5# z2M{;;EcjC9twit%q$28I>d8XG=}O(Na!#HX-SYY31Tjzb{HC$#CfpT2kh@f>8W~qXS8-d^#dd0PH`EDXFYrz5CsNSykX-E=)bO|HTf#hhx3kcv>xd;4zNa z3V5jTW5}?dyboSEWo3ES>EbhVqbA;AU{eo1;kGnbUmpZ>cx|L)Uygm`3eyyv`8bKY z90T(>L7A!J)_6NTJH^0_%ZnCH&iCnIeq$k(H$B>Vf*WagzQ$*9)ZlQ}8)}lxVsIw^d2Nk8wxL|Elq0`xv zO-9ZAvtcG{ex3Gqvq7;!=9Rd>!*WD5$X7T|9J>2smOx8IDx%UCbf`NNdrNhtZW?et zHzVJZ^@rQZ&*D@Y>oz|w3RP_0dRTR@A{&t;B~FbCzBh0)GhJq+rn0ZJp?XSn?N_Pd zC~=veLeyy0j{5>V5xk*bR*F{_$BV5^%=7VuDLN4(e#Qm-0Tj=}v~2tg;Q#Qc5{}}E zy9P2~0GIf!wK<7MYyJ!bCa!vkR5Jvov)SqD9d{z1)+Gs16zJ&?-KQK`U%d>U`M zVzFZK&WCl3z{0maL4%hVXtyrj(izD3Rhn3f>TZJs(?f|5bY)ljSWYA~D{!P6KnS(K zIR9x4Kh+HJ2vQgaI`Hlb*HKBG=TJPon#0Bk54CEFeApn(_-Fr1Phqgrq8XX zzKkBSg~xK-AoS?N9i&+OlatBrf(BQi|Ac6W8RNn%-KY5Jo1@{^r=L4Fw**f!cX~>V zbELND*34^Gcs@E%Vx(58i6cRY9dBk0!R?8Y@5Fxu7C-dEj@H%T8JRBZfql{byIy7^ zm0-Th7bF(VZ@jKy*Loi=$RQyC`jrH$xf_BPlWp`$;FZyn2Rb&(eL<0o3*0Yed&R2# zDo>9ZWe?Loq6^O5SYd&hJ%^*$&QvT(!@{e>#7-RR9X=kdVGh#t=@!~jB;Ba8ZrhNdU?%CzPXze!1t|Uh>vFv>-SI|*;9`9%lm_O)#)b!27 z(|Np@9s6|tCv-A#U=SLsE}^)b#O)*lo_C!X=QF%De?gvFA(CY+*k?C%jo-*`&!FCs4` z+WmOnW%=VuNuyM3V$@tL$F!)j*v z$GRE@G2_?(EBv^CQl|Qk*MVp%P7%)iTb`jUQNWJ-#+02m7S~qA**@X!H(_kpm*hdW z%(#qQHz!Ms09;KU9A#jb;W)EvQzDAFg{gNRL`F>;{Q0Jpz7(V`w}p?6BlP%Wd|X_J zOmempC1@>R)-a=6@L%Ekzt%VZjL`r5dF3Ek`iN4ew%zJAUKx#q_$kP!N>@o42mU_{ Cr+hyE literal 0 HcmV?d00001 diff --git a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java index 9f08a838f86..6513a340408 100644 --- a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java +++ b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java @@ -688,6 +688,7 @@ public GetMessageResult getMessage(final String group, final String topic, final continue; } + // 从CommitLog文件中读取消息 SelectMappedBufferResult selectResult = this.commitLog.getMessage(offsetPy, sizePy); if (null == selectResult) { if (getResult.getBufferTotalSize() == 0) { From d27420be83e4cabef68e04b5583e13086f6b5dcf Mon Sep 17 00:00:00 2001 From: "Jindong.Tian" Date: Sat, 21 Sep 2024 20:54:50 +0800 Subject: [PATCH 18/18] =?UTF-8?q?'=E6=96=B0=E5=A2=9E=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=B3=A8=E9=87=8A'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../broker/offset/ConsumerOffsetManager.java | 1 + .../processor/ConsumerManageProcessor.java | 1 + .../processor/SendMessageProcessor.java | 2 + .../consumer/store/LocalFileOffsetStore.java | 1 + .../store/RemoteBrokerOffsetStore.java | 13 +++ .../ConsumeMessageConcurrentlyService.java | 8 +- .../consumer/DefaultMQPushConsumerImpl.java | 5 + .../ConsumerSendMsgBackRequestHeader.java | 12 ++- .../UpdateConsumerOffsetRequestHeader.java | 13 +++ .../example/quickstart/BroadcastConsumer.java | 98 +++++++++++++++++++ .../rocketmq/example/quickstart/Consumer.java | 2 +- .../rocketmq/example/quickstart/Producer.java | 2 +- 12 files changed, 150 insertions(+), 8 deletions(-) create mode 100644 example/src/main/java/org/apache/rocketmq/example/quickstart/BroadcastConsumer.java diff --git a/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java b/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java index 88ab403097c..0e3f0560bfb 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java @@ -142,6 +142,7 @@ public void commitOffset(final String clientHost, final String group, final Stri } private void commitOffset(final String clientHost, final String key, final int queueId, final long offset) { + // 更新broker内存中消费进度 ConcurrentMap map = this.offsetTable.get(key); if (null == map) { map = new ConcurrentHashMap(32); diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/ConsumerManageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/ConsumerManageProcessor.java index 028d21bf976..8da666e28f2 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/processor/ConsumerManageProcessor.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/ConsumerManageProcessor.java @@ -108,6 +108,7 @@ private RemotingCommand updateConsumerOffset(ChannelHandlerContext ctx, Remoting final UpdateConsumerOffsetRequestHeader requestHeader = (UpdateConsumerOffsetRequestHeader) request .decodeCommandCustomHeader(UpdateConsumerOffsetRequestHeader.class); + // 更新broker中的消费进度 this.brokerController.getConsumerOffsetManager().commitOffset(RemotingHelper.parseChannelRemoteAddr(ctx.channel()), requestHeader.getConsumerGroup(), requestHeader.getTopic(), requestHeader.getQueueId(), requestHeader.getCommitOffset()); response.setCode(ResponseCode.SUCCESS); diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java index 93d4fa722ff..bbfabc8a383 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java @@ -140,6 +140,7 @@ private RemotingCommand consumerSendMsgBack(final ChannelHandlerContext ctx, fin return response; } + // 如果重试队列数量小于等于0,则直接返回成功,说明该消费组不支持重试。 if (subscriptionGroupConfig.getRetryQueueNums() <= 0) { response.setCode(ResponseCode.SUCCESS); response.setRemark(null); @@ -214,6 +215,7 @@ private RemotingCommand consumerSendMsgBack(final ChannelHandlerContext ctx, fin delayLevel = 3 + msgExt.getReconsumeTimes(); } + // 设置延时级别 msgExt.setDelayTimeLevel(delayLevel); } diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java b/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java index ca96bae593e..33c66b9e60f 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java @@ -156,6 +156,7 @@ public void persistAll(Set mqs) { String jsonString = offsetSerializeWrapper.toJson(true); if (jsonString != null) { try { + // 将内存中的广播消费进度存储至磁盘 MixAll.string2File(jsonString, this.storePath); } catch (IOException e) { log.error("persistAll consumer offset Exception, " + this.storePath, e); diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java b/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java index e5d2b6e15eb..9b7f5b07878 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java @@ -38,6 +38,13 @@ /** * 消费进度存储的远程实现。集群消费模式下使用该实现。 + * + * 集群消费模式,当 `RebalanceService` 将 `MessageQueue` 负载到当前客户端时,会调用 + * `org.apache.rocketmq.client.impl.consumer.RebalancePushImpl#computePullFromWhere` + * 方法从broker中获取当前 `MessageQueue` 的消费进度 + * + * RemoteBrokerOffsetStore 会把从broker查询到的消费进度进行缓存,其余时间客户端查询和更新消费进度都是基于内存中的数据, + * 而消费进度的持久化同样是通过定时任务(默认每5s)调用 `RemoteBrokerOffsetStore#persistAll` 将内存中的消费进度通过网络请求写入broker磁盘。 * Remote storage implementation */ public class RemoteBrokerOffsetStore implements OffsetStore { @@ -92,8 +99,10 @@ public long readOffset(final MessageQueue mq, final ReadOffsetType type) { } case READ_FROM_STORE: { try { + // 从broker获取指定MessageQueue当前消费组的消费进度 long brokerOffset = this.fetchConsumeOffsetFromBroker(mq); AtomicLong offset = new AtomicLong(brokerOffset); + // 更新内存中的消费进度 this.updateOffset(mq, offset.get(), false); return brokerOffset; } @@ -115,6 +124,10 @@ public long readOffset(final MessageQueue mq, final ReadOffsetType type) { return -1; } + /** + * + * @param mqs + */ @Override public void persistAll(Set mqs) { if (null == mqs || mqs.isEmpty()) diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyService.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyService.java index 7566761a951..863b5ed9927 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyService.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/ConsumeMessageConcurrentlyService.java @@ -294,7 +294,7 @@ public void processConsumeResult( if (consumeRequest.getMsgs().isEmpty()) return; - // 根据消息监听器返回的结果计算ackIndex + // 根据消息消费结果计算ackIndex switch (status) { case CONSUME_SUCCESS: if (ackIndex >= consumeRequest.getMsgs().size()) { @@ -440,8 +440,7 @@ public void run() { ConsumeConcurrentlyStatus status = null; defaultMQPushConsumerImpl.resetRetryAndNamespace(msgs, defaultMQPushConsumer.getConsumerGroup()); - // 执行消息消费钩子函数ConsumeMessageHook#consumeMessageBefore。通过 - // consumer.getDefaultMQPushConsumerImpl().registerConsumeMessageHook(hook)方法消息消费执行钩子函数 + // 执行消息消费钩子函数ConsumeMessageHook#consumeMessageBefore。通过consumer.getDefaultMQPushConsumerImpl().registerConsumeMessageHook(hook)方法消息消费执行钩子函数 ConsumeMessageContext consumeMessageContext = null; if (ConsumeMessageConcurrentlyService.this.defaultMQPushConsumerImpl.hasHook()) { consumeMessageContext = new ConsumeMessageContext(); @@ -454,6 +453,7 @@ public void run() { ConsumeMessageConcurrentlyService.this.defaultMQPushConsumerImpl.executeHookBefore(consumeMessageContext); } + // 消息消费开始时间 long beginTimestamp = System.currentTimeMillis(); boolean hasException = false; ConsumeReturnType returnType = ConsumeReturnType.SUCCESS; @@ -474,7 +474,9 @@ public void run() { // 若出现异常,则设置未true hasException = true; } + // 消息消费耗时 long consumeRT = System.currentTimeMillis() - beginTimestamp; + if (null == status) { if (hasException) { returnType = ConsumeReturnType.EXCEPTION; diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java index ec915b847b9..c44d9215f68 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java @@ -79,6 +79,9 @@ import org.apache.rocketmq.remoting.common.RemotingHelper; import org.apache.rocketmq.remoting.exception.RemotingException; +/** + * 消费组维度的对象,每一个消费组一个实例 + */ public class DefaultMQPushConsumerImpl implements MQConsumerInner { /** * Delay some time when exception occur @@ -279,8 +282,10 @@ public void pullMessage(final PullRequest pullRequest) { return; } } else { + // 如果是顺序消费 if (processQueue.isLocked()) { if (!pullRequest.isLockedFirst()) { + // 计算需要拉取消息的偏移量 final long offset = this.rebalanceImpl.computePullFromWhere(pullRequest.getMessageQueue()); boolean brokerBusy = offset < pullRequest.getNextOffset(); log.info("the first time to pull message, so fix offset from broker. pullRequest: {} NewOffset: {} brokerBusy: {}", diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java index f823b46e12e..ed6583d2637 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java @@ -24,10 +24,13 @@ public class ConsumerSendMsgBackRequestHeader implements CommandCustomHeader { /** - * 消息物理偏移量 + * 消息物理偏移量,因为需要重试的消息在Broker中本来就有,所以发送重试消息只需要发送消息的物理偏移量即可 */ @CFNotNull private Long offset; + /** + * 消费组名 + */ @CFNotNull private String group; /** @@ -37,15 +40,18 @@ public class ConsumerSendMsgBackRequestHeader implements CommandCustomHeader { @CFNotNull private Integer delayLevel; /** - * 消息ID + * 原消息的消息ID */ private String originMsgId; /** - * 消息topic + * 原消息的topic */ private String originTopic; @CFNullable private boolean unitMode = false; + /** + * 最大重新消费次数,默认16次。 + */ private Integer maxReconsumeTimes; @Override diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/UpdateConsumerOffsetRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/UpdateConsumerOffsetRequestHeader.java index 3f44db645c5..ccebe142903 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/UpdateConsumerOffsetRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/UpdateConsumerOffsetRequestHeader.java @@ -25,12 +25,25 @@ import org.apache.rocketmq.remoting.exception.RemotingCommandException; public class UpdateConsumerOffsetRequestHeader implements CommandCustomHeader { + + /** + * 更新的消费组 + */ @CFNotNull private String consumerGroup; + /** + * 主题名称 + */ @CFNotNull private String topic; + /** + * 队列ID + */ @CFNotNull private Integer queueId; + /** + * 更新的消费进度 + */ @CFNotNull private Long commitOffset; diff --git a/example/src/main/java/org/apache/rocketmq/example/quickstart/BroadcastConsumer.java b/example/src/main/java/org/apache/rocketmq/example/quickstart/BroadcastConsumer.java new file mode 100644 index 00000000000..d98a14a4574 --- /dev/null +++ b/example/src/main/java/org/apache/rocketmq/example/quickstart/BroadcastConsumer.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.example.quickstart; + +import java.util.List; +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; +import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; + +/** + * This example shows how to subscribe and consume messages using providing {@link DefaultMQPushConsumer}. + */ +public class BroadcastConsumer { + + public static void main(String[] args) throws InterruptedException, MQClientException { + + /* + * Instantiate with specified consumer group name. + */ + DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("TopicTest-Broadcast-Consumer"); + + /* + * Specify name server addresses. + *

+ * + * Alternatively, you may specify name server addresses via exporting environmental variable: NAMESRV_ADDR + *

+         * {@code
+         * consumer.setNamesrvAddr("name-server1-ip:9876;name-server2-ip:9876");
+         * }
+         * 
+ */ + consumer.setNamesrvAddr("127.0.0.1:9876"); + /* + * Specify where to start in case the specified consumer group is a brand new one. + */ + consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET); + // 设置为广播消费模式 + consumer.setMessageModel(MessageModel.BROADCASTING); + /* + * Subscribe one more more topics to consume. + */ + consumer.subscribe("TopicTest", "*"); + + /* + * Register callback to execute on arrival of messages fetched from brokers. + */ + consumer.registerMessageListener(new MessageListenerConcurrently() { + + @Override + public ConsumeConcurrentlyStatus consumeMessage(List msgs, + ConsumeConcurrentlyContext context) { + System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs); + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + }); + + + /* + * Register callback to execute on arrival of messages fetched from brokers. + */ + consumer.registerMessageListener(new MessageListenerConcurrently() { + + @Override + public ConsumeConcurrentlyStatus consumeMessage(List msgs, + ConsumeConcurrentlyContext context) { + System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs); + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + }); + + /* + * Launch the consumer instance. + */ + consumer.start(); + + System.out.printf("Consumer Started.%n"); + } +} diff --git a/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java b/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java index 990fbf13e22..df154e54b63 100644 --- a/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java +++ b/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java @@ -35,7 +35,7 @@ public static void main(String[] args) throws InterruptedException, MQClientExce /* * Instantiate with specified consumer group name. */ - DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_4"); + DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("TopicTest-Consumer"); /* * Specify name server addresses. diff --git a/example/src/main/java/org/apache/rocketmq/example/quickstart/Producer.java b/example/src/main/java/org/apache/rocketmq/example/quickstart/Producer.java index eebfd0da1ae..f470c36597f 100644 --- a/example/src/main/java/org/apache/rocketmq/example/quickstart/Producer.java +++ b/example/src/main/java/org/apache/rocketmq/example/quickstart/Producer.java @@ -31,7 +31,7 @@ public static void main(String[] args) throws MQClientException, InterruptedExce /* * Instantiate with a producer group name. */ - DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name"); + DefaultMQProducer producer = new DefaultMQProducer("TopicTest-Producer"); /* * Specify name server addresses.