突然想到一个问题,消息队列的意义是什么?

2020-12-01 14:25:40 +08:00
 Joker123456789

消息队列 发明的初衷 是 降低下游的压力,让下游的服务按照自己的能力去消费。

但是这引发了另一个问题,如果下游服务的消费能力小于上游服务的生产能力,那么必然会造成消息积压,而且随着时间的累计会越积越多。

为了解决这个问题,不得不增加消费能力,但是又出现了一个问题,如果消费能力上去了,可以让队列里不积压消息了,那就说明消费能力不比生产能力差了,既然如此,为什么不直接让生产者调用消费者?

12666 次点击
所在节点    Java
95 条回复
nanjingwuyanzu
2020-12-01 17:35:27 +08:00
解耦 削峰 非实时统计的数据可以走 mq
hws8033856
2020-12-01 17:43:42 +08:00
把消息队列比喻成水库你就明白了
astkaasa
2020-12-01 18:03:28 +08:00
削峰填谷
laminux29
2020-12-01 18:17:54 +08:00
把 Factorio 玩一遍你就懂了,这游戏能让你直观感受到用不用队列的差别。
iColdCat
2020-12-01 18:23:25 +08:00
削峰啊 上游服务的流量并不一定一直是很高的 可能只是在某个时间段内高 那你为了这某个时间段的高流量去提升下游服务的配置就显得不是那么划算了
lepig
2020-12-01 18:23:46 +08:00
并行转串行?
beryl
2020-12-01 18:28:53 +08:00
上游不会一直大于下游的处理能力,削峰填谷的还一个点是时间的错峰,整点上游并发大,阻塞在消息队列里面,下游可以分散时间处理
liudaolunhuibl
2020-12-01 19:00:03 +08:00
举个例子,我一个电商系统,客户下单之后有:计算积分、通知库管系统准备出货并且存量-1,自动领取一些优惠卷等操作,如果是微服务架构那么这些操作肯定是放在对应的服务上面的,如果假如说我们不用消息队列的话那么订单系统怎么通知这些服务做对应的操作呢?我能想到的是调用 Http 接口( fegin )或者 rpc 调用( dubbo ),刚上线的时候我服务是单节点还行没啥问题,到了后面生意越来越好了我要做集群了,那么我就要保证我通知下游系统的接口是幂等的因为每个节点都可能调用,到了后面下单之后的操作越来越多(该死的产品经理),甚至是有部分下游系统不在我微服务里我要用 restTemplate 去调用了,这样又有了新问题:每接入一个新服务我都要去修改代码去和其他服务对接口然后联调,然后因为下游服务越来越多我的订单服务在双十一这种流量洪峰的时候已经快扛不住了,那么怎么解决?对,我可以导读抽出一个通知服务,让订单服务调用通知服务的接口获取订单信息,我下游系统去和通知服务进行对接,但是通知系统要不要持久化这些订单信息?万一下游系统挂了我的通知系统怎么去重复通知呢?怎么保证我的订单信息不丢失呢?消息队列就出来了,他实际上就是人家帮我们做好了的通知系统,他可以保证消息的重复消费、持久化、重试。并且自身也可以集群的。
liudaolunhuibl
2020-12-01 19:01:32 +08:00
并且用消息队列还有个好处就是,你不需要定义“接口”,我只需要定义消息,下游系统直接消费我的消息就可以了,我不用对接口不用联调了,每接入一个新下游服务他们只需要去消费对应的消息就可以了,代码维护性也大大提高了
Anarchy
2020-12-01 19:04:15 +08:00
和实际生活中的排队解决的问题一致,可预期可控。
liian2019
2020-12-01 19:09:31 +08:00
服务之间聊天用的
sampeng
2020-12-01 19:29:15 +08:00
解耦我觉得算是副作用,不是消息队列的主要作用。因为这个一搞不好就不好调试,重试容错,失败策略都极其男做,解耦把研发解成 sb 了。其实你换个角度,直接调用也算是消息队列。这个队列是在系统 tcp 层给你干的。

我个人认为所有不是为了削峰平谷用消息队列的一概是炫技,反正 3-5 年后这一块不一定还是自己维护。只要帅就够了。

上游多的时候,好的系统可以弹性伸缩,消费者自动增加。当然也不能无上限,上限是数据库的瓶颈。这个时候在一定阈值的时候会触发告警让 ops 或者研发上线关注堵塞情况。根据情况处理。而不会我本来写入只能 100 歌。突然来一万个导致写功能完全崩溃。这是很多场景下不能接受的。有同学会杠,那我直接调用也可以弹性伸缩啊。对,是可以,但是不一定来得及。怕你们是没有被突然 10-20 倍压力在 5 分钟内灌进来过…这不算什么。100 倍都有可能。弹性伸缩?你试试 10 秒内起 10 个 java 系的微服务或者 5 分钟内 100 台机器上千个微服务。而且马上全功率提供服务。所以没有支付系统是直接调用的。都是消息队列。结耦有毛线关系…就是怕挂了。

反过来,上游少,下游多。这是资源浪费,这是 ops 的活,和你没关系…
fregen
2020-12-01 19:30:06 +08:00
sampeng
2020-12-01 19:30:59 +08:00
@liudaolunhuibl 嗯,我们试过 10 个接口本来同步很简单搞定的。硬要设计成消息队列。还不是乖乖改回去。千万别这么做…会累死。
liudaolunhuibl
2020-12-01 19:45:27 +08:00
@sampeng 代码层面主要是考虑维护性,你现在是十个接口,如果后面越来越多了呢?然后比如说你知道这十多二十个接口,那你离职了后面的人呢》这个太考验文档性了,再比如说,我十个接口中有一个系统要下线了或者重启了,那你调用接口不久疯狂报错了吗?虽然可能是异步的不影响,如果用消息队列的话对接 message 就可以了,就算下游系统下线了没关系,并且 mq 还可以帮你解决重复消费、重试等问题
shawnsh
2020-12-01 19:52:07 +08:00
消息队列还有几个功能,比如进程通讯,任务易管理
sampeng
2020-12-01 19:56:19 +08:00
另外我想说楼主,难道你们没监控吗?这压根就不是问题啊。积累了告警啊…
locochen
2020-12-01 20:07:08 +08:00
可以搞供给侧结构性改革
dddd1919
2020-12-01 21:54:59 +08:00
非常常见的解耦场景:一个生产方对应多个消费方
milukun
2020-12-01 23:41:37 +08:00
爬虫场景,数据抓取之后需要存储的数据库。
但是数据库不止有一种,有存储全文的 es,也有存储提取到数据关键内容的其他数据库等等。
这时候一个生产者(爬虫)就可以通过消息队列的订阅模式接入多个消费者(不同的数据库)
同时如果数据库挂掉,消息队列可以暂时起到存储的作用,等数据库恢复以后重新上数据。否则存储失败,抓取到的数据就丢失了,有些时候抓取需要一次成功。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/730959

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX