1.消息系统是什么?

image.png

上图是一些小系统的典型架构。考虑订单的业务场景,有大量的请求指向我们的业务系统,如果直接经过复杂的业务逻辑进入业务表,将会有大量请求超时失败。所以我们加入了一张中间缓冲表(或者Redis),用来承接用户的请求。然后,有一个定时任务,不断的从缓冲表中获取数据,进行真正的业务逻辑处理。

这种设计有以下几个问题:

  • 定时任务的轮询间隔不好控制。业务处理容易延迟。
  • 无法横向扩容处理能力,且会引入分布式锁、顺序性保证等问题。
  • 当其他业务也需要这些订单数据的时候,业务逻辑就必须要加入到定时任务里。

当访问量增加、业务逻辑复杂化的时候,消息队列就呼之欲出了
image.png

请求会暂存在消息队列,然后实时通过推(或者拉)的方式进行处理。
在此场景下,消息队列充当了削峰和冗余的组件。

2. 消息系统的作用

削峰 :用于承接超出业务系统处理能力的请求,使业务平稳运行。这能够大量节约成本,比如某些秒杀活动,并不是针对峰值设计容量。

缓冲: 在服务层和缓慢的落地层作为缓冲层存在,作用与削峰类似,但主要用于服务内数据流转。比如批量短信发送。

解耦 :项目尹始,并不能确定具体需求。消息队列可以作为一个接口层,解耦重要的业务流程。只需要遵守约定,针对数据编程即可获取扩展能力。

冗余: 消息数据能够采用一对多的方式,供多个毫无关联的业务使用。

健壮性: 消息队列可以堆积请求,所以消费端业务即使短时间死掉,也不会影响主要业务的正常进行。

3. 消息系统要求

消息系统即然这么重要,大体要求有如下这几点:

  • 高可用
  • 高可靠
  • 性能要高
  • 消息要可靠
  • 扩展性要好
  • 生态成熟

    3.1 高可用

    高可用主要解决集群单节点,在异常情况下的failover和HA。解决高可用问题的一般就是副本机制。

消息系统 & kafka - 图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. 消息类型

消息系统 & kafka - 图4普通消息主要分为点对点和广播,点对点指的是一条消息只被消费一次,pub/sub通过发布,订阅模式被多个消费端消费。广播指通过广播的形式,即