.Net下RabbitMQ的使用(8) — 远程过程调用RPC

释放双眼,带上耳机,听听看~!

RPC是在计算中是一种常见的模式,是通常我要用消息队列来实现RPC有3个关键点:

  1. 服务的寻址

  2. 消息的接收

  3. 消息的关联

 

在RabbitMQ的.net客户端里,提供了2个类:SimpleRpcClient 和 SimpleRpcServer 来让我们方便的开发RPC应用。

因为RabbitMQ的RPC一定是基于队列的,所以在客户端和服务端都需要要一个各自的队列,客户端的队列用来接收服务回复的数据,服务端的队列用来缓存需要调用的服务的Request。这些请求一定不单单从一个客户端而来。

服务的地址是公开的,地址也就是一个队列,客户端只要把参数放进这个服务端监控的队列中就可以了。服务端每次从队列中获得的一个数据即是一次调用。

服务不单单为一个客户端服务,所以在客户端调用的参数里面,每次都需要加上需要回复的队列名字,也就是要告诉服务端方法调用结果需要放在这个队列里。客户端不仅可以直接把队列的名字放在参数里面还可以给出一个路由,例如这样的格式:exchangeType://exchangeName/routingKey。 exchangeType就是exchange 的类型,四选一。这个队列里面的数据就是我调用服务的返回值。每一个客户端都有一个这样的返回值队列。你可以用如下命令查看队列的情况。

 

 

客户端也许调用比较频繁,或者是不是调用一个方法,返回值不同,又或者服务端每次返回的时间都不一样,不能保证回复的顺序和客户端调用的顺序一致。那么程序是怎么保证这个返回值就是这次调用的结果呢?RabbitMQ使用了CorrelationId,他是一个属性,在每次调用的时候,客户端会生成一个这样的属性来代表这次调用,Id唯一的。当然服务端也会把这个Id放在返回值里面一同返回,这个客户端就可用这个CorrelationId来配对一次调用。

如果在调用过程中,CorrelationId没有被匹配到,那么返回值这个消息就会被丢弃,而不会出抛出异常。

一个服务端往往不只提供一个服务(方法),在一个队列中也许会有不同方法的Request,这种就需要根据每次Request里面带的参数来判断是调用具体哪个方法的。一个服务提供多个方法常见也有显而易见的弊端也,如果某些方法服务处理的时间比较长的话就需要其他调用等待。如果服务端采用多线程处理,那么在客户端调用的时候,每个服务端的方法都要一个专门的SimpleRpcClient 去调用。也就是说,不同的方法需要有不同的callback队列,这样才能避免客户端会犹豫匹配CorrelationId不对而丢弃消息。

 

RPC调用的顺序如下:

  1. 在客户端初始化的时候,也就是SimpleRpcClient类初始化的时候,它会随机的创建一个callback队列,用于存放服务的返回值,这个队列是exclusive的。连接断开就没有了。

  2. 客户端在发送Request的时候,会加上两个参数:ReplyTo和CorrelationId,前者用于告诉服务返回值放在哪个队列里面(callback的队列名)或路由,后者用于配对每次的Request。这两个属性都放在客户端发送消息的附带的IBasicProperties字典中。

  3. 把消息放入服务的监控队列里,消息里面自然有调用方法的参数。

  4. 服务在所监控的队列中收到数据后,进行运算,并把返回值放入到客户端指定的callback队列中去。

  5. 客户端在发送完Request后,便去自己创建的callback队列监听,如果获得到数据,则查看里面的CorrelationId,如果和调用Request一致,则返回结果。

 

SimpleRpcClient 和 SimpleRpcServer 只是RabbitMQ .net客户端的一个实现。知道了原理,我们也可以自己实现RPC的功能。

 

服务的负载均衡

服务端往往有一个队列来接收客户端的请求,我们记得在这一篇中,我们看到了RabbitMQ内置的消费者负载均衡功能,那么对于RPC的服务端,我们是不是也适合呢?答案是肯定的。因为我们RPC服务端其实也就是一个Worker,我们只要运行多个监控同一个队列的服务端就可以了。所有的被监控队列中的请求都平均的分配到不同的服务端去了。

给TA打赏
共{{data.count}}人
人已打赏
安全网络

CDN安全市场到2022年价值76.3亿美元

2018-2-1 18:02:50

安全资讯

安全生产十五条措施

2022-4-10 8:51:58

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索