分布式知识 -- RPC 和消息队列

本文最后更新于:4 天前

RPC 作用

  1. 解决不同主机通信问题

  2. 解决接口寻址问题

消息队列作用

  1. 应用服务解偶

  2. 流量限制

  3. 异步通信

RPC 和消息队列的区别

  1. RPC是调用模式,MQ是实现模式。

  2. 二者侧重点不一样,RPC侧重两端,MQ侧重中间(中间件)

  3. RPC 底层通常没有队列,而消息队列一定有

  4. RPC指的是远程调用,也就是说,调用的函数不在同一内存空间内,强调的是远程,具体怎么实现的远程,并不强求。MQ是网络中的通用队列,它不在乎存储的数据格式,可以是数据,可以是任务,它只是提供了一个存放的场所,规定了存取的方式。可以用它发布消息,分发任务,也可做RPC实现。它是通用,异步,和解耦的。

  5. RPC 客户端只是一个桩(stub),真正服务提供者在服务端(类似 CS 模式)。消息队列客户端就是消息本身

  6. RPC 和消息队列的选择

    1. RPC 是同步的,在实时性要求比较高的条件下 RPC 是首选

    2. 消息队列可以存储消息,崩溃后恢复,消息不丢失

    3. RPC 同步调用瓶颈,改用异步消息队列调用提高吞吐量

例子:

RPC:假设你是一个饭店里的服务员,顾客向你点菜,但是你不会做菜,所以你采集了顾客要点什么之后告诉后厨去做顾客点的菜,这叫RPC(remote procedure call),因为厨房的厨师相对于服务员而言是另外一个人(在计算机的世界里就是remote的机器上的一个进程)。厨师做好了的菜就是RPC的返回值。

任务队列和消息队列:本质都是队列,所以就只举一个任务队列的例子。假设这个饭店在高峰期顾客很多,而厨师只有很少的几个,所以服务员们不得不把单子按下单顺序放在厨房的桌子上,供厨师们一个一个做,这一堆单子就是任务队列(当然,取决于问题的语境,可能要把放订单的桌子也算在里面一起构成所谓的任务队列平台),厨师们每做完一个菜,就从桌子上的订单里再取出一个单子继续做菜。任务队列和消息队列的一个典型使用场景就是所谓的Producer-Consumer模式,若干producer生产出任务/消息,放到队列当中,同时consumer从队列中取出任务/消息来进行处理。

RPC 调用流程

消费端:

  1. 通过网络向服务端发送序列化后的 RPC 请求

  2. 等待服务器返回结果

  3. 如果服务器调用成功,那么就将结果反序列化

服务端:

  1. 在本地维护 RPC 接口映射关系

  2. 等待请求

  3. 得到一个请求后,将其数据包反序列化并得到具体的 RPC 接口

  4. 将参数反序列化后,在本地调用接口,得到结果

  5. 将结果序列化后通过网络返回给消费端

涉及到的主要几个操作:

  1. RPC 接口映射

  2. 序列化和反序列化。客户端怎么把参数值传给远程的函数呢?在本地调用中,我们只需要把参数压到栈里,然后让函数自己去栈里读就行。但是在远程过程调用时,客户端跟服务端是不同的进程,不能通过内存来传递参数。甚至有时候客户端和服务端使用的都不是同一种语言。这时候就需要客户端把参数先转成一个字节流,传给服务端后,再把字节流转成自己能读取的格式。这个过程叫序列化和反序列化。同理,从服务端返回的值也需要序列化反序列化的过程。

  3. 网络传输。远程调用往往用在网络上,客户端和服务端是通过网络连接的。所有的数据都需要通过网络传输层需要把映射的接口和序列化后的参数字节流传给服务端,然后再把序列化后的调用结果传回客户端。只要能完成这两者的,都可以作为传输层使用。因此,它所使用的协议其实是不限的,能完成传输就行。尽管大部分RPC框架都使用TCP协议,但其实UDP也可以,而gRPC干脆就用了HTTP2。Java的Netty也属于这层的东西。

RPC 协议 和 HTTP 协议

为什么有了 HTTP 协议还要 RPC 协议

  1. RPC 最大的优势:易用性。

  2. 有的 RPC 协议基于 UDP 性能更好,能够做到实时性的需要

  3. 也有 RPC 框架兼容了 HTTP 协议,方便普通 HTTP 接口的调用,它们同时存在