1.消息系统是什么?
上图是一些小系统的典型架构。考虑订单的业务场景,有大量的请求指向我们的业务系统,如果直接经过复杂的业务逻辑进入业务表,将会有大量请求超时失败。所以我们加入了一张中间缓冲表(或者Redis),用来承接用户的请求。然后,有一个定时任务,不断的从缓冲表中获取数据,进行真正的业务逻辑处理。
这种设计有以下几个问题:
- 定时任务的轮询间隔不好控制。业务处理容易延迟。
- 无法横向扩容处理能力,且会引入分布式锁、顺序性保证等问题。
- 当其他业务也需要这些订单数据的时候,业务逻辑就必须要加入到定时任务里。
当访问量增加、业务逻辑复杂化的时候,消息队列就呼之欲出了
请求会暂存在消息队列,然后实时通过推(或者拉)的方式进行处理。
在此场景下,消息队列充当了削峰和冗余的组件。
2. 消息系统的作用
削峰 :用于承接超出业务系统处理能力的请求,使业务平稳运行。这能够大量节约成本,比如某些秒杀活动,并不是针对峰值设计容量。
缓冲: 在服务层和缓慢的落地层作为缓冲层存在,作用与削峰类似,但主要用于服务内数据流转。比如批量短信发送。
解耦 :项目尹始,并不能确定具体需求。消息队列可以作为一个接口层,解耦重要的业务流程。只需要遵守约定,针对数据编程即可获取扩展能力。
冗余: 消息数据能够采用一对多的方式,供多个毫无关联的业务使用。
健壮性: 消息队列可以堆积请求,所以消费端业务即使短时间死掉,也不会影响主要业务的正常进行。
3. 消息系统要求
消息系统即然这么重要,大体要求有如下这几点:
通过增加副本,可以将数据的风险分散到多台机器上。这就需要在主分片出现问题时,能够从副本中找出一个作为新的主分片。有很多这样的协调工具,比如zk
3.2 高可靠
单机高可靠
集群的高可靠方面,会有ack机制和多副本机制进行保证。对于单个节点来说,断电或者主机异常,会是一个比较大的挑战。为了处理这种情况,需要有刷盘机制或者其他持久化机制。同时,数据的完整性校验也是需要的。
生产端
生产端除了要考虑buffer丢失的问题,还要考虑到一些发送错误的情况,包括与集群通信的超时和重试处理。
消费端
消费端通过消息确认机制来保证消息已经被正确消费。由于其间会发生很多异常情况,所以大多数消息系统保证at least once语义。即确保消息至少被消费1次。
3.3 高性能
包含消息投递和消息消费,都要快。高性能主要从两个方面考虑,
一个是消息的延迟,消息从生产端发出,到消费者处理,其间的过程不能太长
另一个是消息的吞吐量。对于消息吞吐量来说,是一个生产端、mq节点、消费端共同优化的结果
消息的延迟的影响因素主要有两个就是网络和吞吐的速度。抛除网络因素,只和吞吐量相关。而对与吞吐量,主要有以下解决办法:
- 异步化
消息采用异步发送的方式,发送端不用同步等待,加快了处理速度。
- 批传输
采用批量发送的形式,(类似于编程语言中处理 string 字符串的形式,减少内存消耗),在内存中缓冲一个 buffer,如果 buffer 满了,或者到达时间,则进行一次性传输。这样减少网络传输的次数,方便进行数据压缩,但是如果处理不当,容易丢失数据。
- 顺序读写
顺序读写操作磁盘,比随机操作磁盘要快,这也是 kafka 高吞吐的一个原因。
- 并行
3.4 消息要可靠
在某些场景,不能丢消息。生产、消费、MQ端都不能丢消息。一般通过增加副本,强制刷盘来解决。
3.5 扩展性好
3.6 生态成熟
监控、运维、多语言支持
4. 消息类型
普通消息主要分为点对点和广播,点对点指的是一条消息只被消费一次,pub/sub通过发布,订阅模式被多个消费端消费。广播指通过广播的形式,即