技术专栏——你所不知道的 RocketMQ 的集群管理:副本机制

这些精彩的技术类型的体系化文章,后面我会放到公众号上,并集中在合集“分布式消息中间件专栏”中,欢迎大家去订阅我的公众号和视频号“架构随笔录”,大家可以订阅合集,这样更加方便喔,后面会出电子版本,更加方便。另外本人也出版过“Spring Cloud Alibaba微服务架构实战派上下册”的技术类书籍,另外新书“RocketMQ分布式架构实战派”即将上架。

RocketMQ 是阿里巴巴中间件团队开源出来的高可用、高性能和高并发的分布式消息中间件,也是在调研了行业生态中主流的消息中间件之后决定自研。Kafka 不能满足金融和电商业务场景对低延迟和高可靠性方面的变态要求,ActiveMQ 在队列以及主题达到上限之后,资源 I/O 又是瓶颈。早期的 RocketMQ 的集群管理只支持主从,也就是 Master-Master 或者 Master-Slave,从新版本 4.5.0 开始支持多副本机制。

本文主要内容包括:

  • RocketMQ 主从集群管理原理

  • RocketMQ 多副本集群管理原理

  • 如何灵活应用 RocketMQ 集群管理的方法论

Chat 内容不在多,在于如何说清楚需要讨论的问题,本文适合对 RocketMQ 有一定了解的技术工程师、技术专家以及架构师。

本篇集群管理主要针对 Broker 端。

RocketMQ集群入门

集群角色

  • ASYNC_MASTER

  • SYNC_MASTER

  • SLAVE

ASYNC_MASTER 是同步 Master 节点,SYNC_MASTER 是异步 Master 节点,SLAVE 是从节点。如果对消息的可靠性和可用性要求比较严格,可以采用 SYNC_MASTER 加 SLAVE 的部署方式。如果对消息可靠性要求不高,可以采用 ASYNC_MASTER 加 SLAVE 的部署方式,提升 Producer 和 Consumer 的吞吐量。

如果只是运维部署方便,则可以选择仅 ASYNC_MASTER 或仅 SYNC_MASTER 的部署方式,也就是多个 Master 组成集群,当某一个 Master 挂了之后,数据就完全丢失了,没有备份。

集群如何启动

4.7.1-SNAPSHOT 版本集群启动方式:

1. 首先启动 Name Server 集群 nohup sh mqnamesrv &,这个命令会直接启动类 NamesrvStartup,通过 main 函数完成初始化,从而启动 NamesrvController,并加载全局配置文件 NamesrvConfig,配置文件会默认加载 namesrv 文件目录下的文件——kvConfig.json 和 namesrv.properties 文件,前者存储 kv 数据,后者存储当前节点的集群信息。

2. 然后启动 Broker,例如启动集群中的某一个节点:

nohup sh mqbroker -n 192.168.1.1:9876 -c $ROCKETMQ_HOME/conf/2m-noslave/broker-a.properties &

这里只是举例子,也就是 RocketMQ 启动的属性文件,需要自己手动在启动命令中输入,现在还没法做到动态,当然你可以通过 RocketMQ 的后端控制台,简单修改一些属性。

RocketMQ主从集群管理原理

4.5.0 版本之前的 RocketMQ 的 Name Server 和 Broker 端的集群数据是怎么管理的呢?

Name Server 端集群管理

Name Server 集群环境初始化

org.apache.rocketmq.namesrv.NamesrvStartup

NamesrvStartup 包含一个 main() 函数。熟悉 Java 的都知道,通过 main 函数启动的类,可以传入 jvm 级别的系统属性到当前启动的应用,例如:kvConfig.json 和 namesrv.properties。

  1. 初始化环境变量:日志和属性等。

  2. 实例化 NamesrvController,绑定属性文件到对应的实例。

  3. 启动 NamesrvController,包括:资源初始化和线程开启。

org.apache.rocketmq.namesrv.NamesrvController

这个类是整个集群的核心类,它会绑定整个集群启动所需要的所有的资源。

构造函数传入资源包括:NamesrvConfig、NettyServerConfig、KVConfigManager、RouteInfoManager、BrokerHousekeepingService 和 Configuration。

  • NamesrvConfig 包含全局配置:RocketMQ 安装目录、kvConfigPath 存储路径、configStorePath 存储路径、productEnvName、clusterTest 和       orderMessageEnable 等。

  • NettyServerConfig 包含 Name 端的 Netty RPC 的配置信息。

  • KVConfigManager 对 kvConfig.json 进行管理。

  • RouteInfoManager 管理整个集群的路由信息。

Name Server 路由管理 

路由管理主要的服务边界是:

  • topicQueueTable:主要维护 topic 和 List<QueueData> 的映射关系,初始化容量大小 1024;

  • brokerAddrTable:主要维护 brokerName 和 BrokerData 的映射关系,初始化容量大小 128;

  • clusterAddrTable:主要维护 clusterName 和 Set<String/* brokerName */> 的映射关系,初始化容量大小 32;

  • brokerLiveTable:主要维护 brokerAddr 和 BrokerLiveInfo 的映射关系,初始化容量大小 256;

  • filterServerTable:主要维护 brokerAddr 和 List<String>/* Filter Server */ 的映射关系,初始化容量大小 256。

