4

如何降低复杂度,用数据库做消息队列的存储? - 架构摆渡人

 2 years ago
source link: https://www.cnblogs.com/jiagoubaiduren/p/16278810.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

如何降低复杂度,用数据库做消息队列的存储?

大家好,我是【架构摆渡人】,一只十年的程序猿。这是消息队列的第一篇文章,这个系列会给大家分享很多在实际工作中有用的经验,如果有收获,还请分享给更多的朋友。

今天跟大家聊聊如何用数据库来做消息的存储,这样就可以将消息队列的整体复杂度进行降低,如果后续你们需要自己造更贴近公司业务的轮子,我觉得可以用数据库来存储。

假设你们的业务消息量每天是10亿条,数据存储最近7天的量,也就是70亿条。我们以单表2000W条数据作为上限,1个库放10张表,那么总共需要40个库来承载这些数据量。

当然这40个库可以不用40个单独的数据库实例,这样成本有点高,当然主要还是取决于你们消息的读写并发有多高,如果很高的话数据库实例越多,性能肯定越好。不多的话就5个数据库实例,每个实例上建8个库即可。(根据消息读取和写入的量结合数据库规格的性能进行评估)

因为我们总共也就能存放80亿条的数据,如果数据量多了必然会影响查询性能或者磁盘空间不够的问题,而且对于已消费的消息,其实后面就没有业务价值了。

所以我们还需要每天进行数据的归档操作,归档你可以将这些数据移到Nosql中,也可以进行删除,看业务场景决定。有了归档,这样就能保持当前的数据库集群能够承载每日的消息容量。

接下来聊聊最重要的存储设计,就是我要用数据库来存,我的表该怎么设计?

前面我们也讲到了,我们大概需要400张表来存储这些数据。我们对某个Topic进行消息发送,那么数据必然要落到这400张表中的某一张表里面,所以我们很自然的想以某个字段来分表就行了呗,比如Topic,每个Topic写入的数据必定在同一张表里面。

这样也没啥问题,但是在实际的业务中,必定是有的Topic消息量会很大,有的会很少。对于消息量很大的,可能几个小时就突破2000W的量了,那么这个表必定越来越大。所以我们在设计数据存储的时候一定要考虑到如何将某个Topic下的数据均匀的存储到多张表里面去。

2534155-20220516221501179-153308127.png

可能有人就会说了,既然不能固定按Topic进行分表,那么就对总的表数量取模好啦,这样数据就会分布在每张表里面。但是这样对于consumer在消费的时候就有影响了,因为consumer压根就不知道自己要消费Topic的数据存在哪,必须得从所有的库表里面进行查询才能拿到数据,性能不太好。

2534155-20220516221505313-1830055.png

要解决这个问题,我们先回顾下开源的MQ是怎么设计的,以RocketMQ来说,一个Topic下的消息会存储到多个Queue中(也就相当于kafka中的partition),也就是每个Topic下的Queue并不是一定的数量,而是可以在创建Topic时进行指定,所以我们在用表做存储的时候,也可以参考这个设计,本来每个Topic对应的消息量就不同。

所以一张表也就相当于一个Queue,用于存储消息内容。我们可以记录Topic和Queue之间的关系,记录后有如下的作用:

  • 往某个Topic写入消息的时候,就知道这个Topic对应哪些Queue(数据表),可以轮询的写入这些表,这样数据就比较平均。
2534155-20220516221510119-1085580580.png
  • 创建Topic的时候要预估一下数据量,然后指定分配多少个Queue用于存储。(后续也能在线修改Queue的数量)
  • Consumer消费某个Topic消息的时候,同样也知道对应哪些Queue,在Consumer初始化的时候就会分配好哪个Consumer消费哪个Queue,这样每个Consumer只会去固定的一个表中查询数据,性能也非常好。如果后面Consumer增加或者减少,Queue增加或者减少就需要重新分配了,这就是消息队列中经常提到的重平衡的一个概念。
2534155-20220516221514958-314754692.png

当然这里只是说了整体的设计,还有很多细节需要去完善,比如Topic消息量小的如何处理,就算是只分配一个表,但是我们总的表数量是有限的,所以还会涉及到多Topic共用一个表的情况。

