架构设计:让你设计一个消息队列,你会怎么设计它的架构?

52 阅读4分钟

架构设计:让你设计一个消息队列,你会怎么设计它的架构?

要设计自己的消息队列,要围绕生产者、消费者、broker和topic4个方面

本章将设计一个以MySQL为基础的消息队列

topic设计

  • topic是必不可少的,它代表的是不同业务

  • 分区也是必不可少的,不划分分区会有并发竞争。比如所有生产者都要竞争同一把锁才能写入到topic,消费者读取数据也必须竞争同一把锁,这样性能很差,所以topic内部肯定要通过分区细分

  • MySQL怎么把topic和表关联起来?

    • 一个topic是一个逻辑表,对应的分区就是逻辑表执行分库分表后得到的物理表

      • 举例:假如有个叫order的topic,代表我有一个逻辑上叫order的表
      • 如果这个topic有3个分区,那么代表我有order0、order1、order2三张物理表
      • 这种情况下,每张表都可以用自增主键,自增主键对应kafka中的偏移量
  • 为什么不能所有topic都用一张逻辑表?

    • 不这样做的原因有两方面原因,性能和隔离

      • 性能:一张表难以应付高并发场景,分库分表也要分几千张
      • 隔离:topic天然就是业务隔离的,不同topic用不同的表,相互之间就不会影响
      • 使用不同的表,能够更好的安排不同数据库实例来存储

broker与消息存储

接下来就要考虑怎么存储topic和分区。kafka存储分区是尽量分散开来,我们也可以学习这种方式

  • 为了保证高可用,同一个topic的不同分区最好分散在不同broker上存储。这样一个broker崩溃,这个topic最多只有一个分区收到影响

  • 要使用MySQL实现,那么一个topic的不同分区,不仅要分表,还要分库。也就是说最好存放在不同的主从集群上

    • 最好的策略是把分区分散在不同主从集群上,比如有四个分区,四个分区分别在四个不同的主从集群上。

      • 优点是分散了流量,还互不影响
    • 主从集群本身就类似kafaka的副本效果,不过没有ISR概念

      • 主从集群说明分区在从库都有对应的数据。如果是一主两从,说明每个分区都有一个主分区和两个从分区。MySQL的主从机制也方便我们不需要管理主从选举的问题

发送消息

解决topic和broker后,就是讨论发送者怎么发送了。要先确定是发送者主动发给broker还是broker主动拉去

  • 就生产者来说应该主动推送到broker,因为消息产生速率和broker没关系。broker拉取不好控制频率和数量

批量发送

  • 为了优化发送性能,可以支持批量发送。生产者凑够一个批次后再发

  • 批次大小生产者决定

  • 生产者也要有兜底措施,一段时间内没有凑够也要发送,防止消息长时间停留在生产者内存,出现消息丢失

    • kafka有类似机制,通过linger.ms来控制等待时长

直接插入消息

用MySQL实现,消息最终是存在DB里的,所以可以通过broker访问数据库,也可以生产者直接访问数据库

  • 如果要追求极致性能可以考虑生产者直接把数据插入到数据库。生产者同进程下引入一个本地依赖处理数据库配置和连接问题。发送消息就是调用本地依赖的方法执行INSERT语句。可以省略一次网络中间通信,可以结合批量插入进一步提高性能

消费消息

可能会有不同业务方消费同一个topic的消息,所以可以引入消费组和消费者的概念

  • 一个业务方就是一个消费者组,一个消费者组有多个消费者。kafka中,每个分区有一个消费者,一个消费者可以消费多个分区。可以参照这个方法,每个分区是一张表,这张表对于一个消费者组来说,只能有一个消费者读取

记录偏移量

  • 可以用另外一张表来记录,只需要记录消费组名字、分区、已消费偏移量即可。
  • 每次消费者提交消息,对于broker来说就是更新这张表的偏移量

直接拉取

  • 消费者也可以设计一个本地依赖直连数据库,也可以提高性能

延迟消息

用MySQL为基础很容易实现延迟消息,只要在消息表里加上一个预期发送时间,消费者拉去消息的时候判断一下