这里又涉及到一个关于 HashMap 的知识点,由于一个主题对应的消息队列在一个虚拟机上理论上是有限制的,但是又可以有很多个,所以设定初始化 topicQueueTable 容量为 1024;集群中的 Broker 的数量肯定不会很多,很多都不会超过 2 位数,所以 brokerAddrTable 容量就为 128;集群名称和 brokerName 的映射关系会更少,所以 clusterAddrTable 的容量为 32,后面的容量规划其实也都一样,都会结合场景来初始化。

Name Server 路由管理,在整个集群管理的角色场景如下:

适配层的核心类是 NettyRemotingServer、DefaultRequestProcessor、NettyRemotingAbstract 和 NettyRemotingClient,那么从领域模型的角度去分析 这个两个类,提供了哪些领域能力(在集群管理这个核心域下面)。

DefaultRequestProcessor

  • 通过 NettyRemotingServer.registerDefaultProcessor(),与 NettyRemotingServer 发生子域关联关系,当 NettyRemotingServer 在处理所有的 RPC 请求时,会判断如果模块请求没有注册 NettyRequestProcessor 类型,就会默认走 DefaultRequestProcessor 逻辑。

  • 其实 DefaultRequestProcessor 主要是封装了 RouteInfoManager 和 KVConfigManager 的能力,统一对外暴露给 NettyRemotingServer,这个也体现了设计模式中的,单一职责原则了依赖反转原则。

DefaultRequestProcessor 具体封装了如下能力:

能力点能力描述能力实现点
RequestCode.PUT_KV_CONFIG设置 key-value 存储文件getKvConfigManager().putKVConfig()
RequestCode.GET_KV_CONFIG获取 key-value 存储文件getKvConfigManager().getKVConfig()
RequestCode.DELETE_KV_CONFIG删除 key-value 存储文件getKvConfigManager().deleteKVConfig()
RequestCode.QUERY_DATA_VERSION查询数据的版本号getRouteInfoManager().queryBrokerTopicConfig()
RequestCode.REGISTER_BROKER注册 BrokergetRouteInfoManager().registerBroker()
RequestCode.UNREGISTER_BROKER取消注册 BrokergetRouteInfoManager().unregisterBroker()
RequestCode.GET_ROUTEINTO_BY_TOPIC根据 Topic 信息获取路由信息getRouteInfoManager().pickupTopicRouteData()
RequestCode.GET_BROKER_CLUSTER_INFO获取 Broker 端的集群信息getRouteInfoManager().getAllClusterInfo()
RequestCode.WIPE_WRITE_PERM_OF_BROKER获取 Broker 的读、写以及继承的权限getRouteInfoManager().wipeWritePermOfBrokerByLock()
RequestCode.GET_ALL_TOPIC_LIST_FROM_NAMESERVER获取所有的主题信息getRouteInfoManager().getAllTopicList()
RequestCode.DELETE_TOPIC_IN_NAMESRV删除主题信息getRouteInfoManager().deleteTopic()
RequestCode.GET_KVLIST_BY_NAMESPACE根据命名空间获取 key-value 信息getKvConfigManager().getKVListByNamespace()
RequestCode.GET_TOPICS_BY_CLUSTER根据**cluster 信息获取主题信息getRouteInfoManager().getTopicsByCluster()
RequestCode.GET_SYSTEM_TOPIC_LIST_FROM_NS获取系统默认的主题信息getRouteInfoManager().getSystemTopicList()
RequestCode.GET_UNIT_TOPIC_LIST获取单元的 topic 信息getRouteInfoManager().getUnitTopics()
RequestCode.GET_HAS_UNIT_SUB_TOPIC_LIST获取子单元的 topic 信息getRouteInfoManager().getHasUnitSubUnUnitTopicList()
RequestCode.GET_HAS_UNIT_SUB_UNUNIT_TOPIC_LIST获取 hash 单元的子单元的主题信息getRouteInfoManager().getHasUnitSubUnUnitTopicList()
RequestCode.UPDATE_NAMESRV_CONFIG更新 NameServer 端的配置信息getConfiguration().update()
RequestCode.GET_NAMESRV_CONFIG获取 NameServer 端的配置信息getConfiguration().getAllConfigsFormatString()

NettyRemotingAbstract

