消息队列深入剖析(上)
Posted JudyGirl
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了消息队列深入剖析(上)相关的知识,希望对你有一定的参考价值。
本文章内容为自己对NX知识点理解
王雪芬
前言
消息队列在分布式架构中的作用
主流消息队列选型对比分析
RocketMQ深入剖析
消息队列的使用场景
消息队列: 在消息的传输过程中保存消息的容器,生产者和消费者不直接通讯,依靠队列保证消息的可靠性,避免了系统间相互影响.
消息队列主要角色:
1 服务端: MQ Server
2 客户端: 生产者Producer,订阅者Consumer
Topic1和Topic2理解为两个主题,例如一个买的队列,另一个是卖的队列
应用场景
以核心模块和运营活动举例说明, 假如运营活动可能需要在核心业务逻辑中添加临时的运营活动,所以会经常对核心业务逻辑做修改, 给核心模块带来很大的风险
最开始的架构,Logic里面包含了核心业务逻辑和运营活动业务.这就是我们所以耦合高,依赖性强.
举一个栗子, 当天交易满3笔送5元红包
1查库存减一并且锁库存 , 2下订单 , 3查看订单的数量是否满3笔 , 4 给用户送红包
在业务没有拆分的时候跟上图的架构一样, 当我们利用MQ把拆分核心订单模块和运营活动模块,如果用上MQ做消息中间件, 这时就实现了解耦合, 运营出现问题的时候,不会连累到主模块
举第二个栗子,IM系统实现
对于核心基础服务,可能各个业务线都会关注某些请求处理结果,假如图中v4不在线了,我们需要通过微信去通知,这个时候如果频繁改也不好.所以更改架构,使用MQ.
东哥举了一个列子说, 之后有很多业务系统需要使用IM进行消息发送,例如图书, 卖家不在线, 推荐一个活跃商家商品, 把业务放到扩展业务里处理.
从上面图中我们会发现发送微信等业务模块或有很多业务功能它需要对接所有业务,下面是改造把消息都放到MQ中,然后进行广播, 这个消息对每一个业务线都发一次, 这样图书模块可以自己处理自己的业务逻辑
消息队列的主要作用
1 业务解耦
2 异步调用
3 流量削峰
业务解耦
将模块之间的RPC调用改为通过消息队列中转, 接触系统间的耦合
1 提示系统稳定性
2 通过广播消息避免多次调用
3 提高编码效率
东哥问: 可否完全替代RPC, 可以替代 , 但是存在风险,如果MQ挂了,则服务都不能使用, 但是RPC是集成在内部模块的,所以也只是自己的服务不能使用, 但是其他服务可以调用与自己无关的服务
异步调用
对于无需关注调用结果的场景,可以通过消息队列异步处理, 下单业务优化
1 风控拦截
2 扣减库存
3 通知卖家
4 记录数据
可以看出红色部分是与订单业务没有关系的,因为订单业务已经完成,所以这里我们可以使用mq来减少链路太长
更改为:
1 风控拦截
2 扣减库存
3 异步通知卖家
4 异步记录数据
流量削峰
系统的吞吐量与底层存储服务能力成正比, 数据访问层可以调整缓解存储服务压力,避免短暂的高峰将系统压垮
1 mq 接受消息
2 放回一个不确定的状态码
3 当用户在刷新页面的时候进行rpc调用查看是否消费成功
队列选型对比
可靠性对比
功能对比
我用文字描述一下:
1 都支持顺序性
2 只有RocketMQ支持事物消息
3 消息过滤kafaka和rocketMQ支持
4 消息查询只有RocketMQ支持
5 批量发送只有kafaka支持
kafaka针对的是系统间的数据流通道
RocketMQ; 高性能可靠消息传输
RabbitMQ: 可靠消息传输
RocketMQ深入剖析
整体架构
首先看一下拓扑图: Name Server存储Broker信息, Producr跟Name server拉取信息, 然后 访问具体的 Broker , Consumer也一样需要注册到 Name Server 然后访问具体Broker.
再看一下RocketMQ架构图
消息存储
CommitLog: 存储消息主体
ConsumeQueue: 消息消费队列
IndexFile:消息索引文件:在读取的时候根据索引找队列
minoffset:消费最小位置
consumeroffset:下次拉取的地方
maxOffset:最大消息位置,如果有新的则添加
顺序写,随机读 ,性能优化
1 CommitLog文件切换, 默认1G
2 MMap 提升文件访问性能
3 SSD
特性分析
可靠性存储
1 同步刷盘: 由于是性能不高,但是可靠性高
2 异步刷盘: 由于是异步所以性能高, 但是可靠性低
消息消费
消息消费一般分为pull和push两种方式
push:消息队列主动的将消息推送给消费者,这种情况消息实时性比较高,但是没有考虑客户端是否有足够的消费能力
pull: 由消费者客户端主动向消息队列拉取消息,这种情况消息实时性低,可能会带来很多无效请求, 因为实时性低,所以为了提供实时性,我们拉取频率变高,所以导致有很多无效请求。
对于RocketMq来说Push相等于PUll+长轮训方式
消息消费方式
1集群消费:集群内竞争消费,单条消息只消费一次,各节点均匀消费topic消息,不会重复消费。
2广播消费:各集群消费全量的消息,单条消息在每个集群都会被消费一次
负载均衡
Product端负载均衡
1定时从NameSpace中获取信息,存放到Proudct队列中
2Product根据负载均衡算法选出某一个队列信息
3如果该队列一直没有响应设置超时时间则换下一个队列
Consumer端负载均衡
保障队列消费合理的分配给Consumer
1 前提客户端会上报自己的心跳
2 20s定时负载均衡
2.1 从NamSpace获取队列信息和Consumer信息
2.2 队列和Consumer排序和平均分配
消费失败
策略:1 如果consumer消费失败则重试16次,创建重试retry队列, 2 重试时间可以间隔递增, 3 如果超过16次则进入死信队列人工处理。
东哥讲了一个案例我感觉还不错, 如果一个mq服务端对应很多consumer,如果一条信息有问题,那么consumer都会往回返数据,假如这个时候创建重试队列, 则假如只有一个Consumer消费重试队列,这个是时候Consumer QPS会很大。
以上是关于消息队列深入剖析(上)的主要内容,如果未能解决你的问题,请参考以下文章
面试官心理分析+面试题剖析:消息队列+Redis 缓存+分布式系统等