• Home
  • Archives
  • 随笔
所有文章 友链 关于我

  • Home
  • Archives
  • 随笔

如何设计消息中间件

发布于: 2021-05-21
更新于: 2023-07-09

消息中间件

设计中间件

假设让你设计一个消息中间件,你会怎么做呢?需要考虑些什么东西呢?

个人畅想

以下是笔者初看时的想法

从需求出发,思考有哪些是必备的功能点,需要考虑的点

需求项 描述
消息的存储 保证消息存储不丢失,消息如何高效存储,且存储密度高
订阅 对 topic 的订阅,保证失败后重试,保证消息消费成功,对于广播消息的消费
灾备机制 保证宕机后消息存在,恢复后可以从断点进行消费
高性能 保证消息的发送、消费能保证高并发
高可用性 如何部署高可用的集群,同城、异地,分布式集群时投票机制等

消息中间件的特点

消息中间件特点

消息中间件的缺点

消息中间件的缺点

可靠消息最终一致性

可靠消息最终一致性

如何上游服务对消息的 100%可靠投递

sequenceDiagram
    participant 上游
    participant 可靠消息服务
    participant 下游MQ
    上游->>可靠消息服务: 1️⃣如果上游开启事务失败<br/>由于这是同步调用,<br/>上游可自行决定回调or放弃<br/>对下游不会有影响
    可靠消息服务->>可靠消息服务: 2️⃣将开启的事务存储到数据库<br/>记为“待确认”

    上游->>可靠消息服务: 3️⃣如果上游操作完业务<br/>通知可靠消息ok时失败
    loop Healthcheck
        可靠消息服务->>可靠消息服务: 4️⃣可靠消息服务有一个线程<br/>定时检查“待确认”的订单
        可靠消息服务->>上游: 5️⃣将待确认订单去上游回查<br/>查询订单实际状态
    end

    loop Healthcheck
        可靠消息服务->>可靠消息服务: 1️⃣可靠消息服务有一个线程<br/>定时检查“已投递”的订单
        可靠消息服务->>下游MQ: 2️⃣如果一直未处理<br/>尝试重新发送消息<br/>要求下游幂等性
    end

高可用的降级方案

基于KV存储的队列支持降级方案

关于 KV 存储的设计要点

由于是消息队列的设计
第一点先把 KV 存储划分为几十个、几百个的线程 Key,这样子我们只需要往对应的 key 里面写,即可实现消息队列的功能。

注意点 补充项
避免数据量过大,大 value KV 数据库对于大 value、大 key 本身处理是很慢的,无论是带宽还是内存,假如因为太大,导致触发虚拟内存,写回磁盘的操作,那 redis 本身就拖垮了
避免热 key 不要往少数的 key 持续写消息,应用一定的分发规则将消息进行打散下发,这样子能提高 TPS
是否需要保证消息的顺序性 按照队列配置,同时消费端也固定消费指定线程,保证单线程取到数据

架构

数据结构

  • 考虑点
    • 存储地方
      • 内存
      • 磁盘
      • both
    • 持久化
      • 内存

        每隔几秒刷入 disk,刷入后生成的文件大小、数量

      • 磁盘

        切割文件规则,如何使用一些标识来标志数据信息,像 offset 偏移量 or 内置的唯一 id

    • 消费模型
      • 均匀分配给消费者各实例
      • etc

海量数据

背景:需要支撑 GB 级、TB 级海量数据高并发高吞吐写场景

那么需要实现高并发、高吞吐、海量数据,要考虑些什么呢?首先要解决海量数据存储的问题,单点肯定无法支撑,那么就要考虑分布式存储

分布式存储

关于数据的切分,把数据分成 n 片,放在不同的机器上,这里可以参考一致性哈希模型

假如原先分了 15 分片,达到了上限,那么就需要进行扩容数据,那么中间件就要支持动态增删分片、分片数据自动迁移

灾备

对于生产环境的产品,都要考虑高可用性,极端宕机场景,确定数据是否不可丢失 RPO[^rpo],数据恢复时间指标是多少[^rto],通过多副本冗余机制实现高可用