具备的核心能力:

  • 封装 processMessageReceived 方法,并通过这个方法融合 NettyRemotingServer.NettyServerHandler 和 NettyRemotingClient.NettyClientHandler,这两个类会处理 REQUEST_COMMAND 和 RESPONSE_COMMAND 两种类型的 Netty 事件。

  • 当处理 REQUEST_COMMAND 事件的时候,就会融合 DefaultRequestProcessor 的能力,这样基于 Name Server 的集群路由能力就和 Broker 端融合了。

  • 那么 Consumer、Producer 和 DefaultRequestProcessor 怎么融合,这个其实还涉及到适配的过程。

 MQClientInstance 其实就是消费者、生产者和 Name Server 融合的关键类,也是和集群间的路由管理相融合的关键类。我在这里只讨论路由管理是怎么融合的,具体更加细节的类的实现,其实主要要看 MQClientAPIImpl 类。

Broker端集群管理

Broker 端集群管理,主要是针对集群之间数据同步问题,也就是集群之间如何保证分布式场景下的 CP 和 AP 模式。4.5.0 版本之前的 RocketMQ 如何管理整个 Broker 集群。

  • 多 Master 零 Slave 模式

  • 多 Master 多 Slave 同步模式

  • 多 Master 多 Slave 异步模式

熟悉 RocketMQ 的人都知道,它是靠 brokerId 是否为 0 来标志 Master 节点,非 0 为 Slave 节点。多 Master 零 Slave 模式,就意味着每个节点都具备读写能力,其实这样对于集群管理的可靠性要求还是蛮高的。

场景如下,三个节点 BrokerA,BrokerB 和 BrokerC,节点角色都是 Master,生产者是多实例 ProducerInstanceA,ProducerInstanceB,ProducerInstanceC,消费者也是多实例 ConsumerInstanceA,ConsumerInstanceB 和 ConsumerInstanceC。生产者发送 topic 为 loginDetail 的消息,消息队列为 16 个,由于是 3 主无从模式,那么就意味着集群要维护 48 个队列,这个 48 个队列都具备读写能力,负载均衡为平均负载,就这么一个场景,3 主模式下,集群如何运转才能保持稳定性。

生产者和消费者如何区分多实例?

生产者和消费者在初始化的时候(调用 start 方法),会通过 MQClientManager.getOrCreateMQClientInstance,去创建 MQClientInstance,并存储在当前虚拟机的内存中,也就是说针对同一个 JVM 的同一个生产者和消费者的实例理论上只有一个。但是如果我们自己定义多个生产者和消费者,并且 MQClientInstance 的去重的要素,添加一些特殊标识,这样也能做到不同的生产者和消费者对应不同的实例,其实 RocketMQ 官方是不建议这样做的,这样会增加很大的性能开销。
MQClientInstance 去重要素:

  • clientIP:客户端 IP,可以自定义

  • InstanceName,实例名称,可以自定义

  • unitName,单元名称,可以自定义

生产者如何关联主题以及对应的队列?

生产者注册到生产者组,注意不能重复;消息主题现在一般都是直接和消息对象关联,生产者不直接创建主题;消息发送的时候,会根据 topic 去 NameServer 端,查询主题信息,是否已经被注册以及主题信息是否绑定路由关系(队列和 Broker 的映射关系),注意这个是多对多的绑定关系。

生产者如果不指定队列数,默认 readQueueNums 和 writeQueueNums 都是 16,这里还是有一个疑问,topic 什么时候和队列绑定?既然 topic 是在发送消息的时候主动创建的,那么队列的创建以及和 topic 的绑定是否也是在消息发送期间操作的?

通过通读源码,我发现绑定关系也是在消息发送期间操作,并且只操作一次,就存储在内存和文件中了,具体方法入口见 TopicConfigManager.createTopicInSendMessageMethod(),从方法名字就知道,创建主题是在发送消息期间发生的,创建主题的过程中就会通过 readQueueNums 和 writeQueueNums 参数或者是生产者指定的队列数,来创建队列以及和 topic 绑定,注意这里是线程安全的,因为加了可重入锁。还是要注意,这里的 TopicConfigManager 属于 Broker 域,所以这些数据就直接落地到了 Broker 端的内存中,然后再落地到文件中,在根目录下面就会多出一个 topics.json 文件。

Broker 又如何关联 nameServer 以及 topic 和队列?

Broker 会发起向 NameServer 注册的 RPC 请求,具体请参考 RouteInfoManager.registerBroker() 方法逻辑,具体细节逻辑这里就不细讲。里面有一个细节,就是只有当注册到 nameServer 端的 Broker 为 Master 时,才会去执行 createAndUpdateQueueData() 逻辑,去更新 topic 和队列的绑定关系。

消费者如何关联主题以及对应的队列?

和生产者一样,消费者也会注册到 MQClientInstance 对应的生产者组,注意不能重复。执行消费会经历如下逻辑:订阅主题、添加监听器和消费者 start(),消费者和主题的映射关系是在订阅阶段会添加,主题与队列的映射关系在消息发送阶段,在生产者端就会完成映射绑定关系,并推送给 NameServer 以及各个 Broker 集群节点,新增一个消费者客户端实例,就会完成一次集群消费者注册事件的心跳通知,这个和生产者的逻辑一样。

