写点什么

消息队列消息存储设计(架构实战营 模块八作业)

作者:Gor
  • 2022 年 7 月 31 日
  • 本文字数:843 字

    阅读完需:约 3 分钟

消息表

对于 mysql 来说,控制表的大小以及对表进行顺序的读写,性能是最高的,因此每个 topic 用一张单独的表存储,并且每张表支持设置最大消息数量,超出最大消息数量则会创建新的表来存储。消息队列往往有对 topic 分区(partition)存储的要求,因此每一个分区也使用一张单独的表存储。因此,表名规则为:message_{topic}_n_m,其中 n 为分区序号,m 为表的序号。例如,业务方创建名为 test 的 topic,分区数为 4,每张表支持最大消息数量为 100w,对于第一个分区的表来说,表名为 message_test_0_0,当第一张表超出 100w 条消息后,会创建第二张表,表名为 message_test_0_1。

其中 id 设置为 primary key,消费者通过 id 读取对应的消息。submit_time 设置为普通索引,满足根据时间清理过期消息。

消费信息表


consume_log 表

光有消息表还不够,还需要一张表记录消费状态。也有几个要点:

  • 我们支持多个消费者组,每个消费者组共享一条消费进度记录,所以表中需要有 group 字段来区分是哪个消费者组的消费记录;

  • 消费偏移量是最重要的,记录了消费到哪条数据,用 offset 来标识,即 message 表中的 msg_id,因为 msg_id 在一个数据分组,一个 topic 下是严格递增的;

所以最终消息消费记录表设计如下:

如果不考虑太复杂的设计,核心主要就这两个表。

索引分析

我们先从几个高频场景来分析:

发送消息
  1. 客户端完成分片路由,分配到某个 shard,发送消息数据

  2. 消息队列服务器根据 topic 找到对应的消息表 message_{topic},然后插入数据,msg_id 自增


消费消息
  1. 客户端完成分片的路由,向对应服务器拉取消息,带上参数 topic,group

  2. 查询 consumer_log 表,根据 topic,group 通过索引找到对应的数据,取出 offset

  3. 根据 offset 查询对应的 message 表,通过主键 id,找出下个 offset 的记录,取出并准备返回

  4. 更新 consumer_log 的 offset 信息

  5. 返回数据

以上 2,3,4 在一个事务中执行。

从 2 可以看出,message_log 需要加个 topic+group 组合索引,命名为 idx_topic_group

从 3 可以看出,message 表需要 msg_id 的索引,但是其本身已经是主键,无需额外增加


发布于: 刚刚阅读数: 3
用户头像

Gor

关注

还未添加个人签名 2020.05.05 加入

还未添加个人简介

评论

发布
暂无评论
消息队列消息存储设计(架构实战营 模块八作业)_Gor_InfoQ写作社区