RabbitMQ快速入门(七)RPC

RabbitMQ入门系列的最后一篇文章。
RPC[1](Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC使得开发包括网络分布式程序在内的应用程序更加容易。

引用:
[1]
百度百科词条“RPC”: https://baike.baidu.com/item/%E8%BF%9C%E7%A8%8B%E8%BF%87%E7%A8%8B%E8%B0%83%E7%94%A8%E5%8D%8F%E8%AE%AE/6893245?fromtitle=RPC&fromid=609861&fr=aladdin

接下来,将使用RabbitMQ实现一个简单的RPC系统:包括RPC客户端及RPC服务端。在这个示例中,RPC客户端传递给RPC服务端一个整数,RPC服务端使用该整数计算出相应的斐波那契数,返回给客户端。

1.客户端接口

创建一个计算斐波那契数的类:FibonacciRpcClient()。其中的成员函数call()用来发送RPC请求并阻塞,直到接收到RPC服务端返回的结果:

客户端需要发送RPC请求至服务端指定的rpc_queue队列==》服务端计算出相应的结果==》服务端将结果返回给客户端指定的队列中==》客户端消费该队列中的“返回结果”。

2.回调队列(callback queue)

客户端发出RPC请求之后将会一直阻塞,直到服务端返回结果。而服务端是将计算结果返回在哪里的呢?事实上,为了获得服务端响应的计算结果,客户端在发出请求的时候会额外的指定一个“回调队列”给服务端。告诉服务端:把计算结果发送至这个队列里就可以了。它们大概长这个样子:

也就是说,在这个RPC示例中,客户端和服务端各声明了一个队列。

3.关联id(Correlation id)

上面提到的回调队列(callback queue)是为每个RPC请求服务的——用来存放每个RPC请求返回的相应结果。然而,若为每一个RPC请求都声明一个回调队列的话就太低效了。那么问题来了,如果所有的RPC请求的返回结果都存放在一个回调队列中的话,怎么区分它们对应的是哪一条RPC请求呢?

关联id提供了解决方案:客户端在发送每个RPC请求消息的时候都可以指定一个独一无二的关联id。服务端接收RPC请求之后,将请求结果随同关联id一并返回。接着,客户端将请求消息的关联id与回调队列中的关联id进行比较,取出具有相同关联id的消息进行消费即可。整个流程用图3-1概括如下:rpc3-1

图3-1

         上图中有 两个队列。对于这两个队列,再多说两句:rpc_queue是由服务端声明的,并且将会自动的绑定至默认交换器上,主要用来接收rpc请求;而客户端声明的回调队列没有显式地指定队列名(由消息代理自动生成,以amq.为前缀命名),当然,你也可以为其指定一个名字。

此时,总结一下该RPC示例的工作流程(摘录自官网):

  • When the Client starts up, it creates an anonymous exclusive callback queue.
  • For an RPC request, the Client sends a message with two properties: reply_to, which is set to the callback queue and correlation_id, which is set to a unique value for every request.
  • The request is sent to an rpc_queue queue.
  • The RPC worker (aka: server) is waiting for requests on that queue. When a request appears, it does the job and sends a message with the result back to the Client, using the queue from the reply_to field.
  • The client waits for data on the callback queue. When a message appears, it checks the correlation_id property. If it matches the value from the request it returns the response to the application.

4.示例

(1)RPC客户端rpc_client.py

(2)RPC服务端rpc_server.py

(3)运行

#RPC服务端

#RPC客户端

这里只是实现了一个简单的RPC示例。然而,如果你想要实现一个更加完善的RPC客户/服务模型,还需着重考虑以下几点:

一,如果服务端没有运行,客户端该如何响应?
二,客户端发出RPC请求之后,客户端是否需要启动超时机制?
三,如果RPC服务器异常,是否需要将异常转发给RPC客户端?
等等。

5.其他

RabbitMQ入门系列的文章到此就结束了。这几篇文章是本人对RabbitMQ官方资料的浅析的理解和总结,如有错误,请指出。

参考:
http://www.rabbitmq.com/tutorials/tutorial-six-python.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注