用数据库来实现消息队列有什么不好?

小公司,业务量不大,架构很简单,一个SQL数据库,一个web服务。最近老板不知道听了什么讲座,回来就让我们去弄一个消息队列,说是为以后发展作准备。

我百度了一些消息队列的资料,发现好像用数据库来做也可以,新建一个名为 messages 的table,里面有:

  • sender (消息发送者)
  • topic (队列主题)
  • created_at (时间)
  • data (内容)
  • is_consumed (是否被消费)

生产者的消息就往这个表里 insert 一行,消费者就到这里面去定时查询某个 topic里未被消费的消息。(如果要考虑时效性,发送完了就可以直接 http 或者 tcp 通知一下消费者去取)

我把这个想法和老板说了,老板说我这个没用,有点想不通。

本文参与了SegmentFault 思否面试闯关挑战赛,欢迎正在阅读的你也加入。
阅读 3.2k
5 个回答
  • 你自己造出来的轮子并没有得到有效的测试,而主流的消息队列经过了大量生产环境的检验
  • 发送完了就可以通知一下消费者去取 完全丧失了消息队列的意义,消息队列就是为了解耦消费者和生产者

当然,公司业务小架构简单,用数据库实现消息队列确实方便。定时任务查询未被消费的任务去消费即可,这样实时性不高,再加一个发送完通知下游去数据库取任务。那么再深入看一下可能的一些问题:

  1. 生产者通知下游消费者去数据库读消息,这样做是不是增加了生产者和下游消费者的耦合?例如:用户在支付系统下完单,需要通知仓库系统出库、通知积分系统给用户加积分、通知xxxxxx...

    • 那么是不是要挨个去发通知?
    • 其中一个通知失败要怎么办?要不要重试还是直接取消订单?
    • 如果下游的某个系统正好故障了怎么办?
    • 如果新需求要再新增通知另一个系统,是不是要修改上游服务的代码加这个通知?

    如果使用了一个消息中间件,作为上游完全不需要知道下游的存在,而使用数据库的方案,上游系统要小心翼翼的处理上面每一个问题,除非不去通知消费者,不考虑时效性。

  2. 如果不通知消费者,站在消费者端,还有许多问题等待题主解决。

    • 消费者怎么消费,单线程还是多线程还是多节点
    • 单线程没有竞争但是太慢,多线程/进程消费就存在一个问题,怎么去抢占任务?加事务和锁?这样并发性会不会有影响,性能会不会差?
    • 多个进程如何保证消费的负载均衡
    • 如果消费失败了,是不是要重试?重试多少次?重试次数超过上限还是失败怎么办?
    • 如果想要按某种顺序消费怎么保证?

上面的这些问题,使用数据库也是可以解决的,但是要写很多代码,要测试,并且很难保证实现没有问题?那么如果直接使用成熟的消息队列产品,它已经帮你实现好了这些,你只需要专注业务开发即可。


本文参与了SegmentFault 思否面试闯关挑战赛,欢迎正在阅读的你也加入。

l老板说没用可能是指对他想为以后做的准备没用,老板是想做大做强,未来你们的项目有百万千万的用户使用,如果用你这个数据库mq,只能在简单的架构中使用,举个例子,多消费者是常见的情况,你的数据库mq怎么解决重复消费的问题?同样的问题还有很多,除非你都解决了,不然还是“没用”

本文参与了SegmentFault 思否面试闯关挑战赛,欢迎正在阅读的你也加入。

虽然在理论上,使用数据库来实现消息队列是可行的,但是这种实现方式存在一些潜在的问题和限制,相较于专业的消息队列服务,使用数据库作为消息队列的实现方式有以下几个问题:

性能问题:数据库是为了存储大量数据而设计的,而消息队列则是为了高效地处理大量的消息而设计的。在高并发的场景下,数据库可能会成为瓶颈,影响性能。

可靠性问题:数据库虽然提供了事务机制来保证数据的一致性,但是在高并发的场景下,如果消息的生产者和消费者同时操作同一条记录,可能会产生死锁等问题,从而影响消息的可靠性。

时效性问题:消息队列通常需要满足实时性的需求,即消费者需要在消息被发送后尽快消费,否则可能会产生重复消费或漏消费的问题。使用数据库作为消息队列的实现方式,消费者需要定时轮询数据库以获取新消息,这样可能会产生延迟,影响时效性。

可扩展性问题:如果业务量增长,需要处理的消息量也会增加,如果使用数据库作为消息队列的实现方式,可能需要进行水平扩展,增加数据库的数量,从而增加了维护和成本的复杂度。

综上所述,虽然使用数据库作为消息队列的实现方式是可行的,但是相比专业的消息队列服务,其性能、可靠性、时效性和可扩展性都存在一定的问题。如果公司未来业务量增长,需要处理更多的消息,建议使用专业的消息队列服务,如RabbitMQ、Kafka等。

推荐问题
宣传栏