V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
springmarker
V2EX  ›  程序员

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

  •  
  •   springmarker · 2019-07-04 18:11:01 +08:00 · 16748 次点击
    这是一个创建于 2000 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

    第 1 条附言  ·  2019-07-04 20:48:27 +08:00
    额,大家讨论起了异步和同步的问题来了,其实我想问的不是这个,我的设想是如果队列包装成类似 RPC 的功能,拥有队列的特性的同时也有 RPC 的功能 这样是否可行?
    第 2 条附言  ·  2019-07-04 22:10:38 +08:00
    大家好像对 RPC 的同步调用很有执念啊,RPC 实现同步本质还是异步转同步,大家就不用讨论异步同步的问题了,不要妖魔化了 RPC/rest
    129 条回复    2020-07-30 10:36:38 +08:00
    1  2  
    shawndev
        1
    shawndev  
       2019-07-04 18:27:34 +08:00   ❤️ 7
    rpc 是通信手段,队列是数据结构。出现这种数据结构是因为内容可能会并发,堆积。所以我理解的两个东西不是一回事,不存在取代的关系。

    猫能取代音乐吗?你要说能也算能。但我不会这么说。
    springmarker
        2
    springmarker  
    OP
       2019-07-04 18:31:02 +08:00
    @shawndev #1 两者可能并没有明显的界限,RPC 同样可以用队列实现,这个帖子也不是对 “队列和 RPC 之前的区别”的讨论,而是在微服务中,两者用哪种更好一些。
    xmge
        3
    xmge  
       2019-07-04 18:31:38 +08:00
    @shawndev 感觉楼主的意思是:通过猫去接近一个姑娘,还是通过音乐。 可能通过猫更好一点吧
    ikaros
        4
    ikaros  
       2019-07-04 18:33:43 +08:00
    1 楼结帖
    Kaiv2
        5
    Kaiv2  
       2019-07-04 18:34:39 +08:00 via Android
    消息队列用来做异步处理,RPC 做同步处理。我的项目都是这样做的
    sin30
        6
    sin30  
       2019-07-04 18:36:38 +08:00
    我理解强依赖的调用关系,肯定是要走 RPC,并且明确获得返回结果的情况下才能继续的。
    那些弱依赖的,类似只是通知一下其他服务做动作的,可以做成队列异步执行的,确保最终一致就行。
    但是这个界限还是比较模糊的,理论上是可以把所有对外的调用都做成队列消息,异步让其他服务处理,不过这样的话设计起来就会复杂很多,你得定义多少消息类型,异步任务啊。
    Aruforce
        7
    Aruforce  
       2019-07-04 18:38:04 +08:00
    估计说的队列指的是具有 MQ 这类功能的东西吧;
    需要返回结果的时候....用队列的还要将调用方线程阻塞掉使异步变同步,调用方线程不还是阻塞着么?那调用方线程直接 RPC 不行么?还用加个队列?这不是脱裤子放屁么....
    springmarker
        8
    springmarker  
    OP
       2019-07-04 18:39:08 +08:00
    @ikaros #4 标题可能说的没那么明确,我再说清楚一点吧,我的意思是:现在 RPC 基本上都是“ client 直接连接 server (可能有个注册中心)”的模式,我说的 RPC 也指代这种 RPC。在使用这种 RPC 的业务中,同样可以用队列来实现,而且有些队列的优点是 RPC 无法取代的。
    51300520
        9
    51300520  
       2019-07-04 18:39:50 +08:00
    同步的用 rpc,异步的用队列,特别是量大要缓冲或者时间久那种,像发邮件。rpc 现在一般是用 etcd 或者 consul 这种来服务注册来实现类似 zookeeper 的功能
    keepeye
        10
    keepeye  
       2019-07-04 18:42:23 +08:00
    微服务跟队列有冲突吗?压根不是一个概念啊老兄
    keepeye
        11
    keepeye  
       2019-07-04 18:43:19 +08:00
    rpc 是微服务之间通信方式 队列是异步处理耗时任务的方式
    springmarker
        12
    springmarker  
    OP
       2019-07-04 18:46:09 +08:00
    @sin30 #6 RPC 在网络层面也是异步,都得靠程序来保证同步异步。

    @Aruforce #7 RPC 也是阻塞啊,我也没有说队列性能高啊。

    @keepeye #11 我觉得不冲突,RPC 在网络层面也是异步,同样是靠程序保证同步。
    monsterxx03
        13
    monsterxx03  
       2019-07-04 18:56:46 +08:00
    我的理解你是想用 rabbitmq 之类的 队列 broker 来实现类似 rpc 的同步调用方式?
    chmaple
        14
    chmaple  
       2019-07-04 19:00:21 +08:00
    我一点点来说
    第一点,丢失的概率,消息是会丢的、会失败的、可能要回滚的,RPC 立即返回结果或者使用 netty 之类的 NIO 框架管理 channel 返回结果,在这个角度上是 RPC 优于队列的,队列最大的好处是可以积压,但是最大的坏处就是本质是异步无法直接知道结果。
    第二点,负载均衡,Nginx 是用来做什么的,要负载为什么不让专业的来而要自己来靠队列来实现均衡?
    第三点,nginx 完美解决你的问题,发送端和接收端只要对接 nginx 就可以了

    如果让我选择服务间通讯,我毫不犹豫会选 RPC 框架,实现简单、同步结果,项目简单的话我干脆面向 socket 编程,越粗暴越简单越好,再上一层就 NIO,多节点就上 nginx。
    多了队列,就要维护队列、路由、TOPIC,要多一个 MQ 的监控和运维,要多考虑异步失败处理,要多个队列 listener 线程池和一堆相关的事情。
    springmarker
        15
    springmarker  
    OP
       2019-07-04 19:12:18 +08:00
    @chmaple #14
    1.netty 之类的返回数据也是异步,同样还是得靠 RPC 内部来控制同步,你要返回数据,使用双向队列 /两条队列同样不是不可能。
    2.关于负载均衡,传统 RPC 和 Nginx 都是主动向 Server 端发送数据,这两者都无法或者很难判断 Server 端是否繁忙,如果由 Server 端主动判断自己是否空闲并获取消息不是更简单吗。

    你说的简单粗暴是因为 RPC 封装好了网络和异步转同步细节,如果有成熟度和传统 RPC 差不多的由队列实现的 RPC,效果不是一样吗?
    xuanbg
        16
    xuanbg  
       2019-07-04 19:15:22 +08:00
    除非是错误信息能够返回前端的,否则都用队列传递数据而非 RPC。
    henry19890701
        17
    henry19890701  
       2019-07-04 19:34:16 +08:00
    @chmaple 同步调用,一样会出现类似“丢失的”,你远程 rpc 调用,报了了网络层超时,你咋知道对放接口是操作了,还是没操作

    本质上,这两是两种编程模型:同步,异步。看你场景,哪个组织代码的逻辑比较顺畅,就用哪个,当然,绝大部分,还是同步的模型好理解
    springmarker
        18
    springmarker  
    OP
       2019-07-04 19:39:44 +08:00
    @henry19890701 #17 我觉的本质上,无论 RPC 和队列,都是异步的,只不过 RPC 在异步的基础上提供了同步的功能,理论上队列同样可以封装一下改为同步。
    justRua
        19
    justRua  
       2019-07-04 19:41:21 +08:00
    你是想把 MQ 当做请求的分发器,等于所有请求都先到了 MQ,然后再给服务端消费。以前公司做 ETL 时有个类似的场景,数据抽取转换后先扔到 kafka,每个入库的程序去 kafka 拉取数据存数据库。这种需要数据不丢失的场景下挺合适的,大多业务场景的请求当服务器响应不过来了就丢弃了,把请求持久化保存起来也没用。
    springmarker
        20
    springmarker  
    OP
       2019-07-04 19:49:02 +08:00
    @justRua #19 为什么要丢弃呢?既然用了微服务,只要不设置超时,这个请求不就是一直有用吗?
    ErrorMan
        21
    ErrorMan  
       2019-07-04 19:50:18 +08:00
    回复 #18 楼主的观点,RPC 在设计上是同步的,只是实现上因为网络通信等各种原因实现成了异步,而队列在设计上就是异步模型,实现更不用说。
    springmarker
        22
    springmarker  
    OP
       2019-07-04 19:54:47 +08:00
    @ErrorMan #21 那如果设计一个由队列实现的 RPC 呢?
    l8g
        23
    l8g  
       2019-07-04 19:57:58 +08:00   ❤️ 5
    显然大部分场景都是替代不了的,楼主连 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
        24
    zhangtao  
       2019-07-04 20:02:22 +08:00   ❤️ 4
    可以这么理解,微服务化之后,服务之间的通信方式可以分为 2 种,同步和异步:
    同步的方式,就是用 RPC 或者 rest
    异步的方式,就是用消息队列(rabbitmq/rocketmq/kafka)之类的,可以提供消息的订阅和通知
    看具体的业务场景,谁也无法被谁替代
    petelin
        25
    petelin  
       2019-07-04 20:03:19 +08:00 via iPhone   ❤️ 1
    这不就是同步和异步的区别吗
    springmarker
        26
    springmarker  
    OP
       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
        27
    miv  
       2019-07-04 20:15:23 +08:00
    RPC 是 A 服务请求 B 服务,然后 A 就可以拿到 B 返回的结果了,不需要“ B 再发消息给 A ”了。
    springmarker
        28
    springmarker  
    OP
       2019-07-04 20:16:13 +08:00
    @zhangtao #24
    @petelin #25
    我的理解是 RPC 和队列本质上都是在异步基础上实现的,理论上队列同样可以实现 RPC 的功能,但是队列因为协议的关系,会多出一些传统 RPC 没有的功能,我的设想是在这两者之间比较。
    springmarker
        29
    springmarker  
    OP
       2019-07-04 20:18:17 +08:00
    @miv #27 谁跟你说 B 不需要发送给 A 的?那你的 RPC 获取的数据是从哪里拿的?
    zhangtao
        30
    zhangtao  
       2019-07-04 20:23:08 +08:00
    @springmarker 你的理解有问题,RPC 就是同步返回结果,而且微服务大量的场景都是需要同步等待返回结果,可以看看 GRPC 的 server 端实现
    springmarker
        31
    springmarker  
    OP
       2019-07-04 20:26:25 +08:00
    @zhangtao #30 RPC 底层都是通过 socket 流来传输的,再往下就是 TCP 了,都没有同步这一说,都是 RPC 内部实现的同步功能。
    miv
        32
    miv  
       2019-07-04 20:27:40 +08:00
    我的意思是 A 通过一次网络请求拿到了 B 返回的数据。
    像 23 楼说的,队列 A 发送消息给 B,B 发送消息给 A,这是 2 次网络请求了。
    所以,你 26 楼说的“ RPC 不也是 A 发个消息给 B,B 再发个消息给 A 吗?”,这个地方就是不同之处了。
    其他的我感觉楼上已经说很明白了。
    qiyuey
        33
    qiyuey  
       2019-07-04 20:34:30 +08:00
    削峰、解耦、异步这个三个目的用 MQ,同步调用用 RPC
    springmarker
        34
    springmarker  
    OP
       2019-07-04 20:35:24 +08:00
    @miv #32 传统 RPC 基本都是长连接,TCP 本来就是双工的,Client 请求过去,Server 收到再返回,只是你人为的理解为两次请求,Server 做的不是请求,而是把这个返回值放到这个 TCP 流中,实质上是一样的。
    petelin
        35
    petelin  
       2019-07-04 20:41:24 +08:00 via iPhone
    队列的方式扩容怎么做请教一下?
    Aresxue
        36
    Aresxue  
       2019-07-04 20:42:14 +08:00   ❤️ 1
    这俩比较相似的地方就是都能完成通信,内部都有自定义的一套序列化标准和传输协议。但两者的区别也很明显,RPC 是同步消息队列异步(业务上而非调用上),RPC 适用于要求强一致性的场景,消息队列天然就是弱关联性的(有持久化机制可以做弥补,消息重发、位点重置啥的)。
    petelin
        37
    petelin  
       2019-07-04 20:42:15 +08:00 via iPhone
    还是用中心化注册 客户端发现这套吗
    petelin
        38
    petelin  
       2019-07-04 20:43:46 +08:00 via iPhone
    我觉得如果从 tcp 角度上看 rpc 已经是基于队列了 而且没有明显的缺点 为什么要瞎搞
    cheng6563
        39
    cheng6563  
       2019-07-04 20:45:37 +08:00 via iPhone
    要用队列就肯定要异步编程
    你猜 go 语言是怎样火起来的
    NewDraw
        40
    NewDraw  
       2019-07-04 20:46:15 +08:00 via Android   ❤️ 2
    这楼主有点憨啊,说了半天都只说“队列”,队列和消息队列能混为一谈吗?以上只是发个牢骚,见谅。
    接下来讲道理:
    按照楼主的想法,我们暂且假定“队列”是消息队列。
    ① 那么调用方向服务方发起调用→向消息队列主题 a 发请求消息
    ② 服务方接收消息并处理得到结果后,自然不能直接返回结果,所以只能使用另外一个主题 b,发结果消息。
    ③ 调用方必须再从主题 b 来获取消息。但是此时,消费主题 b 的消费者大概率是多机多线程,如何让指定的消息被指定的机器线程消费呢?
    l8g
        41
    l8g  
       2019-07-04 20:49:59 +08:00 via iPhone
    @springmarker RPC 当然也要来回发送 但 RPC 本身就不是为了解耦
    springmarker
        42
    springmarker  
    OP
       2019-07-04 21:00:45 +08:00
    @NewDraw #40 我觉得有“微服务”,“ RPC ”,“队列”这三个关键词,不是很容易想到消息队列吗?
    最坏的情况是请求带标志头,让服务端判断放在哪个队队列,最坏的情况队列 数量 =( Client+1 ),如果有类似 ActiveMQ 的消息过滤器的功能,队列数量就可以缩减到两个。
    springmarker
        43
    springmarker  
    OP
       2019-07-04 21:05:32 +08:00
    @petelin #38 传统 RPC 没有消息冗余、解耦等队列的特性
    ntop
        44
    ntop  
       2019-07-04 21:12:44 +08:00
    当然是可以的,我司现在就是在 80% 的场景上使用消息队列取代 RPC,从本质上看消息队列和 RPC 都是一个消息管道,如果消息采用对方确认返回的模式那么和 RPC 在行为上就一致了。消息在性能上可能不如 RPC,我司现在用的是 NATs 一个 go 写的超高性能的消息系统,只有极个别对性能要求甚高的系统采用 RPC 直连。我司主要做社区 /论坛系统的,目前还没有遇到啥问题。
    NewDraw
        45
    NewDraw  
       2019-07-04 21:17:33 +08:00 via Android   ❤️ 1
    @springmarker

    探讨问题应该把题目说清楚,而不是让别人去猜,总之很别扭。
    如果完全不考虑性能因素,只关注实现功能,那么消息队列确实能实现 rpc 的所有功能,无论异步还是同步。
    但是本质上来说消息队列和 rpc 都是基于 tcp 链接,所以似乎没有什么突破。
    springmarker
        46
    springmarker  
    OP
       2019-07-04 21:26:44 +08:00
    @NewDraw #45 大家都认为传统 RPC 的主要功能就是同步调用,但是使用同步 RPC 调用本身就是高性能编程的大忌(指无协程的语言),我想用队列实现类似 RPC 的功能 其实更想要的是队列的特性所带来的好处。
    gz911122
        47
    gz911122  
       2019-07-04 21:42:42 +08:00
    @zhangtao rest 怎么就同步了呢?rpc 怎么就同步了呢?
    异步 rest 不比同步的多多了?
    gz911122
        48
    gz911122  
       2019-07-04 21:43:36 +08:00
    @zhangtao 你的理解严重有问题
    billlee
        49
    billlee  
       2019-07-04 21:48:58 +08:00
    akka 了解一下
    springmarker
        50
    springmarker  
    OP
       2019-07-04 22:24:05 +08:00
    @l8g #41 我没说 RPC 是用来解耦的,难道拥有解耦的特性不好吗
    ccpp132
        51
    ccpp132  
       2019-07-04 22:25:38 +08:00 via Android
    用队列实现 rpc 就是 rpc,和其他的 rpc 比没更多好处。
    另外这是一个不同层面的东西,你实现一个消息队列服务也要通过 rpc 把新的请求放入队列中,所以不可能脱离 rpc
    windfarer
        52
    windfarer  
       2019-07-04 22:25:44 +08:00 via Android
    zeromq 了解一下
    springmarker
        53
    springmarker  
    OP
       2019-07-04 22:31:32 +08:00
    @ccpp132 #51 1.一开始括号里我也说了,指的是以传统 RPC 来比较。2.为什么要通过 RPC 把消息放入队列,直接用消息队列的驱动放进去不好吗?
    ccpp132
        54
    ccpp132  
       2019-07-04 22:36:38 +08:00 via Android
    @springmarker 你想想,消息队列的驱动怎么做,是不是要发消息给消息队列的服务器,是不是要收响应看是否成功,是不是要处理失败重试负载均衡等问题,这不就是一个 rpc
    springmarker
        55
    springmarker  
    OP
       2019-07-04 22:44:12 +08:00
    @ccpp132 #54 额,这样理解的话,连接数据库也属于一个 RPC 了。
    关于检查成功、重试等问题,也是事先想到了,因此性能肯定不如直接传统 RPC 调用,一开头我也说了。
    也正因是如此复杂,所以带来了队列的一些特性,开头我也说了。
    ccpp132
        56
    ccpp132  
       2019-07-04 23:00:21 +08:00 via Android   ❤️ 1
    @springmarker 你先想明白一点,rpc 就是这么个概念,同步请求得到结果。和底下的实现关系不大。现在的优缺点放你用 mq 实现也还是一样,不会变的,要不然人家 grpc 底层就改掉就完了。
    springmarker
        57
    springmarker  
    OP
       2019-07-04 23:11:03 +08:00
    @ccpp132 #56 你是用传统 RPC 和由 MQ 实现的“ RPC ”直接进行比较,我想的是在微服务中他俩效果有什么差距,我并不希望由 MQ 实现的“ RPC ”是同步调用,本来就不符合队列的特性,只是利用它来传输信息并异步返回数值,同时拥有 MQ 的特性。
    springmarker
        58
    springmarker  
    OP
       2019-07-04 23:17:08 +08:00
    @ccpp132 #56 我一开始想问的就是在最大利用 MQ 特性实现异步“ RPC ”的特性的同时,他俩效果有什么差距,我也并不想鼓吹队列多么多么好,只是上面很多人回答的不到点上。
    chinvo
        59
    chinvo  
       2019-07-04 23:22:00 +08:00 via iPhone   ❤️ 2
    #迷惑行为大赏
    ccpp132
        60
    ccpp132  
       2019-07-04 23:35:42 +08:00 via Android
    rpc 和 mq 这两个东西的层次有一些不同,直接放一起比是容易跑偏,主要是两者也不是可以完全互相替代的。你应该也明白如果就是需要一个同步操作的时候,用队列实现 rpc 不会有太多的优点。除非是处理时间非常长的任务,你不能接受网络连接断开进行重试。因为异步的模型就是比同步的更难理解和维护,所以大家都愿意用 rpc
    scnace
        61
    scnace  
       2019-07-04 23:53:22 +08:00 via Android
    业界本来就有这种实践吧 用 MQ 就属于消息型接口了 这种情况下我觉得不太适合高并发的场景?当然也能做但是相比 rpc 的实现来说,这种实现是不是成本也会更高了(比如还要多考虑下 MQ 的 backend ) 还有,容错方面 ,如果哪天 MQ 的集群因为某些原因炸了,那我的接口是不是都炸了? 但是我始终觉得存在就是合理的,比如这种消息型接口在某些允许离线的工作模式下面价值就可以发挥出来(大晚上 XJB 乱打的)
    Raymon111111
        62
    Raymon111111  
       2019-07-05 00:12:09 +08:00
    阿里, 京东订单的状态流转是全部消息队列推动的.
    petelin
        63
    petelin  
       2019-07-05 07:52:40 +08:00 via iPhone
    那你有想过为了付出消息队列的你说的这两个特性需要付出多少代价吗

    我觉得你这个有搞头但不可能像 http2.0 对 http1.1 那样的颠覆性
    算是加 feature 不算是升级
    HunterPan
        64
    HunterPan  
       2019-07-05 08:25:07 +08:00
    zeroMQ 了解下,就是队列形式
    luozic
        65
    luozic  
       2019-07-05 08:39:39 +08:00 via iPhone
    两个有关系么?队列里面也可以塞 rpc 啊。有些 rpc 也支持队列啊。
    luozic
        66
    luozic  
       2019-07-05 08:51:59 +08:00 via iPhone
    rpc 不等价于同步。rpc 讲的是数据传输层的活;消息队列是传输数据的组织方式。 一个是用啥交通工具(汽车,飞机,火车),一个是物流方式,无中心点对点,还是有物流中心集中调配。怎么就可以对比了?
    hhyvs111
        67
    hhyvs111  
       2019-07-05 08:52:08 +08:00 via iPhone
    两者都不是一个类型,有什么好比的?
    no1xsyzy
        68
    no1xsyzy  
       2019-07-05 09:15:46 +08:00
    微服务本来就是队列的( erlang ),只不过后来发现写面向对象的写不来队列才这样的。
    本来同步就是伪问题,我们活在爱因斯坦的世界。
    blackccc
        69
    blackccc  
       2019-07-05 09:36:56 +08:00
    学习了
    reus
        70
    reus  
       2019-07-05 09:39:30 +08:00
    队列服务也可以有 rpc 接口。rpc 接口也可以用队列来处理请求。
    两者不是互斥的
    Takamine
        71
    Takamine  
       2019-07-05 09:59:06 +08:00
    要什么队列要什么 RPC,大家一起走 HTTP 接口不好吗。
    q397064399
        72
    q397064399  
       2019-07-05 10:03:19 +08:00
    看你的整体的架构风格,很多系统可以拆分成 事件驱动来完成的话,消息队列很明显是一个非常好的东西,没有强一致性需求的时候 是非常不错的。
    justRua
        73
    justRua  
       2019-07-05 10:07:31 +08:00
    @Takamine 走 http 也算是 RPC 啊,RPC 可以通过 tcp http 等的方式实现,消息载体可以是 json、xml、二进制等
    Takamine
        74
    Takamine  
       2019-07-05 10:17:40 +08:00
    @justRua 我说的 HTTP 接口就是最直接的封装好暴露接口的业务逻辑,哪怕是一个 1+1,我也写个接口给你,要什么队列,要什么 RPC :doge:。
    javaWeber
        75
    javaWeber  
       2019-07-05 10:27:01 +08:00
    "Spring Cloud 的 RPC ?"
    其实,SpringCloud 是基于 restful 的。Dubbo 才是基于 rpc 的。
    rpc 是远程远程调用。通过某些协议调用其他模块的接口。
    restful 是类似于用 url 进行 http 请求。
    index90
        76
    index90  
       2019-07-05 10:42:45 +08:00
    可行,微信的后台就有类似实践
    Aresxue
        77
    Aresxue  
       2019-07-05 11:06:38 +08:00
    @javaWeber http 也属于广义的 RPC,RPC 这个概念被滥用了,如果不严格限制的话消息队列也算是一种异步的 RPC。。。狭义的 RPC 才是 dubbo、hsf、grpc 这些
    Duluku
        78
    Duluku  
       2019-07-05 11:16:49 +08:00 via iPhone
    这个可不是同步和异步的关系、异步 gRPC 调用也是有的…
    springmarker
        79
    springmarker  
    OP
       2019-07-05 11:22:48 +08:00
    @petelin #63 ...... 我没有说颠覆性,我理解的优缺点我开头就说了,实现所需要付出的代价肯定是有的,但是同时也会带来一些队列的特性,我想知道如果两者放在微服务效果是怎样的,是否值得。我不是鼓吹队列肯定比传统 RPC 好,你们只是一个劲的反驳,看的我莫名其妙。

    @scnace #61 性能不如传统 RPC 是必然的,但是同时高并发的压力也会转移到队列中一部分去。关于炸了,个人觉得现在队列都有分布式,应该还好。

    @luozic #66 都可以放在微服务通讯中,为什么不可以比较?

    @reus #70 我想的就是因为不是互斥的,在某些场景是可以替换的,想知道两者在微服务中的差距。

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

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

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

    正常一个 api 请求.例如 100ms 内部其实已经掉用了 5 个 rpc 了......消息队列能做到吗
    webee
        90
    webee  
       2019-07-05 12:33:03 +08:00   ❤️ 1
    @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
        91
    sampeng  
       2019-07-05 12:36:09 +08:00 via iPhone
    两个都用有什么问题……
    springmarker
        92
    springmarker  
    OP
       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
        93
    sampeng  
       2019-07-05 12:38:16 +08:00 via iPhone
    @sampeng 是你妖魔化了异步和同步…谁最合适用谁…哪来的非 0 即 1
    webee
        94
    webee  
       2019-07-05 12:41:37 +08:00
    @springmarker 你据说的 100%成功不是对所有消息都有意义,消息也是有时效性的,过了时间就没有意义了,因此才有超时的概念,所以 rpc 请求堆积然后处理不即时丢失很正常啊。
    Mohanson
        95
    Mohanson  
       2019-07-05 12:42:09 +08:00 via Android
    据我浅薄的认知,json rpc 规范本身就要求用队列实现。
    sampeng
        96
    sampeng  
       2019-07-05 12:45:07 +08:00 via iPhone
    按楼主的说法…一切皆 tcp。要啥 rpc。要啥队列。tcp 再底层点也是队列。要啥自行车?我们直接二进制编码好不好…
    sampeng
        97
    sampeng  
       2019-07-05 12:46:06 +08:00 via iPhone
    不对。连 tcp 都不需要。直接撸 udp 啊。所有 tcp 的特性原则上 udp 都能实现 z
    version
        98
    version  
       2019-07-05 12:46:50 +08:00
    @springmarker 是可以 tcp 长轮..不过消息队列跨语言不好处理...而且你去看看阿里云.价格受不起..topic 按个数计算.请求按 4k 一次计算...烧不起...不过呢.阿里云本来就靠 java 方案赚钱的..
    我的通用业务还是内网 rpc.自己起 thrift...省钱才是我中型企业的趋势...
    服务器成本技术部成本?未来中国真有那么多土豪企业么?
    springmarker
        99
    springmarker  
    OP
       2019-07-05 12:50:36 +08:00
    @sampeng #96 ???这个帖子压根就不是讨论同步异步的问题,是楼上歪楼了,他们的认知是 RPC 就只是同步的,用队列实现通讯就是只能是异步的。
    feelinglucky
        100
    feelinglucky  
       2019-07-05 12:50:40 +08:00
    看戏模式,一楼已经结帖的事情还能扯那么多,真闲
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1004 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 20:20 · PVG 04:20 · LAX 12:20 · JFK 15:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.