消息队列RocketMQ(一)

消息队列RocketMQ(一)

消息队列应用分析

消息队列: 在消息的传输过程中保存消息的容器,生产者和消费者不直接通讯,依靠队列保证消息的可靠性,避免消息间的相互影响(例如避免雪崩)。

消息队列主要角色

服务端

客户端:

  1. 生产者(Producer)

  2. 订阅者(Consumer)

应用场景

场景1

运用活动可能需要在业务逻辑中各个环节加入运营活动逻辑,而且有时效性,频繁在正常业务逻辑中添加/删除代码显然不合理且风险极大。例如各种送红包活动,有时效性,然后每次添加或者删除这个活动我们都需要修改logic层的核心代码,如下图的框架。

所以我们应对这种问题通常会引入一个MQ,不管用户起什么请求,logic都会发一个mq消息,然后起一个运营的Business logic来消费消息,他自己也有数据访问层,访问运用所用到的数据。这样即使Business logic即使挂掉了也不影响核心逻辑。

场景2

核心基础服务,可能各个业务线都会关注某些请求处理结果,不断修改代码添加业务线的通知显然不合理。

如下图电商IM系统就实现了业务解耦。

消息队列的主要作用:

  1. 业务解耦:

将模块间的RPC调用改为通过消息队列中转,解除系统间的耦合:提升系统稳定性,通过广播消息避免多次调用,提高编码效率。

  1. 异步调用(RPC异步和MQ异步不一样,RPC异步必须收到结果,MQ是纯异步,可以不需要结果):

对于无需关调用记过的场景可以通过消息队列异步处理。

  1. 流量削峰:

系统的吞吐量往往取决于底层存储服务的处理能力,数据访问层可以调整消费速度缓解存储服务压力,避免短暂的高峰将系统压垮。

例如:

我们可以很容易横向拓展Logic和Data Access,而DB的扩展就非常困难(分库分表,数据路由),制约性能的就是DB,所以需要MQ减少DB的压力,也减少了对Logic的QPS需求。

思考:

使用消息队列能带来很大的收益,但也会对系统架构造成一些负面影响(系统可用性,架构复杂度,排查问题路径),消息队列不能完全代替rpc,需要合理设计业务调用。

高可用及高拓展解决方案剖析

RocketMQ功能特性:

支持事务型消息

支持延时消息

支持消息重发

支持consumer端tag过滤

支持消息回放(比如push出错了没有给用户成功推送,我们就可以用消息回放进行重新消费然后push)

RocketMQ拓扑图:

Name Server(类似注册中心)

Broker

Producer

Consumer

producer从name sever拉取特定topic的broker的路由信息,然后producer就可以跟broker进行连接了,发送消息,consumer也是如此,指定特定的topic从name server拉去路由信息,然后连接broker,消费特定topic的消息。

通过增加broker即可分布式扩容。

consumer既连接Master又连接slave不是为了读写分离,而是为了可靠性,之后我会详解。

RocketMQ架构

Broker主从部署,自身消息注册在NameServer中

Client从NameServer中获取Broker信息

NameServer节点相互独立,无数据交互:

因为Broker数量少,所以我们不需要做NameServer间的数据同步,仅需要Broker给NameServer通过广播的方式定时发心跳,然后就算一开始失败,经过几次心跳后也可以完成同步。

可靠性分析:

同步刷盘:性能低可靠性高。

异步刷盘:性能高可靠性低。

异步复制(主从):提高可靠性,不丢失性能。

同步双写(主从):可靠性最高,但牺牲性能。

 

官方文档关于可靠性的解释:

RocketMQ支持消息的高可靠,影响消息可靠性的几种情况:

  1. Broker非正常关闭
  2. Broker异常Crash
  3. OS Crash
  4. 机器掉电,但是能立即恢复供电情况
  5. 机器无法开机(可能是cpu、主板、内存等关键设备损坏)
  6. 磁盘设备损坏

1)、2)、3)、4) 四种情况都属于硬件资源可立即恢复情况,RocketMQ在这四种情况下能保证消息不丢,或者丢失少量数据(依赖刷盘方式是同步还是异步)。

5)、6)属于单点故障,且无法恢复,一旦发生,在此单点上的消息全部丢失。RocketMQ在这两种情况下,通过异步复制,可保证99%的消息不丢,但是仍然会有极少量的消息可能丢失。通过同步双写技术可以完全避免单点,同步双写势必会影响性能,适合对消息可靠性要求极高的场合,例如与Money相关的应用。注:RocketMQ从3.0版本开始支持同步双写。

可用性分析

主从模式Master宕机:

这个Broker就会变得可读不可写(Slave还可以被继续消费)

集群搭建方式:

  1. 单Master模式

  2. 多Master模式(一个Master挂了,可以访问另一个Master,多Master也提高了存储量和吞吐量)

  3. 多Master多Slave模式-异步复制(提高了可靠性,一个Masker挂了后,Consumer可以继续把这个Slave的消息消费掉,然后Provider不在写入这个挂掉的Master,改为写入另一个master(比如两个Master本来各处理provider的百分之50,现在一个挂了,没挂的就处理百分之一百的))

  4. 多Master多Slave模式-同步双写

以上就是分布式方案(Mysql没有路由模块,需要业务解决分布式问题,所以Mysql是一个单机数据库)

RocketMQ存储原理

CommitLog:存储消息主体(生产者的负载均衡将生产的消息分配到ConsumeQueue中)

ConsumerQueue:消息消费队列(存的是在CommitLog里的索引信息,RocketMQ不丢消息考的就是minOffset;Consumer可以一次拉去一批消息,消费完后批量的会一批ACK,但也使RoketMQ有重复消费的问题,对于重复消费有严格要求的时候,我们需要做幂等处理)

IndexFile:消息索引文件

由RocketMQ的模型我们可以看到,RocketMQ有着顺序写随机读的问题。

优化手段

  1. CommitLog文件切分,默认1G

  1. MMap提升文件访问性能(类似于零拷贝,我们读写一个文件,我们会经历用户态到内核态的切换,实现Read和Write操作,例如我们读的时候会先拷贝到内核空间,然后再拷贝到用户空间,写的时候也同理。MMap其实就是用户态跟内核态进行了映射,我们操作用户态的文件实质是操作内核态的文件,从而减少内核态和用户态的数据交换。)

  2. SSD(机械硬盘实际上已经足够)

生产方式

同步(sync)

异步(async)

单向(oneway)

消息消费由两种方式:

Push:消息队列主动地将消息推送给消费者(实时性高,但没有考虑客户端的消费能力)。

Pull:由消费者客户端主动向消息队列拉取消息(实时性低,可能造成大量无效请求)。

RocketMQ消费模式

RocketMQ地消费方式相当于拉模式,但是使用了长轮询机制,来平衡Push和Pull地缺点

LongPoll:

  1. Consumer发送拉去信息

  2. Broker hold住请求,直到有新消息再返回

  3. 请求超时,Consumer再次发起请求

  4. 请求超时默认三十秒

消息消费方式

集群消费:集群内竞争消费,单条消息只消费一次,各节点均匀消费Topic的消息。

组广播消费:各集群消费全量的消息,单条消息在每个集群都会被消费一次。

RocketMQ通常使用Group内竞争,Group间广播对queue的消息进行消费 

posted @ 2020-12-10 22:21  皎皎白驹  阅读(270)  评论(0)    收藏  举报