大概的我们可能会有下面的一些表:

  • consumer: 消费者,记录当前消费者的信息,比如ip, 进程ID, 应用类型,启动时间等等。
  • consumerGroup: 消费组信息。
  • topic:主题表。
  • queue: 消息表,记录消息内容,对应的Topic等等。
  • topicQueue: Topic和queue的关系。
  • queueOffset: 队列消费偏移量,记录consumer的消费信息。

不同的场景可以选择不同的技术方案,用数据库作为MQ的存储也是一种不错的思路。但为什么开源的都是自己写磁盘呢?其实这也跟架构有关系,因为一旦依赖外部存储,也就是整个架构会比较复杂。而且MQ这种本来就是用来扛大流量的,所以要对底层进行优化,用三方的也就意味着性能其实依赖了三方。

通过数据库来存储MQ的数据,相对来说技术难点会比写磁盘要简单点,大家也可以按照这个思路,自己去设计实现一款MQ。

原创:架构摆渡人(公众号ID:jiagoubaiduren),欢迎分享,转载请保留出处。

推荐一款开源的mock框架:https://github.com/yinjihuan/fox-mock 基于Java Agent实现的自测,联调Mock利器


Recommend

  • 121

    相信不少同学在维护老项目时,都遇到过在深深的 if else 之间纠缠的业务逻辑。面对这样的一团乱麻,简单粗暴地继续增量修改常常只会让复杂度越来越高,可读性越来越差,有没有固定的套路来梳理它呢?这里分享三种简单通用的重构方式。 什么是面条代码 所谓的【面条...

  • 49

    背景 在项目开发中,我们经常见到复杂度很高的代码,由于历史原因,代码一直没有重构,导致后面越来越难以维护和迭代,所以在项目开发期间,控制代码复杂度是非常重要的。 衡量标准 代码复杂度就是统计一个函数有多少个分支(if,while,for等)每增加一个分支,复...

  • 13

    云妹导读: 随着互联网的不断发展,大数据高并发不再遥远,是大部分项目都必须具备的能力。其中,消息队列几乎是必备技能。成熟的消息队列工具有很多,本篇文章就来介绍一款京东智联云自研消息队列工具——JCQ。 JCQ全名JD Cloud Messa...

  • 12
    • developer.51cto.com 4 years ago
    • Cache

    降低代码的圈复杂度

    0. 什么是圈复杂度 可能你之前没有听说过这个词,也会好奇这是个什么东西是用来干嘛的,在维基百科上有这样的解释。 Cyclomatic complexity is a software metric used to indicate the complexity of a program. It is a quan...

  • 8

    本文代码示例以Go语言为例 欢迎微信关注「SH的全栈笔记」 0. 什么是圈复杂度 可能你之前没有听说过这个词,也会好奇这是个什么东西是用来干嘛的,在维基百科上有这样的解释。

  • 10

    对于一个程序员来说,日常最常说的词恐怕就是「复杂」了,这段代码太复杂了,这个逻辑太复杂了,所以,在这篇文章里,我们就好好掰扯掰扯「复杂」到底是怎么产生的,又要怎么去避免。 复杂度的产生 我们先列一下当我们...

  • 1
    • 微信 mp.weixin.qq.com 3 years ago
    • Cache

    不得不看!降低Transformer复杂度的方法

    首先来看一下原始Transformer的复杂度self-attention复...

  • 7

    作者|王维,中国移动云能力中心IaaS产品部rpc产品组研发工程师,主要负责消息队列云原生方向的设计与研发工作胡宗棠,中国移动云能力中心laaS产品部消息队列&rpc团队的负责人,主要负责消息队列、rpc、配置管理等云原生中间件的架构设计与技术研发工作

  • 2

    降低复杂度提升效率,DDD在携程用车/租车订单系统重构中的实践 作者:小白龙 2023-04-14 10:20:41 本文描述了两车如何利用DDD(Domain-driven Design,领域驱动设计)方法论降低系统复杂度以及在重构历史系统中的...

  • 7

    theme: Chinese-red本次主要是聊聊关于使用接口抽象和降低圈复杂度的方式工作中,难免会遇到老项目老代码,不仅仅需要我们维护,可能还需要我们在原来的垃圾代码上进行新增功能或者是进行优化调整现有的老代码中关于用户系统这一块就已经经是...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK