服务间,系统间信息交互,简单的方式可以是http,但比http更为高效的是RPC,gRPC是比较流行的RPC工具了,使用上也比较简单。那么,我们不妨也了解一下RabbitMQ实现RPC又是怎样一番风味。
RabbitMQ是单向的消息传递,生产者将消息发送给消费者之后就不再管后续的业务处理了。实际业务中,有的时候我们还需要等待消费者返回结果给我们,或者是说我们需要消费者上的一个功能、一个方法或是一个接口返回给我们相应的值,而往往大型的系统软件,生产者跟消费者之间都是相互独立的两个系统,部署在两个不同的电脑上,不能通过直接对象.方法的形式获取想要的结果,这时候我们就需要用到RPC(Remote Procedure Call)远程过程调用方式。
RabbitMQ实现RPC的方式很简单,生产者发送一条带有标签(消息ID(correlation_id)+回调队列名称)的消息到发送队列,消费者(也称RPC服务端)从发送队列获取消息并处理业务,解析标签的信息将业务结果发送到指定的回调队列,生产者从回调队列中根据标签的信息获取发送消息的返回结果。
如图,客户端C发送消息,指定消息的ID=rpc_id,回调响应的队列名称为rpc_resp,消息从C发送到rpc_request队列,服务端S获取消息业务处理之后,将correlation_id附加到响应的结果发送到指定的回调队列rpc_resp中,客户端从回调队列获取消息,匹配与发送消息的correlation_id相同的值为消息应答结果。
事件总线模式下RabbitMQ,客户端发送消息,并等待返回值:
var command = new GetAllPackageCommand(); var res = BusFactory.DefaultBus.SendCommand<GetAllPackageCommand, List<PackageContract>>(command); var packages = res.GetResult();
当客户端发起消息的时候,程序对DefaultBus作了初始化,其主要代码是初始化客户端 生产者和消费者 身份:
1 publishConnection = RabbitConnectionManager.Allocate(this.busUri, true); //客户端作为生产者 连接MQ 2 publishChannel = publishConnection.CreateModel();//客户端作为生产者 创建信道 3 publishConfirmChannelPool = new ComfireSelectChannelPool(publishConnection);//客户端作为生产者 信道设置 confirm select模式,以确保能发消息到队列 4 consumeConnection = RabbitConnectionManager.Allocate(this.busUri); //客户端作为 消息者 连接MQ 5 consumeChannel = consumeConnection.CreateModel(); 客户端作为消费者 创建信道 6 7 var args = new Dictionary<string, object>(); 8 args.Add("x-expires", this.responseQueueExpireTime); 9
//接收模型consumeChannel,绑定队列 MyQueueingBasicConsumer。MyQueueingBasicConsumer 监听 this.responseQuque,当消息到来时,存入自身的Queue队列中。
10 consumeChannel.QueueDeclare(this.responseQuque, true, false, false, args); 12 consumer = new MyQueueingBasicConsumer(consumeChannel); 13 consumeChannel.BasicConsume(this.responseQuque, true, consumer); 14 15 consumerCancellation = new CancellationTokenSource(); 16
// 启动了 consumerTask, 内部一直在轮询 MyQueueingBasicConsumer.Queue队列。发现消息后,根据消息的关系id,获取发送的 BusResponse 对象,并赋值。 17 consumerTask = new Task(() => ProcessResponse(this.consumerCancellation.Token), TaskCreationOptions.LongRunning); 18 consumerTask.Start();
当客户端发起请求,它作为生产者的同时,也成为了一个等待结果的消费者,这个消费者一直在监听着 响应队列(response) 里面的消息。