在微服务中是用队列好还是 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,如果替换成队列会有什么影响吗?不需要高性能的场景下可以互相替换吗?

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

16823 次点击
所在节点    程序员
129 条回复
ErrorMan
2019-07-04 19:50:18 +08:00
回复 #18 楼主的观点,RPC 在设计上是同步的,只是实现上因为网络通信等各种原因实现成了异步,而队列在设计上就是异步模型,实现更不用说。
springmarker
2019-07-04 19:54:47 +08:00
@ErrorMan #21 那如果设计一个由队列实现的 RPC 呢?
l8g
2019-07-04 19:57:58 +08:00
显然大部分场景都是替代不了的,楼主连 RPC 的作用都没有理解。
再举个最简单的例子,如果 A 调用 B 是需要返回值的,换成 MQ 怎么做?难道 A 先发 MQ 消息给 B,B 再发一个 MQ 消息回来给 A ?
PRC 是为了不同服务之间通信,一般是关心结果的。
MQ 往往是为了解耦,消息生产者不关心谁消费消息,消费者也不关心这个消息是谁发送的,你用 MQ 替代 RPC,反而是耦合在了一起,与 MQ 的思想完全相违背。
再看你列的 3 点,
1. 在 MQ 和 RPC 都是稳定的前提下,你怎么就能说 MQ 比 PRC 丢消息的概率低,你有验证过吗?再者 RPC 的异常是很容易监控的,MQ 丢消息反而不是那么容易发现。
2. RPC 怎么就无法负载均衡了呢?
3. 谁和你说 MQ 没有注册中心?没有注册中心,生产者不知道把消息发到哪里,消费者也不知道去哪里拉消息,早乱套了。
先问是不是,再问为什么。
zhangtao
2019-07-04 20:02:22 +08:00
可以这么理解,微服务化之后,服务之间的通信方式可以分为 2 种,同步和异步:
同步的方式,就是用 RPC 或者 rest
异步的方式,就是用消息队列(rabbitmq/rocketmq/kafka)之类的,可以提供消息的订阅和通知
看具体的业务场景,谁也无法被谁替代
petelin
2019-07-04 20:03:19 +08:00
这不就是同步和异步的区别吗
springmarker
2019-07-04 20:11:04 +08:00
@l8g #23 RPC 不也是 A 发个消息给 B,B 再发个消息给 A 吗?
我没测试过丢消息的概率,只是按照我的经验来说的,我也不是来发表文章说队列比 RPC 好,你有异议可以随时说。
关于负载均衡,我没说过 RPC 无法负载均衡,原话是“无法均衡的负载”,因为传统 RPC 的 Client 或中间的负载均衡(如 Nginx)都无法判断 Server 是否繁忙,只是相比较而言,而不是"无法负载均衡"。
你说的可能是 kafka 的注册中心,我想的是以 RabbitMQ 为基础,就算你 Client 和 Server 使用了类似 kafka 的注册中心,那面对的也只是 kafka,而不是 Client 和 Server。
miv
2019-07-04 20:15:23 +08:00
RPC 是 A 服务请求 B 服务,然后 A 就可以拿到 B 返回的结果了,不需要“ B 再发消息给 A ”了。
springmarker
2019-07-04 20:16:13 +08:00
@zhangtao #24
@petelin #25
我的理解是 RPC 和队列本质上都是在异步基础上实现的,理论上队列同样可以实现 RPC 的功能,但是队列因为协议的关系,会多出一些传统 RPC 没有的功能,我的设想是在这两者之间比较。
springmarker
2019-07-04 20:18:17 +08:00
@miv #27 谁跟你说 B 不需要发送给 A 的?那你的 RPC 获取的数据是从哪里拿的?
zhangtao
2019-07-04 20:23:08 +08:00
@springmarker 你的理解有问题,RPC 就是同步返回结果,而且微服务大量的场景都是需要同步等待返回结果,可以看看 GRPC 的 server 端实现
springmarker
2019-07-04 20:26:25 +08:00
@zhangtao #30 RPC 底层都是通过 socket 流来传输的,再往下就是 TCP 了,都没有同步这一说,都是 RPC 内部实现的同步功能。
miv
2019-07-04 20:27:40 +08:00
我的意思是 A 通过一次网络请求拿到了 B 返回的数据。
像 23 楼说的,队列 A 发送消息给 B,B 发送消息给 A,这是 2 次网络请求了。
所以,你 26 楼说的“ RPC 不也是 A 发个消息给 B,B 再发个消息给 A 吗?”,这个地方就是不同之处了。
其他的我感觉楼上已经说很明白了。
qiyuey
2019-07-04 20:34:30 +08:00
削峰、解耦、异步这个三个目的用 MQ,同步调用用 RPC
springmarker
2019-07-04 20:35:24 +08:00
@miv #32 传统 RPC 基本都是长连接,TCP 本来就是双工的,Client 请求过去,Server 收到再返回,只是你人为的理解为两次请求,Server 做的不是请求,而是把这个返回值放到这个 TCP 流中,实质上是一样的。
petelin
2019-07-04 20:41:24 +08:00
队列的方式扩容怎么做请教一下?
Aresxue
2019-07-04 20:42:14 +08:00
这俩比较相似的地方就是都能完成通信,内部都有自定义的一套序列化标准和传输协议。但两者的区别也很明显,RPC 是同步消息队列异步(业务上而非调用上),RPC 适用于要求强一致性的场景,消息队列天然就是弱关联性的(有持久化机制可以做弥补,消息重发、位点重置啥的)。
petelin
2019-07-04 20:42:15 +08:00
还是用中心化注册 客户端发现这套吗
petelin
2019-07-04 20:43:46 +08:00
我觉得如果从 tcp 角度上看 rpc 已经是基于队列了 而且没有明显的缺点 为什么要瞎搞
cheng6563
2019-07-04 20:45:37 +08:00
要用队列就肯定要异步编程
你猜 go 语言是怎样火起来的
NewDraw
2019-07-04 20:46:15 +08:00
这楼主有点憨啊,说了半天都只说“队列”,队列和消息队列能混为一谈吗?以上只是发个牢骚,见谅。
接下来讲道理:
按照楼主的想法,我们暂且假定“队列”是消息队列。
① 那么调用方向服务方发起调用→向消息队列主题 a 发请求消息
② 服务方接收消息并处理得到结果后,自然不能直接返回结果,所以只能使用另外一个主题 b,发结果消息。
③ 调用方必须再从主题 b 来获取消息。但是此时,消费主题 b 的消费者大概率是多机多线程,如何让指定的消息被指定的机器线程消费呢?

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

https://tanronggui.xyz/t/580080

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

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

© 2021 V2EX