《RocketMQ实战与原理解析》是一本详细介绍了RocketMQ的技术原理和实践应用的书籍。书中包括了RocketMQ的架构、消息的生产和消费、消息的存储和传输、集群管理等内容。通过阅读本书,可以深入了解RocketMQ的实现原理及其在分布式系统中的应用。
《RocketMQ实战与原理解析》读后感(一)
这本书,
1.宣传册图片上貌似很厚,其实只有150多页;
2.标价59元,也不便宜了;
3. 阿里巴巴所谓的专家,原以为要讲一点实战比较多的东西,多少有点启发,结果是一个初学者指南,对阿里巴巴的所谓专家表示非常失望。就当自己网上买的长个记性了:-(
这么几页书能说什么呢?还卖这么贵。差评!
买这本书1-2个小时左右就可以翻完,还真不如官网看一下手册和例子来得实在,各位看客不要再上当了。
《RocketMQ实战与原理解析》读后感(二)
1到7章作者本意是想介绍基础,但是一些基础概念没解释清楚,又需要有一定前置知识的人读,定位有些尴尬。
第8章开始往后就没什么内容,写成几篇博客质量可以,出书有点勉强。
另外160页书定价59,横向对比一下有些偏贵。
不过还是很佩服作者,能在工作的同时完成一本书,也是付出很多努力和很强的执行力,感谢分享的知识。
《RocketMQ实战与原理解析》读后感(三)
比较适合初学者,可以对整体功能有一个较完整的理解,同时会对内部实现有一些思考。如果能够从设计的角度更多的讲解下内部的架构,以及消息转发的完整流程,多个分支情况等就更好了。
下面是我的简单总结,可以参考!=> 《Rocket-MQ总结》
《RocketMQ实战与原理解析》读后感(四)
RocketMQ广泛应用于交易、数据同步、缓存同步、IM通讯、流计算、IoT等场景。
第1章 快速入门
多个低错误率的子系统强耦合在一起,得到的是一个高错误率的整体系统。
1、应用解耦
2、流量消峰
3、消息分发
2007年Notify到2010年的Napoli,2011年升级后改为MetaQ,然后到2012年开始做RocketMQ,RocketMQ使用Java语言开发。
Notify主要使用了推模型,解决了事务消息。
MetaQ主要使用了拉模型,解决了顺序消息和海量堆积的问题。
RocketMQ基于长轮询的拉取方式,兼有两者的优点。
RocketMQ:Java
Kafka:Scala
RabbitMQ:Erlang
第2章 生产环境下的配置和使用
功能与现实生活中的邮政收发信件很类似。
现实生活中的邮政系统要正常运行,离不开下面这四个角色,一是发信者(Producer),二是收信者(Consumer),三是负责暂存、传输的邮局(Broker),四是负责协调各个地方邮局的管理机构(NameServer)。
启动RocketMQ的顺序是先启动NameServer,再启动Broker。
为了消除单点故障,增加可靠性或增大吞吐量,可以在多台机器上部署多个NameServer和Broker,为每个Broker部署一个或多个Slave。
不同类型的消息以不同的Topic名称区分。
发送和接收消息前,先创建Topic,针对某个Topic发送和接收消息。
【性能问题】
一个Topic要发送和接收的数据量非常大,需要能支持增加并行处理的机器来提供处理速度,这时候一个Topic可以根据需求设置一个或多个Message Queue,Message Queue类似分区或Partition。
Topic有了多个Message Queue后,消息可以并行地向各个Message Queue发送,消费者也可以并行地从多个Message Queue读取消息并消费。
【配置参数介绍】
fileReservedTime = 48
在磁盘上保存消息的时长,单位是小时,自动删除超时的消息。
flushDiskType = ASYNC_FLUSH
刷盘策略,分为SYNC_FLUSH和ASYNC_FLUSH两种,分别代表同步刷盘和异步刷盘。
listenPort = 10911
Broker监听的端口号
【多机集群配置和部署】
两台物理机,搭建双主、双从、无单点故障的高可用RocketMQ集群。
第3章 用适合的方式发送和接收消息
消费者可分为两种类型
1、DefaultMQPushConsumer,由系统控制读取操作,收到消息后自动调用传入的处理方法来处理。
2、DefaultMQPullConsumer,读取操作中的大部分功能由使用者自主控制。
Consumer的GroupName用于把多个Consumer组织到一起,提高并发处理能力,GroupName需要和消息模式(MessageModel)配合使用。
RocketMQ支持两种消息模式:Clustering和Broadcasting
1、在Clustering模式下,同一个ConsumerGroup(GroupName相同)里的每个Consumer只消费所订阅消息的一部分内容,同一个ConsumerGroup里所有的Consumer消费的内容合起来才是所订阅Topic内容的整体,从而达到负载均衡的目的。
2、在Broadcasting模式下,同一个ConsumerGroup里的每个Consumer都能消费到所订阅Topic的全部消息,也就是一个消息会被多次分发,被多个Consumer消费。
Push方式是Server端接收到消息后,主动把消息推送给Client端,实时性高。对于一个提供队列服务的Server来说,用Push方式主动推送有很多弊端,首先是加大Server端的工作量,进而影响Server的性能,其次,Client的处理能力各不相同,Client的状态不受Server控制,如果Client不能及时处理Server推送过来的消息,会造成各种潜在问题。
Pull方式是Client端循环地从Server端拉取消息,主动权在Client手里,自己拉取到一定量消息后,处理妥当了再接着取。Pull方式的问题是循环拉取消息的间隔不好设定,间隔太短就处在一个“忙等”的状态,浪费资源,每个Pull的时间间隔太长,Server端有消息到来时,有可能没有被及时处理。
长轮询方式通过Client端和Server端的配合,达到既拥有Pull的优点,又能达到保证实时性的目的。
长轮询的核心是,Broker端HOLD住客户端过来的请求一小段时间,在这个时间内有新消息到达,就利用现有的连接立刻返回消息给Consumer。
长轮询的主动权还是掌握在Consumer手中,Broker即使有大量消息积压,也不会主动推送给Consumer。
长轮询方式的极限性,是在HOLD住Consumer请求的时候需要占用资源,它适合用在消息队列这种客户端连接数可控的场景中。
DefultMQPushConsumer的流量控制
第4章 分布式消息队列的协调者
对于一个消息队列集群来说,系统由很多台机器组成,每个机器的角色、IP地址都不相同,而且这些信息是变动的。在这种情况下,如果一个新的Producer或Consumer加入,怎么配置连接信息呢?
NameServer的存在主要是为了解决这类问题,由NameServer维护这些配置信息、状态信息、其他角色都通过NameServer来协同执行。
NameServer可以部署多个,相互之间独立,其他角色同时向多个NameServer机器上报状态信息,从而达到热备份的目的。NameServer本身是无状态的,也就是说NameServer中的Broker、Topic等状态信息不会持久化存储,都是由各个角色定时上报并存储到内存中的。
集群状态的存储结构
1、topicQueueTable,存储了所有Topic的属性信息,QueueData里存储着Broker的名称、读写queue的数量、同步标识等。
2、BrokerAddrTable,一个Master Broker和多个Slave Broker的地址信息。
3、ClusterAddrTable,存储的是集群中Cluster的信息,结果很简单,就是一个Cluster名称对应一个由BrokerName组成的集合。
4、BrokerLiveTable,存储Broker机器的实时状态,包括上次更新状态的时间戳,NameServer会定期检查这个时间戳,超时没有更新就认为这个Broker无效了,将其从Broker列表里清除。
5、FileterServerTable,过滤服务器,一个Broker可以有一个或多个Filter Server。
为何不用Zookeeper
Zookeeper是Apache的一个开源软,为分布式应用程序提供协调服务,那为什麽RocketMQ要自己造轮子,开发集群的管理程序?
答案是Zookeeper的功能很强大,包括自动Master选举等,RocketMQ的架构设计决定了它不需要进行Master选举,用不到这些复杂的功能,只需要一个轻量级的元数据服务器就足够了。
中间件对稳定性要求很高,RocketMQ的NameServer只有很少的代码,容易维护,所以不需要再依赖另一个中间件,从而减少整体维护成本。
底层通信机制
RocketMQ是基于Netty库来完成RemotingServer和RemotingClient具体的通信实现的,Netty是个事件驱动的网络编程框架,它屏蔽了Java Socket、NIO等复杂细节,用户只需用好Netty,就可以实现一个“网络编程专家+并发编程专家”水平的Server、Client网络程序。
第5章 消息队列的核心机制
消息存储与发送
分布式消息队列因为有高可靠性的要求,所以数据要通过磁盘进行持久化存储。
用磁盘存储消息,速度会不会很慢呢?能满足实时性和高吞吐量的要求吗?
磁盘的速度完全可以匹配上网络的数据传输速度。目前高性能磁盘,顺序写速度可以达到600MB/s,超过了一般网卡的传输速度。
但是磁盘随机写的速度只有大概100KB/s。
一台服务器把本机磁盘文件的内容发送到客户端,一般分为两个步骤:
1、read,读取本地文件内容
2、write,将读取的内容通过网络发送出去
这两个简单的操作,实际上进行了4次数据复制,分别是:从磁盘复制数据到内核态内存,从内核态内存复制到用户态内存,
然后从用户态内存复制到网络驱动的内核态内存,最后网络驱动的内核态内存复制到网卡中进行传输。
消息存储结构
存储结构怎样?如何尽量保证顺序写?
RocketMQ消息的存储是由ConsumerQueue和CommitLog配合完成的,消息真正的物理存储文件是CommitLog,ConsumeQueue是消息的逻辑队列,类似数据库的索引文件,存储的是指向物理存储的地址。每个Topic下的每个Message Queue都有一个对应的ConsumeQueue文件。
CommitLog以物理文件的方式存放。
一个消息的存储长度是不固定的,RocketMQ采取一些机制,尽量向CommitLog中顺序写,但是随机读。ConsumeQueue的内容也会被写到磁盘里做持久存储。
存储机制这样设计有以下几个好处:
1、CommitLog顺序写,可以大大提高写入效率。
2、虽然是随机读,但是利用操作系统的pagecache机制,可以批量地从磁盘读取,作为cache存到内存中,加速后续的读取速度。
3、为了保证完全的顺序写,需要ConsumeQueue这个中间结构,因为ConsumeQueue里只存偏移量信息,所以尺寸是有限的,在实际情况中,大部分的ConsumeQueue能够被全部读入内存,所以这个中间结构的操作速度很快,可以认为是内存读取的速度。
第6章 可靠性优先的使用场景
顺序消息:全局顺序、部分顺序
重复消费问题
解决消息重复有两种方法:第一种方法是保证消费逻辑的幂等性(多次调用和一次调用效果相同),另外一种方法是维护一个已消费消息的记录,消费前查询这个消息是否被消费过。
消息优先级
RocketMQ是个先入先出的队列,不支持消息级别或者Topic级别的优先级。业务中简单的优先级需求,可以通过间接的方式解决。
第7章 吐吞量优先的使用场景
提高Consumer处理能力
1、提供消费并行度
在同一个ConsumerGroup下,可以通过增加Consumer实例的数量来提高并行度,通过增加机器,或者在已有机器中启动多个Consumer进程都可以增加Consumer实例数。
注意总的Consumer数量不要超过Topic下Read Queue数量。
2、以批量方式进行消费
3、检测延时情况,跳过非重要消息
Consumer的负载均衡
提供Producer的发送速度
发送一条消息出去要经过三步
1、客户端发送请求到服务器
2、服务器处理该请求
3、服务器向客户端返回应答
一次消息的发送耗时是三个步骤的总和。
提高发送速度的方法
1、可以采用Oneway方式发送,写入客户端的Socket缓冲区就返回,时间到微秒级
2、增加Producer的并发量,使用多个Producer同时发送,不用担心多个Producer同时写会降低消息写磁盘的效率,RocketMQ引入了一个并发窗口,在窗口内消息可以并发地写入DirectMem中,然后异步地将连续一段无空洞的数据刷入文件系统当中。
第8章 和其他系统交互
SpringBoot、Spark、Flink等交互。
第9章 首个Apache中间件顶级项目
作为一个中间件产品,想真正用好,甚至用来为自己的业务做定制化开发,必须深入了解源码才行。
第10章 NameServer源码解析
阅读源码的时候,很多人喜欢根据执行逻辑,先从入口代码看起。
第11章 最常用的消费类
并发处理会增大实现流量控制、保证消息顺序方面的难度。
第12章 主从同步机制
Master和Slave角色的Broker之间同步信息功能,需要同步的信息分为两种类型,实现方式各不相同:
1、元数据信息,采用基于Netty的command方式来同步消息
2、commitLog信息,同步方式是直接基于Java NIO来实现。
第13章 基于Netty的通信实现
Netty架构总览
Netty主要分成三部分:
1、底层的零拷贝技术和统一通信模型
2、基于JVM实现的传输层
3、常用协议支持