如果RabbitMQ集群只有一个broker节点,那么该节点的失效将导致整个服务临时性的不可用,并且可能会导致message的丢失(尤其是在非持久化message存储于非持久化queue中的时候)。可以将所有message都设置为持久化,并且使用持久化的queue,但是这样仍然无法避免由于缓存导致的问题:因为message在发送之后和被写入磁盘并执行fsync之间存在一个虽然短暂但是会产生问题的时间窗。通过publisher的confirm机制能够确保客户端知道哪些message已经存入磁盘,尽管如此,一般不希望遇到因单点故障导致服务不可用。
如果RabbitMQ集群是由多个broker节点构成的,那么从服务的整体可用性上来讲,该集群对于单点失效是有d性的,但是同时也需要注意:尽管exchange和binding能够在单点失效问题上幸免于难,但是queue和其上持有的message却不行,这是因为queue及其内容仅仅存储于单个节点之上,所以一个节点的失效表现为其对应的queue不可用。
为了提高程序的吞吐量,保持消息的可靠性,一台机器挂了后,RabbitMQ能够正常生产,消费消息。
rabbitmq有三种模式:单机模式,普通集群模式,镜像集群模式
Demo级别的,一般只是本机测试玩玩而已,生产环境下不会用的。
在多台机器上启动多个rabbitmq实例,每个机器启动一个。
但是你创建的queue,只会放在一个rabbtimq实例上,但是每个实例都同步queue的元数据(存放含queue数据的真正实例位置)。消费的时候,实际上如果连接到了另外一个实例,那么那个实例会从queue所在实例上拉取数据过来。
示意图
这种方式确实很麻烦,也不怎么好,没做到所谓的分布式,就是个普通集群。
普通集群的方式,确实达到了消息的高可用,但没办法保证可靠性,没做到分布式,简而言之,只是一个普通的集群。
这种模式,才是所谓的rabbitmq的高可用模式,跟普通集群模式不一样的是,你创建的queue,无论元数据还是queue里的消息都会存在于多个实例上,然后每次你写消息到queue的时候,都会自动把消息到多个实例的queue里进行消息同步。
上图中每个节点有一个queue,生产者生产完毕数据后投递到指定交换机的队列,交换机的队列进行消息同步。
每个节点queue都有一个完整的rabbitmq节点,所以这种方式叫做镜像集群
好处: 任何一个节点宕机后,其它节点不受影响,正常使用
坏处:
确保机器中安装了Docker,若未安装,可看:云原生Docker入门 – 阿里云服务器Linux环境下安装Docker
查看拉取的镜像
成功运行
设置节点1
浏览器输入 您的ip地址:15673
再次测试即可成功~
File —> New —> Project —> Maven —> 直接Next 进入下一步创建普通的Maven工程即可
创建一个默认的Maven聚合工程,将src文件夹删除,该工程就是一个Maven聚合工程
引入依赖如下:
在项目内,新建一个Moudle,rabbitmq-order-producer 默认Maven工程,下一步即可
在项目内,新建一个Moudle,rabbitmq-order-cousumer 默认Maven工程,下一步即可
Maven聚合工程创建完成图
Maven依赖图
自行手写MainApplication即可
创建完成!
编写完成!
启动消费者
交换机
=
15674
15675
成功消费数据!
已成功同步消息~
RabbitMQ, Kafka, rocketMQ等数据可以百度查到QMQ的开发者又谈到QMQ的性能和rocket的性能处于同一个数量级
Kafka和RocketMQ都是基于partition的存储模型, 也就是每一个subject分成一个或者多个partition, 同时consumer消费的时候也是和partition一一对应的
如下 :
在这种设计的模式下, 如果consumer数目大于partition的数据, 就会出现consumer处于空闲的状态
如果partition数据大于consumer的数据就会出现部分consumer繁忙的状况
以上是用基于partition去做负载均衡所带来的问题 由于这种静态绑定的关系, 如果遇到了消费速度更不上消费的速度, 单单的增加consumer是不够的 需要增加partition 尤其是在kafka里, partition是一个比较重的资源, 增加太多的partition还需要考虑集群的处理能力; 同时当高峰期过了之后, 如果想缩容consumer也是比较麻烦的, 因为partition只能增加, 不能减少
上述设计, 同时带了另一个问题, 就是如果有消息积压, 我们增加partition也是没有用的, 因为消费已经挤压到已存在的partition中, 新增partition只能够消费新分配过来的数据
以上是QMQ的存储模型, 方框上方的数字代表该方框自己在log中的偏移量, 方框中的数据代表该项的内容 如何message log上方的3,6,9表示这几条消息在message log中的偏移量 而consume log中方框内的数据3,6,9,20对应着message log的偏移, 表示这几条消息都在topic1中, consume log 方框上方的1,2,3,4代表这几个方框在consume log中的逻辑偏移 下面的pull log 方框中的1,2,3,4对应着consume log的逻辑偏移, 而pull log方框外的数字表示pull log的逻辑偏移
message log 是所有消息的主存储体, 所有topic的消息都进入该log
consume log 存储的是message log的索引
pull log 每个consumer拉取消息的时候会产生pull log, pull log 记录的是拉取消息在consume log中的sequence
这个时候消费者就可以使用pull log上的sequence来表示消费的进度, 这样一来我们就解耦了consumer和partition之间的耦合关系 两者可以任意扩展
分片 + 复制
QMQ不是基于partition的, 可以通过增加更多的机器提高一个topic的可用性 消息按照一定的负载均衡策略, 分配到不同的机器上, 某台机器离线之后, producer将不再将消息发送到server
QMQ通过主从复制来提高单机高可用 QMQ将服务器划分为过个group, 每一个group都包含多个master和slave, 消息的发送和消费全部指向master, slave只保证可用性
一般的消息分为At Most Once, At Least Once, Exactly once 而最后一种属于我们最期望的一种模型, 同时这种模型的实现也不容易 由于网络和应用依赖的复杂性, Exactly once基本不可行, 但是我们可以通过幂等处理来实现最终的Exactly once
QMQ中用到的HashWheelTimer是采用Netty得HashWheelTimer实现的。
如上面的这个图, 假设时间轮大小为8(这个轮子底层用了一个数组实现的) 1s转动一格, 每一格指向一个链表, 这个链表保存着待执行的任务(TimeOutTask)
参考 :
>
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)