如上图,生产者在生产消息的时候,会默认创建 16 个读队列和 16 个写队列,那么如果 Broker master 的节点数为 3,就会在每个 Broker 上创建 16 个队列,那么总共就有 48 个队列。通过平均负载均衡,对消息队列进行算法排序,并均摊到消费者实例上,注意这里的消费者实例的去重维度是靠 clientID,也就是 MQClientInstance,不是消费者服务的节点数,因为有可能一个消费者服务节点,会存在多个 clientID,这样设计是为了达到消费线程隔离的效果。

多 Master 零 Slave 模式下分配的 48 个队列都具备读写能力,这样会提高生产者的消费者的吞吐量和性能,但是会增加 Broker 数据一致性维护的资源成本,如果使用这种模式,Broker 节点需要较高的配置,才能真正的发挥多 Master 零 Slave 模式设计的目标。

多 Master 零 Slave 模式下数据一致性都是同步模式,其实这样也会增加一定的开销,但是我们自己想想,如果都是 master 就意味着数据肯定是强一致性的,不能容忍数据丢失。

多 Master 多 Slave 同步模式,比如二主二从模式,这样两个 master 具备读写能力,然后相对应地从节点具备读(也就是消费的能力)。

RocketMQ多副本集群管理原理(@since 4.5.0)

多副本集群管理主要针对 Broker 端的存储模块,这个是 4.5.0 之后引入的提升集群存储性能和可用性的新特性,这个和 Kafka 存储的副本机制有点类似,在没有这个功能之前,RocketMQ 集群存储只支持主从,维度为节点,但是有了副本机制之后,存储的维度被细化为副本,这样就从冗余的角度,增强了数据的可用性。

任何一个集群管理功能都需要入口,那么多副本的入口就是 DLedgerCommitLog 类,注意这个是集成在存储模块中的,作用等同于 CommitLog。

重点来了,既然是多副本集群管理,那么 RocketMQ 的分布式选举算法是什么?这里笔者深度 review 了一下,算法是基于 Raft 算法,关于这个算法的逻辑,请参考笔者的另外一篇文章——《调侃面试官,分布式选举算法 Raft 在 Nacos 中的应用》,西面我们也来分析算法具体落地的逻辑及场景。

副本机制核心类实现分析:

  • DLedgerCommitLog 存储所有元数据便于停机时数据的恢复,提高数据的可靠性。

  • DLedgerServer 分布式选举服务端核心类。

  • DLedgerRpcNettyService 分布式选举服务端通信 RPC 类

  • DLedgerLeaderElector 分布式选举算法封装类

  • MemberState 选举节点的状态机类

  • DLedgerMemoryStore 基于内存存储的核心类

  • DLedgerMmapFileStore 基于文件存储的核心类

  • DLedgerClient 分布式选举客户端核心类

  • DLedgerClientRpcNettyService 分布式选举客户端通信 RPC 类

下面重点分析下 RocketMQ 的 Raft 算法的实现过程,算法选举核心类是 DLedgerLeaderElector,存储端启动会自动的加载这个类,初始化并开启选举线程,选举角色有如下几种:

  • UNKNOWN

  • CANDIDATE

  • LEADER

  • FOLLOWER

初始化 Broker 节点默认为 CANDIDATE,开启之后就开始选举和心跳,走 Raft 选举逻辑。

1. 读取配置文件中的 HeartBeatTimeIntervalMs(心跳间隔时间)、MaxHeartBeatLeak(心跳允许超时的次数)、MinVoteIntervalMs(最小投票间隔时间)和 MaxVoteIntervalMs(最大投票间隔时间)。

2. 开启 maintainState() 方法,开始选举。

3. 在没有选举出 Leader 节点之前,默认都是 CANDIDATE,执行 maintainAsCandidate():

private void maintainState() throws Exception {        if (memberState.isLeader()) {            maintainAsLeader();        } else if (memberState.isFollower()) {            maintainAsFollower();        } else {            maintainAsCandidate();        }    }

4. 判断当前系统时间和 nextTimeToRequestVote 对比的大小,以及 needIncreaseTermImmediately 的取值,如果“当前系统时间 <nextTimeToRequestVote”并且“needIncreaseTermImmediately=false”,就直接返回,选举直接结束,说明集群 Leader 节点还没到换届时间。

5. 选举状态机:VoteResponse.RESULT 和 VoteResponse.ParseResult,这里先列举几个状态机元素,比如 RESULT.REJECT_ALREADY_HAS_LEADER(投票被拒绝,因为已经有 Leader 节点了),还有很多这里就不列举了。

6. 投票过程,也是批量投票,包含当前节点,如果是当前节点,就直接调用 handleVote(),处理选举投票逻辑,如果是集群中的其他节点,就会调用 Netty-RPC 服务通知其他的节点,注意这里的通信机制是复用的原有 RocketMQ 的通信客户端 NettyRemotingClient 和服务端 NettyRemotServer。

这里还有一个小细节,从 4.5.0 开始,平台专门封装了一个针对存储多副本机制的集群模块 dledger 包,这个独立打包的,并且可以被其他中间件复用的。

下面在来说下集群选举核心方法——handleVote(),这个是处理投票逻辑的,怎么处理?首先如果被投票的节点,在当前参与选举的节点列表中不存在,就会被废弃当前选举,选举不合法,候选人不在大名单中。如果不是自己给自己投票,但是被投票的候选人又和当前节点一样,也会被废弃选票;如果被投票的 Term 都小于当前节点的 Term,那么本次选举也会被废弃,经过一系列的逻辑处理之后,会设置当前节点的状态机 memberState 的 CurrVoteFor 属性为 Leader 节点。

下面来分析下核心方法——sendHeartbeats。

在 Raft 算法中,心跳是一种非常重要的通信手段。心跳只能从 Leader 节点发出,FOLLOWER 节点被动的接收心跳包;Leader 节点会包装心跳请求信息,包括:Group、LocalID、RemoteId、LeaderId、Term 等,并通过 RPC 发出。

节点处理心跳,处理心跳的逻辑又封装在 DLedgerServer.handleHeartBeat() 方法中,最终处理心跳的还是 DLedgerLeaderElector.handleHeartBeat()。处理心跳逻辑,又会做很多逻辑校验,会判断当前请求的 Term 和当前处理心跳逻辑节点的 Term:

  • 如果 request.getTerm() < memberState.currTerm(),就会返回 403 错误——EXPIRED_TERM。

  • 如果相等,又会判断当前节点是否已经获取到了 Leader 确认的信息。

  • 如果还没确认,那就修改当前节点的状态为 Follower,作为心跳请求的宿中包含主节点的从节点。

  • 如果心跳请求中的 Leader 节点和当前节点已经确认的 Leader 节点一样,会记录 lastLeaderHeartBeatTime 时间为当前系统时间,说明 Leader 节点已经按时的发送了一次心跳,Follower 已经确认接收了,返回成功的心跳响应。

  • 如果当前请求的“Term>当前节点中的 Term”,说明 Leader 的服务周期已经结束,需要重新选举,然后变更当前节点的状态为 Candidate,开启选举。

那么 RocketMQ 的副本机制又是怎么合选举算法关联起来的呢?这里又得说说这个类了 DLedgerEntryPusher,这个类是和存储相关的类,里面就应用了选举算法的场景。

  • 定义线程 EntryHandler,这个线程会被 Follower 激活,接收文件的 push 请求。

  • 定义线程 QuorumAckChecker。

  • 定义线程 EntryDispatcher。

  • 在执行文件的 Append 操作之前都会校验当前节点是否是 Leader 节点,也就是说只有 Leader 节点才有追加文件的权限。

 如何灵活应用RocketMQ集群管理的方法论

RocketMQ 集群管理非常灵活,在一些不需要强一致性的场景,比如路由管理,采用的 AP 理论-也就是内存 + 数据通过 RPC 同步,其实也就是数据的最终一致性。那么针对存储,采取的是强一致性,4.5.0 版本之前采用主从模式,之后采用基于 Raft 的分布式选举算法(CP 模型),其实这些都是结合场景的,至少在集群管理方面,因为对于存储节点的集群数据访问的控制,肯定是需要强一致性的。

那么对于我们业务而言,我们怎么应用他的集群管理的方法论了,我觉得可以从如下几点落地:

  • 如果我们是在做数据服务,但是又不想过多的依赖分布式组件,比如 ZooKeeper 或者 DB 等,我们就可以利用内存+集群数据同步,保证数据的一致性和高性能。

  • 如果我们在做缓存操作的时候,又需要保证数据的强一致性,因为缓存的场景很苛刻,比如商品库存的缓存,这样我们就可以使用公用的 Raft 算法保证强一致性。

  • 如果我们需要改造定时任务,从单机变成分布式,需要具备分布式能力,但是又要保证性能,就可以使用 Raft 算法替换比较重的分布式算法。

  • 自研中间件,需要选型分布式算法,可以考虑参考 RocketMQ 的实现。

在工作中我们要想快速地提升技术能力,就得先熟悉比较成熟的商业组件的原理,然后再寻找业务场景,快速的将框架的精髓在业务中落地。

总结

方法论有很多,但是只有当能在业务中落地,并能体现价值的时候,才是好的方法论,我在文章的末尾和大家共勉,希望和大家一起能够更深的提升我们的技术视野,并能够快速地变现为生产力,为我们的业务以及我们自己的职业生涯服务。

欢迎关注本人的技术微信公众号:架构随笔录。

另外我的新书RocketMQ消息中间件实战派上下册,在京东已经上架啦,目前都是5折,非常的实惠。

https://item.jd.com/14337086.html​编辑https://item.jd.com/14337086.html

RocketMQ消息中间件实战派上下册”是我既“Spring Cloud Alibaba微服务架构实战派上下册”之后,又一本历时超过1年半的巨无霸技术实战类型的书籍。

为了提高读者阅读本书的体验性,本书总共设计了十个特色,下面我一一的给技术小伙伴阐述一下。 

【特色一】由浅到深

本书将RocketMQ的技术原理和最佳实践体系化,按照由浅到深的顺序呈现给读者,使读者可以按照章节顺序按部就班地学习。当学习完全书内容之后,读者不仅能熟悉RocketMQ的核心原理,还能充分理解RocketMQ的“根”。

【特色二】技术新

本书不仅包括RocketMQ4.x4.9.2版本)的核心原理分析和最佳实践,还包括RocketMQ5.x5.1. 0版本)的新特性分析和最佳实践。

【特色三】精心设计的主线:零基础入门,循序渐进,直至彻底掌握RocketMQ

本书精心研究了程序类、架构类知识的认知规律,全书共分为6篇:基础;进阶;高级;高并发、高可用和高性能;应用;新特性,是一条相对科学的主线,让读者快速从“菜鸟”向“RocketMQ分布式架构实战高手”迈进。

【特色四】绘制了大量的图,便于读者理解RocketMQ的原理、架构、流程 

一图胜于文,书中在涉及原理、架构、流程的地方配有插图,以便读者更加直观地理解。

【特色五】从架构师和技术专家的视角分析RocketMQ 

本书创造性地分析了RocketMQ具备高并发、高可用和高性能的功能及原理,并从架构的视角展开分析,这些也是程序员进阶为技术专家或架构师必备的技能。

以下为从架构师和技术专家的视角分析RocketMQ典型案例,读者阅读完本书之后,也能够达到这样的水准。

【特色六】不仅有原理分析,还有大量的实战案例 

本书介绍了大量的实战案例,能让读者“动起来”,在实践中体会功能,而不只是一种概念上的理解。

在讲解每一个知识模块时,我在思考:在这个知识模块中,哪些是读者必须实现的“标准动作”(实例);哪些“标准动作”是可以先完成的,以求读者能快速有一个感知;哪些“标准动作”具有一定难度, 需要放到后面完成。读者在实践完书中的案例之后,就能更容易理解那些抽象的概念和原理了。

本书的目标之一是,让读者在动手中学习,而不是“看书时好像全明白了,一动手却发现什么都不会”。通过体系化的理论和实战案例去培养读者的主动学习能力,这样本书的价值就会被最大化。 

本书相信“知行合一”的理念,而不是“只知,而不行”,避免开发人员出现眼高手低的现象。尤其是在技术面试过程中,面试官更加看重的是既懂原理,又能够主动是实践技术的技术人。

【特色七】深入剖析原理 

 本书以系统思维的方式,从业务功能视角剖析 RocketMQ 底层的技术原理,使读者具备快速阅读 RocketMQ 框架源码的能力。读者只有具备了这种能力,才能举一反三,实现更复杂的功能,应对更复杂的应用场景。

 【特色八】从运维的视角分析 RocketMQ 的最佳实践

【特色九】参与开源 

 本书向读者展示了如何修改 RocketMQ 源码,并快速验证案例分析。这样,读者可以从中学到参与开源的技能,并为后续自己能够参与开源做准备。

【特色十】双色印刷,读者体验会更好 

为了提高读者阅读本书的体验,在有上下两册的前提下(巨无霸,超过800页),出版社不吝啬印刷成本,依然采用双色印刷。

【推荐】本书的最佳学习路径 

 为了提高读者学习RocketMQ的效率,我这边结合我自身从RocketMQ小白到RocketMQ专家的经历,为读者汇总了一条最佳学习路径。

【寄语】作者寄语 

RocketMQ是我深度参与研究的一款开源消息中间件,无论是从源码,还是架构场景,我都提炼了很多最佳实践。

在开源领域,技术小伙伴可以使用的开源消息中间件非常的多,比如KafkaPulsar等,我之所以选择研究RocketMQ,除了工作内容和角色需要之外,更多的还是自己感兴趣,因此我建议技术小伙伴一定要先培养自己的兴趣,兴趣才是提升技术硬实力的第1要素。

当然我并不止研究了RocketMQ,还研究了PulsarKafka等(包括开源消息中间件生态中的主流框架),只是本书作为一本关于RocketMQ实战派的书籍,我必须要以RocketMQ为主。

假如技术小伙伴想成为Java领域的架构师或者技术专家,我强烈建议你去研究RocketMQ,它会给你带来很多意想不到的技术和架构方法论的收获,这个也是我写本书的主要目的之一。

建议技术小伙伴按照本书设计的学习路线,逐章的去阅读和实战,这样学习效果会更好。

如果技术小伙伴有技术交流的,可以通过博文视点官方的读者群找到我的联系方式,并与我沟通,我会实时的解答读者的疑问。

本文公众号“架构随笔录”

本人视频号“架构随笔录”

【博文视点】2021年度优秀作者

