能用MQ就别用Rpc的9个理由

MQ和Rpc并无优劣,但是在不同的使用场景,需要具体问题具体分析使用哪种方式。

调用端关注调用结果,实时性强的场景,使用 rpc还是mq?

例如创建资源流程一般会对流程参数进行校验,如果参数不合理,则返回创建失败和具体的错误码、错误信息等,创建成功需要返回创建结果例如资源的唯一Id等。因为生产者发送完MQ消息并不知道消费者消费MQ的状态,更无法获知消费结果,所以这个场景并不适合Mq。rpc更适合这个场景,是因为被调用端通过定义Rpc接口,规定了请求入参和出参的格式,调用端像是调用本地方法一样调用服务端方法。

例如业务系统调用短信平台发送短信,就不适合使用MQ。这是因为短信平台会校验短信模版和短信参数是否一致,是否正确,校验短信长度是否符合要求,并告知调用端校验结果。相比Mq,Rpc恰恰更适合这个场景。

由于发送短信接口耗时比较高,使用Rpc可能会导致阻塞调用端。服务端可以在校验完成短信请求后,落库存储,使用MQ或线程池异步发送短信。

MQ和Rpc并无优劣,更多时候需要互相配合,需要根据实际场景选择合适的方案。

查询场景使用rpc还是mq?

因为查询场景调用端必定关注调用结果,所以查询场景,只能使用Rpc,不能使用MQ。不再多说。

异步调用场景,使用Rpc还是mq?

MQ天然支持异步,生产者发送消息成功即刻返回。消费者异步从消息队列推拉方式消费消息。 所以异步场景 MQ天然适合。那Rpc就不可以异步调用吗?

实际上各种Rpc框架都支持异步调用,共体现在三个地方

  1. 业务线程把Rpc请求任务丢到线程池
  2. Rpc 使用Netty NIO方式,使用非阻塞式IO,发送消息和处理请求时,不阻塞IO线程。
  3. Rpc被调用端异步处理,把消息丢弃到线程池处理。

虽然Rpc支持异步处理请求,但是相比MQ而言,更加复杂。不如MQ天然支持异步处理

在这个场景,MQ更胜一筹

发布订阅模式,新增消费组时,生产者无需关注

当有多个潜在消费者关注时,如果使用Rpc,就需要调用端逐个调用生产者,需要使用线程池异步并行调用多个服务者进行处理,并且需要处理超时、处理失败、耗时高等场景。实现较为复杂。 更重要的是,生产者系统并不关心消费者,为什么要修改生产者所在系统呢?

MQ更适用用这个场景。生产者将消息发送到消息队列后,就不再需要关心消息的处理结果。消息的可靠性投递、重试等特性都是消费队列实现。增加一个消费者,只需要在消息队列申请新的消费组即可。生产者系统无需任何改动。

在实际应用中,像订单状态变更消息,有大量消费者订阅,有大量的业务逻辑基于订单状态,通过MQ作为中间层,解耦了订单系统和下游系统。很难想象,如果是rpc依赖,订单系统要感知多少个下游,一个订单事件,要rpc通知多少个下游。

MQ支持广播模式

MQ除了支持一个Topic被多个应用服务、多个消费组消费,也支持将消息广播到每一个消费者实例。例如websocket场景,由于浏览器端websocket连接只能和一个服务端实例连接,所有发给这个socket实例的消息都要转发到这个服务端实例。简单的办法就是通过消息队列先广播给所有的服务器实例,然后服务端查询自己是否管理相关的websocket连接。 其他场景包括缓存数据同步、缓存失效等。都可以通过消息广播实现。rpc并不适用这个场景。

Mq接口格式更加灵活

一般情况下Rpc接口通过IDL或者Java/C++等语言定义,服务端需要实现该接口实现,调用端也需要引用接口依赖。而MQ在这方面更加灵活,生产者和消费者无需强依赖接口定义,两者只需要遵循相同的格式即可。例如定义消息的JSON格式,生产者和消费者按格式解析即可。

MQ相比Rpc在接口格式上更加灵活,如果希望上下游接口依赖更加灵活,可以考虑使用MQ

MQ可解耦生产者消费者,一般就是指

  1. 生产消费速度解耦
  2. 无需接口强依赖
  3. 异步调用解耦
  4. 订阅发布模式下新增消费组无感知等特性。

下面讨论消息队列在性能和稳定性上的优势。

MQ具备存储能力

消息投递到消息队列,会被可靠的存储,可以提供可视化页面提供消息列表查询能力,也可以通过数据通道工具,将kafka消息异构到Hive中,提供离线数据统计的能力。 同时MQ可提供消费端重新消费、回溯历史消息的能力,消费过程中存在异常,可以有效保证重试消费。最大程度保证处理流程的最终一致性。

MQ的存储能力相比Rpc 更强。

使用MQ和binlog实现数据核对

MQ消费端涉及到数据库操作会产生binlog,通过关联MQ和 binlog,可以发现处理失败的case。数据比对任务可以核对MQ和Binlog消息,在一个窗口期如果未关联上,说明这条消息处理出现问题。

把MQ消息离线同步到Hive,数据库同步到Hive中,还可以实现MQ消息和数据库的离线数据核对。

Rpc因为不具备存储能力,无法关联Rpc请求到binlog,自然无法实现数据正确性核对能力。

在数据正确性核对上,MQ更优

Rpc & MQ谁的可靠性更高

如何处理写请求的失败和超时是业务上必须思考的问题。一般情况下业务只需要保证最终一致性,通过重试可以有效解决超时和写失败的问题。

Rpc如何实现重试呢?可通过Spring-Retry框架,设置间隔时间、重试次数等参数进行重试。如果Rpc重试期间遇到服务发布、宿主机重启等问题,重试会中断,所以这种重试方式并不可靠。

MQ可以通过ack机制,多次消费同一条消息,重试多次依然失败,还可以投递到对应的死信队列,稍后继续重试和人工处理。消息队列有多种机制可以保证消费成功。消费者服务发布、宕机等因素也不会导致消息丢失、消息无法消费等情况发生。

相比Rpc,MQ在写场景可以更安全的重试,在可靠性上更强!

MQ & Rpc 吞吐量上谁更高

消息队列可以解决生产者和消费者速度上的差异,当生产者速率超过消费者速率时,消息会积压在消息队列,消费者可以根据服务的容量调整消费速率。 因为消息队列的存在,当消费者速率低时,不会拖累生产者。如果时Rpc同步调用,生产者因为消费者的低速率消费,大量线程会被阻塞,从而降低生产者的处理速度。

例如结算场景处理订单的支付完成消息,可以通过MQ解耦。结算场景不会影响C端用户的体验,结算处理的实时性要求并不高。在流量高峰期,结算处理可能赶不上订单支付速度,如果使用Rpc,结算性能瓶颈会降低C端用户交易链路的稳定性。

MQ的存储能力可以弥补消费端和生产端的消费速率之差,通过消息队列作为中间缓冲,可以削峰填谷,避免瞬时大量请求导致下游过载崩溃,避免两端速率之差导致的服务雪崩风险。

使用同步Rpc,系统的吞吐量受限于木桶最短的一侧。使用MQ解耦,则最大程度提供系统的吞吐。

消费端吞吐量的提升

Rpc服务端无法对多个rpc请求合并然后批量处理,但是MQ消费端可以使用pull拉取模式,批量拉取一批数据,将单次请求转为批量请求,可以有效提高处理速度。

综上来看,在查询场景、实时获取调用结果的写链路比较适合适用Rpc。在异步、实时性低、无需关注调用结果、多个订阅者的场景,优先使用MQ更为合理。

总结

  1. 调用端关注调用结果,实时性强的场景,Rpc更优
  2. 查询场景只能使用Rpc
  3. 异步调用场景,Rpc和MQ均可
  4. 存在多个订阅者场景,更适合使用MQ
  5. 需要广播的场景,适合MQ
  6. MQ接口格式更加灵活
  7. MQ具备存储能力,可以基于MQ和binlog进行数据正确性核对。
  8. MQ处理消息可安全重试,可靠性更强
  9. MQ作为缓冲,可以削峰填谷,弥补生产消费两端的速率之差,避免系统雪崩
  10. MQ通过批量拉取批量消费,可以有效提升系统吞吐量。
相关推荐
小诸葛的博客5 分钟前
开发一个go模块并在其他项目中引入
开发语言·后端·golang
Emma歌小白6 分钟前
初步使用UML设计代码结构
后端
哔哩哔哩技术7 分钟前
2025 B站春晚直播——技术保障复盘
架构
剽悍一小兔27 分钟前
Java8默认方法の终极奥义
后端
Emma歌小白30 分钟前
UML(Unified Modeling Language,统一建模语言)应用方向
后端
雷渊39 分钟前
mybatis底层为什么设计二层缓存?
java·后端·面试
QING61839 分钟前
一文带你了解Android中常见的跨组件通信方案及其适用场景
android·架构·app
祝瑾萱1 小时前
Go语言的负载均衡
开发语言·后端·golang
奔跑吧邓邓子1 小时前
【商城实战(39)】Spring Boot 携手微服务,商城架构焕新篇
spring boot·微服务·架构·商城实战
加个鸡腿儿1 小时前
01实战案例:「新手向」如何将原始数据转换为前端可用选项?
前端·程序员