多副本冗余机制:数据写入主分片后,还要把数据写入灾备数量的副本分片上,才算写入成功,确保发生宕机时,在副本分片上有备份数据,确保不丢失。

[^rpo]: Recovery point Objective 复原点目标,假设发生灾备,如果 RPO=0,代表恢复时数据不会丢失。
[^rto]: Recovery Time Objective 恢复时间目标。假如发生灾备,恢复时间需要多久

数据不丢失

作为消息中间件,确保发送的消息不丢失是第一点,其次是要确保消息能被准确的消费,才算完成了一笔完整的消息投递,而确保的关键点在于 ack 机制。

不丢失就需要先看看消息投递的全链路情况,将各个模块的投递情况做记录

全链路

sequenceDiagram
    participant 造数模块
    participant 消息中间件
    造数模块->>消息中间件: 投递消息给中间件
    Note left of 消息中间件: 如果接收消息后宕机<br/>那么就需要持久化<br/>恢复队列以及数据

    loop checkDurable
        消息中间件->>消息中间件: 持久化队列以及数据<br/>到磁盘中,再返回ack
    end

    消息中间件-->>造数模块: 接收消息成功ack<br/>也可以通过磁盘备份<br/>保证数据不丢失
    Note left of 消息中间件: 依赖磁盘持久化<br/>可能数据会丢失

    消息中间件->>数据库模块: 数据库模块消费消息
    Note right of 消息中间件: 如果数据库消费一半宕机<br/>那这条消息消费失败了

    loop checkConsume
        数据库模块->>数据库模块: 如果已经消费成功<br/>向消息中间件发送ack
    end
    数据库模块->>消息中间件: 消费成功的ack消息
    Note left of 数据库模块: 一条消息完整消费完

    loop checkSend
        消息中间件->>消息中间件: 投递的消息是否已消费<br/>等待ack消息
    end
    Note right of 消息中间件: 假如限时内未收到ack<br/>重新发送消息
    消息中间件->>数据库模块: 重新消费对应消息

更新记录

更新时间 更新内容
2021 年 5 月 31 日 08:17:15 消息中间件设计
2021 年 7 月 6 日 07:23:31 补充了最终一致分布式的原理内容
如何设计消息中间件
/archives/8354089f/
作者
tyrantqiao
发布于
2021-05-21
更新于
2023-07-09
许可协议
CC BY-NC-SA 4.0
赏

蟹蟹大佬的打赏,大家一起进步

支付宝
微信
  • 架构
  • 中间件

扫一扫,分享到微信

微信分享二维码
强推好用的软件插件以及配置项
nginx从入门到无所不能
© 2024 tyrantqiao 本站总访问量次 本站访客数人次 载入天数...载入时分秒...
  • 所有文章
  • 友链
  • 关于我

tag:

  • 复盘
  • 我
  • 规划
  • java
  • 面试
  • 源码
  • 架构
  • Hadoop
  • HTTP
  • TCP
  • 学习笔记
  • IDEA
  • maven
  • idea
  • Java
  • jdk
  • 面经
  • linux
  • 爱情
  • mysql
  • 性能
  • sql
  • Mysql
  • JAVA
  • 技术
  • Redis
  • MQ
  • Spring
  • 数据库
  • TIDB
  • spring
  • unity
  • chatgpt
  • 经验分享
  • 前端
  • redis
  • vue
  • git
  • shadowsocks
  • hexo
  • blog
  • bug
  • 开发
  • 业务
  • jvm
  • 算法
  • MySQL
  • nginx
  • Linux
  • mq
  • db
  • springCloud
  • ssh
  • python
  • 爬虫
  • test
  • vim
  • 影视剧
  • 中间件
  • 事务
  • 性格
  • 音乐
  • 程序员
  • 随笔
  • mybatis
  • 演讲
  • 域名
  • 猫咪
  • 她
  • github
  • 计划
  • 旅游
  • 软件
  • 心理
  • 情商
  • 幽默
  • 才艺
  • 穿搭
  • 编程
  • 排序
  • 查找
  • 缓存
  • 网络
  • 设计模式
  • c
  • 课程设计
  • centos
  • 数学
  • 本网站主题yilia设计者的主页
如果有问题或者想讨论的可以联系[email protected]或者[email protected]