在微服务中是用队列好还是 RPC 好

2019-07-04 18:11:01 +08:00
 springmarker

个人浅薄的认识,在大多数场景下可以用队列替换 RPC(指代通常的 RPC,不是由队列实现的 RPC)。
队列的优点:
1.消息可以堆积,只要队列稳定,消息丢失的概率就比直接 RPC 低。
2.由接收端主动获取消息的话,负载就由接收端控制了,不会像 RPC 一样无法均衡的负载。
3.没有类似 Zookeeper 的注册中心,发送端和接收端只要面对队列就可以,发送端不用同时面对注册中心和多个接收端。

缺点的话就是性能不如直接 RPC、需要手动写异步转同步。

我看很多微服务都用的是 GRPC 和 Dubbo 之类的 RPC,甚至 Spring Cloud 的 RPC,如果替换成队列会有什么影响吗?不需要高性能的场景下可以互相替换吗?

本人了解甚少,上面都是班门弄斧的瞎说,如有不对,希望大神能指教一二。

16825 次点击
所在节点    程序员
129 条回复
Duluku
2019-07-05 11:43:08 +08:00
@springmarker 我狭义的理解一下技术上,对代码有侵入,为了写的方便,用 rpc 写可能方便点。消息队列我就直接理解为 metaq 那种,作为可以被多次消费的东西、实时性可能不保证? 我单纯从我做的业务来讲的、楼上聊的太深、我也不太懂
1ffree
2019-07-05 11:49:39 +08:00
我个人的理解, 楼主想用消息队列的特性取代 rpc。
消息队列例如 rabbitmq, 它本质上是一个中间件。
想要取代 rpc,而且不另外增加网络请求,
相当于是我们所理解的 mq 的一些特性,揉杂在服务提供方,我认为这对服务端来说太重了。
如果要简化,那么我认为最终可能还是往 rpc 的方向靠,因为服务端不需要这些特性。
langxuan
2019-07-05 11:52:03 +08:00
我觉得区别还是在于使用方式上
一般用 RPC 默认时延较低,而且错误重试由请求发起方主导
如果用队列的话,谈到消息可堆积,那就代表时延没有保证;另外感觉也不太会由发送消息方去做重试
Caskia
2019-07-05 12:00:32 +08:00
楼主罗列出了用队列做异步调用的优缺点,楼上的各位只是一味的抨击楼主。为什么不能静下来想想这样做有什么不行的。
大家大多提到队列主要延时性高,这个延时性来自于什么地方?消费的不够快?队列吞吐低?
- 消费的不够快可以增加消费者
- 吞吐低可以使用吞吐量大的队列(内存中)
- 这样跟传统 RPC 的区别?仅仅是多了一次到达回复。而这个到达回复是程序复杂程度上的问题,RPC 难道就不回复了吗?
zhazi
2019-07-05 12:00:35 +08:00
不知道楼上这群人在说啥呢,mq 和 rpc 都是通讯手段,建议看一下 DDD 限界上下文之间的映射关系这里。
两种通讯手动是两个方向,
就拿 save 来说
rpc 是“我”命令“你”要干什么,命令就需要对方必须服从(开接口)
mq 是“我”告诉“你”要干什么, 告诉就代表对方不一定服从(是否消费由对方决定)
从解耦角度来说 mq 好点
zhazi
2019-07-05 12:05:16 +08:00
这个问题换个说法来问,两个对象交互,用观察者模式交互好 还是直接调用方式好。楼上那群杠精就舒服了
justRua
2019-07-05 12:07:29 +08:00
看业务场景吧,类似提交订单、抢红包这种可以需要‘保证’处理,可以接受延迟处理的请求放 MQ 里等待消费返回信息是没问题的。一些如查询列表的请求把它放队列里保证服务器在能处理该请求意义不大吧,服务器响应不过来直接返回服务繁忙通知用户就好了。
1.你说的稳定是指服务器在繁忙时,请求可以在队列里堆积,不至于像直接调用那样返回失败,这个像上面说的看场景,一些不重要的请求失败就失败了,没必要确保服务端一定处理;
2.rpc 也可以做到负载均衡,例如 SpringCloud 里的 RestTemplate+Ribbon,通过注册中心 eureka 提供的信息做到负载均衡(我也只是看过官网的 demo,生产中并没用过,不知道它可不可以实现根据服务方的健康度做到带权重的负载均衡);
3.kafka 这种分布式队列就是使用 zookeeper 做协调中心的,消费者、生产者都只需链接 kafka 集群。
以上是我的看法,不知道对不对:)
tao1991123
2019-07-05 12:25:16 +08:00
微服务中 RPC 和 MQ 并不冲突

现在通常用的 CURD 模式微服务 只需要用到 RPC
但是 还有一种 CQRS 模式微服务 RPC 和 MQ 都要用到
version
2019-07-05 12:26:21 +08:00
rpc 基本是实时通信.而且出错概率低..类似于方法调用那么快了.
消息队列是.监听消费.每隔 3 秒.2 秒.而且容易丢数据.

消息队列只做通知类型的业务.或者下发业务处理.可以跨区域.
rpc 适合做模块方法类拆分处理掉用.需要定义异常等很多细节.最好不要跨太多网段或机器.
运用场景完全不一样.

