异步处理——Queue
-
异步处理 Asynchronous
- 将耗时的同步任务 改成 异步处理,可单独建立排队机制,慢慢取出并外包给多个worker去计算,实现扩展性,就叫 asynchronous
- 通过 消息队列 Queue 这种结构实现
-
好处
- 系统间解耦,主任务 不必依赖于 其他任务 同步完成
- 其他任务通过队列外包给worker延后处理,使得系统对用户的响应时间下降,吞吐量提升
- 可以进一步实现并行
-
漏斗模型
- 消息队列就像一个漏斗,用来控制流量和流速
- 汹涌而至的消息,从敞口流入,经过缩口,以固定速率输出给消费者
- 如果生产速率始终大于消费速率,就会在漏斗中累积,最终溢出,导致消息丢失
- 这种现象称为 Back pressure(反向压力)
- 此时可以限制队列大小,排满了就返回503,让生产者稍后重试
- 所以只有生产速率只是短期大于消费速率的情况下,漏斗才有意义,形成流量削峰的效果
- 消息队列就像一个漏斗,用来控制流量和流速
-
常用的消息队列组件
- RabbitMQ
- 使用比较多,一直在更新优化,github关注10K
- Erlang语言开发的
- 主要用于对时延敏感的在线业务场景,可利用丰富的消息类型支持多变的业务
- RocketMQ
- 阿里开源的,可以使用云服务,github关注17K,已入驻Apache
- java语言开发的,阅读源码方便
- Kafka
- github关注22K
- Scala语言开发,阅读也比较方便
- 主要用于可接受一定时延的日志收集或者业务数据埋点上报,可利用批处理提高吞吐量,做到单机10万级以上
- ActiveMQ(不建议)
- 比较老,不活跃
- java语言开发的
- RabbitMQ
-
三个角色
- 生产者
- 对外的应用程序,往队列里发布任务,并告知用户其状态
- 消费者
- 工作的worker,拿到任务执行,完成后通知
- Broker
- 从队列中取出并分发任务,保证任务的完整性,包括失败重试,动态调整分发策略
- 生产者
-
两种模式
- 推模式
- Broker收到消息后,通过长连接通道主动推送给Consumer
- 优点
- 实时性强
- 客户端实现简单,只需要监听就行
- 缺点
- 容易导致客户端消息堆积,无法自主可控
- 服务端逻辑变得复杂,需要优化推送策略,考虑不同客户端的消费能力去分发
- 拉模式
- Consumer主动向Broker索要消息
- 不能用定时拉取,时长不好控制
- 可以采用长轮询
- 客户端发起索要请求
- 如果服务端有数据就直接返回
- 如果没数据,就保持连接一定时间,这段时间如果有数据就接收
- 超时后,重新发起索要请求
- 客户端发起索要请求
- 优点
- 不会出现消息堆积,自主可控
- 长轮询的实时性也可以保证
- 服务端逻辑简化
- 缺点
- 客户端实现复杂
- 推模式
-
如何设计一个消息队列
-
需要服务端,主要角色是消息的接收者,即Broker
- 1、消息写入磁盘持久化,防止消息丢失
- 设计存储格式
- 设计提交日志和检查点
- 2、考虑主从设计
- 主节点数据同步给从节点,出问题后从节点顶上
- 同时从节点可提供读操作
- 3、考虑分片到多台机器
- 一个Topic数据分成多份,存储在不同的Broker上
- 需要考虑不同Topic的使用量级,均匀分配
- RocketMQ实现是 一个Topic下的消息会存储到多个Queue中(不是固定的),并记录这个一对多的关系
- 需要注册中心协调这些分片
- 哪些分片存了这个Topic?——存储信息
- 哪些Broker在线?——心跳检查
- 为防止单节点故障,需要多个注册中心,都要存储一份这些信息
- RocketMQ实现是 Broker启动时轮流向所有注册中心注册
- Eureka实现是 Broker启动时只注册一个,然后立马返回,后面注册中心之间再同步
- Zookeeper实现是 Broker启动时只注册一个,然后等注册中心之间全部或半数同步完,再返回
- 一个Topic数据分成多份,存储在不同的Broker上
- 1、消息写入磁盘持久化,防止消息丢失
-
需要客户端,提供集成的SDK
- 1、封装一套 发送消息 和 消费消息 的方法
- 统一接口,解耦
- 2、跟服务端Broker通信
- 网络通信可以选Netty框架,也可以直接用http
- 3、兼容多种项目
- 支持多语言
- 1、封装一套 发送消息 和 消费消息 的方法
-
后台管理功能
- 查看集群状态
- 消息状态查询、消费轨迹查询
- 总的消费数量统计
-