2021年我和博文视点合作了一本技术类型的书籍“Spring Cloud Alibaba微服务架构实战派上下册”,它是我涉足知识输出领域以来的第一本书,同时它也是我自己积累的技术池中部分技术的产出。

为了写好那本书,我几乎花费了所有的休息时间,并主动的承担了书的售后技术辅导和咨询的职责(几乎是有问必答,坚持了整整两年)。

所谓有付出总会有回报,Alibaba这本书的销量还不错,我也因此获得了博文视点颁发的2021年度优秀作者。

我很清楚,这个是博文视点为了鼓励我继续去用心写书,因此我又花了接近1年半的时间去写了RocketMQ消息中间件实战派上下册这本书。

所谓一分耕耘一份收获,我将我对RocketMQ的理解体系化的输出给喜欢技术的技术人,希望真的对大家有帮助。

 【博文视点】2023技术成长领路人

2022年,我开始涉足技术直播和技术讲师领域,并和博文视点合作几次技术直播,直播效果还不错,再加上我孜孜不倦的布道“Spring Cloud Alibaba微服务架构实战派上下册”这本书相关的技术,并且这些技术都是有助于“技术人”快速成长的,因此也获得了博文视点颁发的“2023技术成长领路人”这个技术奖项,这个奖项也是为了鼓励我继续通过技术直播的方式给技术人去布道技术,因此只要我有时间,我就会孜孜不倦的去讲和聊技术。

【四维口袋】2022 KVP最具价值技术专家 

2022年,我开始涉足企业培训和相关技术直播,并和“四维口袋”合作了几次技术直播,并荣获了2022 KVP最具价值技术专家的技术奖项。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/315797.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

电脑上不安装Oracle,但是虚拟机装了Oracle,怎么连接到虚拟机里的Oracle数据库呢?

1、准备工作 1.1、确定数据库版本信息 注&#xff1a;如果知道数据库的版本信息&#xff0c;这个步骤可以跳过。 比较简单的方法&#xff0c;直接看数据库的安装位置&#xff0c;也就是数字&#xff08;但是这个方法确定就是&#xff0c;不好确定是多少位的数据库&#xff09;…

AI智能分析网关V4烟火检测算法解决方案

一、背景需求 根据国家消防救援局公布的数据显示&#xff0c;2023年共接报处置各类警情213.8万起&#xff0c;督促整改风险隐患397万处。火灾危害巨大&#xff0c;必须引起重视。传统靠人工报警的方法存在人员管理难、场地数量多且分散等问题&#xff0c;无法有效发现险情降低…

微信小程序(二)事件绑定

注释很详细&#xff0c;直接上代码 新增内容&#xff1a; 点击事件绑定注册页面设置页面初始化数据事件处理函数的实现更新数据并更新视图 源码&#xff1a; index.wxml <!-- 页面的数据绑定 --> <view>{{msg}}</view> <!-- 绑定点击事件 --> <but…

openssl3.2 - 官方demo学习 - cipher - aesgcm.c

文章目录 openssl3.2 - 官方demo学习 - cipher - aesgcm.c概述笔记END openssl3.2 - 官方demo学习 - cipher - aesgcm.c 概述 AES-256-GCM 在这个实验中验证了EVP_CIPHER_fetch()中算法名称字符串的来源定位. 在工程中配置环境变量PATH, 且合并环境. 这样就不用将openSSL的D…

【Python】编程练习的解密与实战(四)

​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《Python | 编程解码》⏰诗赋清音&#xff1a;云生高巅梦远游&#xff0c; 星光点缀碧海愁。 山川深邃情难晤&#xff0c; 剑气凌云志自修。 目录 &#x1fa90;1. 初识Python &a…

Spring Boot - Application Events 的发布顺序_ApplicationStartedEvent

文章目录 Pre概述Code源码分析 Pre Spring Boot - Application Events 的发布顺序_ApplicationEnvironmentPreparedEvent 概述 Spring Boot 的广播机制是基于观察者模式实现的&#xff0c;它允许在 Spring 应用程序中发布和监听事件。这种机制的主要目的是为了实现解耦&#…

linux 服务器上安装 ftp(亲测有效)

目录 1 需求2 安装 1 需求 服务器上需要安装ftp 2 安装 1 下载地址 https://developer.aliyun.com/packageSearch?wordvsftpd或者 https://rpmfind.net/linux/rpm2html/search.php?queryvsftpd2 如何判断 服务器是否安装了ftp rpm -qa | grep vsftpd出现提示则表示已安装…

什么是国密算法

国密算法是指由中国国家密码管理局发布的密码算法标准&#xff0c;旨在保障国家信息安全。目前&#xff0c;国家密码管理局已发布了一系列国产商用密码标准算法&#xff0c;包括SM1&#xff08;SCB2&#xff09;、SM2、SM3、SM4、SM7、SM9以及祖冲之密码算法&#xff08;ZUC)等…

thinkphp学习09-数据库的数据新增