正常一个 api 请求.例如 100ms 内部其实已经掉用了 5 个 rpc 了......消息队列能做到吗
webee
2019-07-05 12:33:03 +08:00
@springmarker 消息队列和 rpc 是两种不同的通信模式,消息队列是 publish/subscribe 模式,rpc 是 request/reply 模式,我们不说同步、异步的问题,很明显消息队列是单向通信,rpc 是双向通信,所以只要有单身通信能力就可以实现队列,有双向通信能力就可以实现 rpc,因此当然你搞两个消息队列就可以实现 rpc 是没有问题的。但是所有功能实现都是有其目的和衡量指标的,就 rpc 来说,主要目的是实现计算的扩展,把本地方法调用扩展到远程、分布式方法调用,计算需要逻辑(必要使用同步保证)和速度,因此 rpc 有两个指标:响应时间(延迟)和吞吐率( client 端和 server 端),且响应时间是更重要的,毕竟吞吐率是很容易通过扩展提升的。你的想法就是在直连 rpc 的中间加上一个队列,把 brokerless 的 rpc 变成了 brokered。在 client 端和 server 端条件不变的情况下,可能增加了 client 端的吞吐率(为什么是可能,因为 rpc 的 server 端也是有缓冲队列的啊),server 端吞吐率就算不变吧(不可能变得更好),整体响应时间肯定变长了,所以这个改变有什么意义呢?要实现你所说的优点完全可以在 client 端和 server 端做改进,没必要添加中间层啊?
sampeng
2019-07-05 12:36:09 +08:00
两个都用有什么问题……
springmarker
2019-07-05 12:36:30 +08:00
@Duluku #81 我觉得都使用微服务了,是否对代码由侵入性显得没那么重要,而且我觉得对于微服务中使用 传统 RPC 代理的模式 本身就有点不那么清真,微服务“远程调用”就该显式的告知调用者这是远程服务,调用者也不会滥用。队列消息可以设置被一次消费还是多次消费。关于性能,开头我就说了肯定不如传统 RPC,但是吞吐量应该还是有一定保证的。

@1ffree #82 解耦、相较之均衡的负载、(可能)更稳定的消息,在微服务种有的话不会好一些吗。

@langxuan #83 延时肯定有的,开头我也说了。关于消息堆积,本质上还是消费者消费速度慢,你消费速度慢不管用什么 RPC 他都得堆积,只不过传统 RPC 堆积的地方在消费者网卡缓存 /内存中而已,而堆积过大会可能导致消息丢失 /内存溢出等问题。

@justRua #87 消息的 100%的成功是每个程序员的梦想,既然都到了业务逻辑块了,为什么不处理一下呢,多浪费,直接返回繁忙不会显得失败率高吗?我觉得微服务面对的又不是用户,在超时限制之内这个消息就是有用的,返回繁忙只会徒增调用者的处理逻辑。你说的负载均衡是由调用者或注册中心判断的,由消费者直接判断自己的负载不是更简单和准确吗? kafka 的确是用 zookeeper 做注册中心,我开头第三条的意思其实是用队列可以解耦,就算用 kafka,调用者面对的只是队列,而不是众多消费者。

@version #89 我不知道你用的什么队列,2、3 秒实在夸张了,多数监听队列中间件的 driver 并不是轮询的方式,而是长连接,能做到什么样的性能我也不知道,所以我就是来问的。
sampeng
2019-07-05 12:38:16 +08:00
@sampeng 是你妖魔化了异步和同步…谁最合适用谁…哪来的非 0 即 1
webee
2019-07-05 12:41:37 +08:00
@springmarker 你据说的 100%成功不是对所有消息都有意义,消息也是有时效性的,过了时间就没有意义了,因此才有超时的概念,所以 rpc 请求堆积然后处理不即时丢失很正常啊。
Mohanson
2019-07-05 12:42:09 +08:00
据我浅薄的认知,json rpc 规范本身就要求用队列实现。
sampeng
2019-07-05 12:45:07 +08:00
按楼主的说法…一切皆 tcp。要啥 rpc。要啥队列。tcp 再底层点也是队列。要啥自行车?我们直接二进制编码好不好…
sampeng
2019-07-05 12:46:06 +08:00
不对。连 tcp 都不需要。直接撸 udp 啊。所有 tcp 的特性原则上 udp 都能实现 z
version
2019-07-05 12:46:50 +08:00
@springmarker 是可以 tcp 长轮..不过消息队列跨语言不好处理...而且你去看看阿里云.价格受不起..topic 按个数计算.请求按 4k 一次计算...烧不起...不过呢.阿里云本来就靠 java 方案赚钱的..
我的通用业务还是内网 rpc.自己起 thrift...省钱才是我中型企业的趋势...
服务器成本技术部成本?未来中国真有那么多土豪企业么?
springmarker
2019-07-05 12:50:36 +08:00
@sampeng #96 ???这个帖子压根就不是讨论同步异步的问题,是楼上歪楼了,他们的认知是 RPC 就只是同步的,用队列实现通讯就是只能是异步的。
feelinglucky
2019-07-05 12:50:40 +08:00
看戏模式,一楼已经结帖的事情还能扯那么多,真闲

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

https://tanronggui.xyz/t/580080

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

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

© 2021 V2EX