我记得大概在16~23年吧,分布式、微服务应用这股风刮得最为强劲,大大小小的企业项目、互联网项目都想着上分布式,上微服务。然而随着时间的验证和项目建设规模的演变,似乎有些项目出现了类似“分布式单体”的问题,也有一些项目因为业务规模缩小而不得不维护一大堆服务,造成各种资源的浪费。写这段前序的目的,是考虑到当下环境的发展趋势,特别是考虑到业务规模、建设团队等更现实的因素,提出的一些应用架构和技术选型的个人思考。本系列仅为一家之言,欢迎各位朋友指出不同观点~
在分布式系统的架构演进中,我们常常面临一个看似简单却充满陷阱的抉择:当涉及多个服务间的异步通信时,是应该直接引入消息中间件(MQ),还是基于现有的数据库能力构建一个"模拟队列"达到相同/相似的目的?我接触过有的团队为了技术而技术,在果断引入 MQ 后出现了运维成本大增、系统稳定性下降等问题,当我了解这些团队的技术负责人时,得到的答案往往是类似于“产品专业”、“特性丰富”等直截了当的观点。但是话又说回来,当一开始引入 MQ 时,系统中真的需要那么多 MQ 产品的特性吗?我们是不是真的给自己“创造”需求了呢?基于数据库实现模拟队列真就那么不堪大用吗?
带着上面的问题和场景,我们来试着探讨一下 MQ 和基于数据库的模拟队列之间的选型决策。
1. 选型的轻/重
很明显,相较于数据库模拟队列而言,MQ 是一个需要额外引入产品的“重量级”方案,对技术架构熟悉的朋友都知道一个定律,系统中每增加一个中间件,就会相应地降低系统的整体稳定性。因此在选型时,考虑解决方案的轻重,实际上有一部分影响的是系统的整体稳定性。为此我们就需要先明确两种方案的优劣,通过对比才能理性准确地作出选型决策。
1.1 数据库队列的优势
在单体应用(或多个服务同时连接一个数据库的“分布式单体”)中,使用数据库表模拟队列(如通过status标记消息状态、通过createTime标记消息的推送时间,配合事务控制)具备以下特性:
零外部依赖:无需引入RocketMQ、Kafka等中间件,直接复用现有数据库资源,降低系统复杂度。
强一致性保证:通过数据库事务(ACID)实现消息的原子性操作,避免MQ场景下可能存在的重复消费、消息丢失等问题。
开发成本低:仅需简单的SQL语句(如
SELECT ... FOR UPDATE)配合定时任务即可实现队列功能,代码侵入性低。

1.2 MQ的隐性成本
MQ 在分布式场景下通常表现出色,但其在单体应用或分布式单体中就不一定全都是优势了:
资源浪费:MQ的高吞吐设计(如Kafka的百万级TPS)对单体应用而言大概率性能过剩,而数据库模拟队列在几千级的TPS场景下已足够应对。
运维负担:用于生产的 MQ 大概率得是集群吧,单体 MQ 上生产未免有些冒险,那么问题就来了,MQ集群的搭建、监控、故障恢复都需要专门运维知识,这部分成本又要谁来承担呢?对比来看,数据库作为基础设施通常已有成熟管理方案,模拟队列也只是数据库中的一张表而已。
1.3 数据库队列也不全好
当然说那么多也不是直接下结论说数据库模拟队列多好多好,既然是基于数据库的,而且是模拟制作的,那就一定存在相应的问题:
性能瓶颈:传统的关系型数据库的并发通常不高,即便是Oracle这种大型商业化数据库也很难比得过成熟的MQ;
定时轮询:使用数据库队列通常需要配合程序设计的定时轮询,而这部分一般都是我们自己开发制作;
特性成本:基于数据库的队列在操作时都会产生事务日志,这部分也要计算到成本中;
功能完整性:可监控性、生产级特性都是不存在的,全部要由我们自己设计;
扩展性:基于数据库表的扩展往往会受到一些限制,如性能、存储、磁盘IO等。
2. 如何抉择
2.1 适用场景分析
通过业务规模和可靠性要求两个维度可明确选型边界:
低频异步任务:如订单状态更新、日志记录等,数据库队列通过批量处理+重试机制即可满足需求。
短事务补偿:在本地事务中插入消息记录,配合定时任务补偿失败操作,避免分布式事务的复杂性。
资源受限环境:开发测试环境或中小型项目,数据库队列可减少依赖组件,提升环境一致性。
2.2 必须引入MQ的信号
当出现以下特征时,需重新评估技术选型:
流量峰值超过数据库处理能力(如秒杀系统万级并发)。
跨系统异步通信需求(如与第三方支付平台对接)。
消息顺序性、延迟敏感性要求极高(如金融交易场景)。
3. 数据库队列也可以很好用
3.1 性能优化策略
分片设计:按业务ID哈希分表,避免单表数据量过大导致锁竞争。
批量处理:使用
LIMIT N批量拉取消息,减少数据库连接开销。索引优化:对
status、create_time字段建立复合索引,加速消息状态查询。
3.2 可靠性保障方案
死信处理:设置最大重试次数,超限消息转入死信表人工干预。
双重确认机制:消费者处理完成后执行
DELETE而非UPDATE,避免僵尸消息残留。监控告警:通过Prometheus+Granafa监控消息积压量,设置阈值告警。
4. 选型决策的考虑
建议通过以下决策树进行选型判断:
是否跨进程通信? → 是:选择MQ;否:进入下一环节。
TPS是否超过2000/s? → 是:评估MQ;否:优先数据库队列。
是否有持久化以外的特殊需求?(如顺序消息、延迟队列) → 是:选择支持特性的MQ(如RocketMQ);否:数据库队列。
写在最后
在技术选型中“简单性”往往被低估,我们在选型时往往会想到XXX产品能完成XXX任务,就直截了当地引入了新产品,殊不知新产品会引入整体架构的复杂度,而这个产品本身的能力并没有发挥多少。数据库队列凭借其与单体架构的高度契合,能够以20%的复杂度解决80%的业务需求,这就很不错了。选型要合适恰当,发挥不同产品尽可能大的能力才是王道。