单数据新增 使用 insert()方法可以向数据表添加一条数据&#xff0c;更多的字段采用默认 public function index() {$data [username > 犬夜叉,password > 123,gender > 男,email > wjl163.com,price > 999,details > 犬夜叉介绍];echo Db::name(user)-&g…

【教学类-43-18】A4最终版 20240111 数独11.0 十宫格X*Y=Z套(n=10),套用没有分割行列的A4横版模板

作品展示&#xff1a; 撑满格子的10宫格数独50%难度 50空 背景需求&#xff1a; 大4班有3位男孩做9宫格数独&#xff08;81格子&#xff0c;30%难度 24空&#xff09;非常娴熟&#xff0c;我观察他们基本都在10分钟内完成&#xff0c;其中一位男孩把九宫格题目给我看时表达自…

android 13.0 Launcher3长按app弹窗设置为圆角背景功能实现二

1.前言 在13.0的系统ROM定制化开发中,在进行一些Launcher3的定制化开发中,在使用app的弹窗的功能时,会弹出应用信息和 微件之类的内容,所以在定制需求中,需要默认设置为圆角背景,接下来就来分析下相关功能的实现如图: 2.Launcher3长按app弹窗设置为圆角背景功能实现二的…

【目标检测】评价指标:混淆矩阵概念及其计算方法(yolo源码)

本篇文章首先介绍目标检测任务中的评价指标混淆矩阵的概念&#xff0c;然后介绍其在yolo源码中的实现方法。 目标检测中的评价指标&#xff1a; mAP概念及其计算方法(yolo源码/pycocotools) 混淆矩阵概念及其计算方法(yolo源码) 本文目录 1 概念2 计算方法 1 概念 在分类任务中…

rime中州韵小狼毫 汉语拼音输入方案

在word中&#xff0c;我们可以轻易的给汉字加上拼音&#xff0c;如下&#x1f447;&#xff1a; 但是&#xff0c;如何单独的输入拼音呢&#xff1f;例如输入 pīn yīn, 再如 zhōng guō。今天我们分享一个使用rime中州韵小狼毫须鼠管输入法配置的输入汉语拼音的输入方案。功…

WPS - 表格虚线变成实线解决方案(Office 同上)

1、选中表格区域&#xff0c;在表格中选中需要调整为实线的表格区域 2、点击设置单元格格式&#xff0c;鼠标进行右击并点击设置单元格格式选项 3、选择实线&#xff0c;在单元格格式下的边框&#xff0c;调整到实线 4、设置为实线&#xff0c;即可将表格的虚线设置为实线

(ros2)gazebo颜色设置

在gazebo当中不用再设置颜色了&#xff0c;因为完全可以使用urdf的设置 <robot name"base" xmlns:xacro"http://wiki.ros.org/wiki/xacro"><xacro:property name"PI" value"3.1415926"/><!--定义一个变量PI&#xff0…

研发日记,Matlab/Simulink避坑指南(三)——向上取整Bug

文章目录 前言 背景 问题 排查 解决 总结 前言 见《研发日记&#xff0c;Matlab/Simulink避坑指南&#xff08;一&#xff09;——Data Store Memory模块执行时序Bug》 见《研发日记&#xff0c;Matlab/Simulink避坑指南(二)——非对称数据溢出Bug》 背景 在一个嵌入式软…

vi/vim 编辑器 --基本命令

1 vi/vim编辑器介绍 vi 是visual interface 的简称&#xff0c;是Linux中最经典的文本编辑器 vim是vi的加强版。兼容了vi的所有指令&#xff0c;不仅能编辑文本&#xff0c;而且具有shell程序编辑的功能&#xff0c;可以通过不同颜色的字体辨别语法的正确性&#xff0c;极大…

七麦数据js逆向(补环境版)

本文目标地址如下&#xff0c;使用base64解码获得 aHR0cHM6Ly93d3cucWltYWkuY24vcmFuay9tYXJrZXRSYW5rL21hcmtldC82L2NhdGVnb3J5LzUvY29sbGVjdGlvbi9hbGwvZGF0ZS8yMDI0LTAxLTEy 本文逆向破解分为扣代码版和补环境版&#xff0c;扣代码版请看专栏另一篇文章 废话不多说了&#…

Docker 安装以及加速器配置

通常我们因为安装docker出现许多错误&#xff0c;使用解压版安装方便快捷&#xff0c;并且增加加速器的配置&#xff0c;以及可视化界面的配置&#xff0c;让我们的成长更近了一步 1. 虚拟机网络配置 虚拟机使用nat模式&#xff0c;配置ens33如下&#xff1a; TYPEEthernet P…

15 个适用于 Windows 的 PDF 解锁工具大全

PDF&#xff08;便携式文件格式&#xff09;是一种文件格式&#xff0c;用于呈现和交换任何独立于任何软件、硬件或操作系统的可靠访问的文档。Adobe 发明了它&#xff0c;但现在它是由国际标准化组织 (ISO) 维护的开放标准。因此&#xff0c;您现在必须了解这些 PDF 解锁工具。…