rabbitMQ第四篇:远程调用
前言:前面我们讲解的都是本地服务器,现在如果需要远程计算机上运行一个函数,等待结果。这就是一个不同的故事了,这种模式通常被称为远程过程调用或者RPC。
本章教程我们使用RabbitMQ搭建一个RPC系统,一个客户端和一个可扩展的RPC服务器,现在我们开始吧。
Callback queue
一般做rpc在RabbitMQ是比较容易的,一个客户端发送一个请求信息和一个响应信息的服务器回复,为了得到一个响应,我们需要发送一个回调队列地址请求。如下
Message属性:
AMQP协议一共预定义了14个属性,但是大多数属性很少使用,下面几个可能用的比较多
deliveryMode:有2个值,一个是持久,另一个表示短暂(第二篇说过)
contentType:内容类型:用来描述编码的MIME类型。例如,经常使用JSON编码是将此属性设置为一个很好的做法:application/json。
replyTo:经常使用的是回调队列的名字
correlationid:RPC响应请求的相关应用
Correlation Id
在队列上接收到一个响应,但它并不清楚响应属于哪一个,当我们使用CorrelationId属性的时候,我们就可以将它设置为每个请求的唯一值,稍后当我们在回调队列中接收消息的时候,我们会看到这个属性,如果我们看到一个未知的CorrelationId,我们就可以安全地忽略信息-它不属于我们的请求。为什么我们应该忽略未知的消息在回调队列中,而不是失败的错误?这是由于服务器端的一个竞争条件的可能性。比如还未发送了一个确认信息给请求,但是此时RPC服务器挂了。如果这种情况发生,将再次重启RPC服务器处理请求。这就是为什么在客户端必须处理重复的反应。
需求
我们的rpc工作方式如下:
1:当客户端启动时,它创建一个匿名的独占回调队列。
2:对于rpc请求,客户端发送2个属性,一个是replyTo设置回调队列,另一是correlationId为每个队列设置唯一值
3:请求被发送到一个rpc_queue队列中
4:rpc服务器是等待队列的请求,当收到一个请求的时候,他就把消息返回的结果返回给客户端,使请求结束。
5:客户端等待回调队列上的数据,当消息出现的时候,他检查correlationId,如果它和从请求返回的值匹配,就进行响应。
编码
RPCServer.Java
public class RPCServer {
private static final String RPC_QUEUE_NAME = "rpc_queue"; private static int fib(int n) {
if (n == 0) {
return 0;
}
if (n == 1) {
return 1;
}
return fib(n - 1) + fib(n - 1);
} public static void main(String[] args) throws IOException, InterruptedException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(RPC_QUEUE_NAME, false, false, false, null);
channel.basicQos(1);
QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume(RPC_QUEUE_NAME, false, consumer); System.out.println("RPCServer Awating RPC request");
while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
BasicProperties props = delivery.getProperties();
BasicProperties replyProps = new AMQP.BasicProperties.Builder().
correlationId(props.getCorrelationId()).build(); String message = new String(delivery.getBody(), "UTF-8");
int n = Integer.parseInt(message); System.out.println("RPCServer fib(" + message + ")");
String response = "" + fib(n);
channel.basicPublish( "", props.getReplyTo(), replyProps, response.getBytes());
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
}
}
服务器代码比较简单
1:建立连接,通道,队列
2:我们可能运行多个服务器进程,为了分散负载服务器压力,我们设置channel.basicQos(1);
3:我们用basicconsume访问队列。然后进入循环,在其中我们等待请求消息并处理消息然后发送响应。
RPCClient.java
public class RPCClient {
private Connection connection;
private Channel channel;
private String requestQueueName = "rpc_queue";
private String replyQueueName;
private QueueingConsumer consumer; public RPCClient() throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
connection = factory.newConnection();
channel = connection.createChannel(); replyQueueName = channel.queueDeclare().getQueue();
consumer = new QueueingConsumer(channel);
channel.basicConsume(replyQueueName, true, consumer);
} public String call(String message) throws IOException, InterruptedException {
String response;
String corrID = UUID.randomUUID().toString();
AMQP.BasicProperties props = new AMQP.BasicProperties().builder()
.correlationId(corrID).replyTo(replyQueueName).build();
channel.basicPublish("", requestQueueName, props, message.getBytes("UTF-8"));
while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
if (delivery.getProperties().getCorrelationId().equals(corrID)) {
response = new String(delivery.getBody(), "UTF-8");
break;
}
}
return response;
} public void close() throws Exception {
connection.close();
} public static void main(String[] args) throws Exception {
RPCClient rpcClient = null;
String response;
try {
rpcClient = new RPCClient();
System.out.println("RPCClient Requesting fib(20)");
response = rpcClient.call("20");
System.out.println("RPCClient Got '" + response + "'");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (rpcClient != null) {
rpcClient.close();
}
}
}
}
客户端代码解读
1:建立一个连接和通道,并声明了一个唯一的“回调”队列的答复
2:我们订阅回调队列,这样就可以得到RPC的响应
3:定义一个call方法用于发送当前的回调请求
4:生成一个唯一的correlationid,然后通过while循环来捕获合适的回应
5:我们请求信息,发送2个属性,replyTo 和correlationId
6:然后就是等待直到有合适的回应到达
7:while循环是做一个非常简单的工作,对于每一个响应消息,它检查是否有correlationid然后进行匹配。然后是就进行响应。
8:最后把响应返回到客户端。
rabbitMQ第四篇:远程调用的更多相关文章
- RabbitMQ第四篇:Spring集成RabbitMQ
前面几篇讲解了如何使用rabbitMq,这一篇主要讲解spring集成rabbitmq. 首先引入配置文件org.springframework.amqp,如下 <dependency> ...
- Spring的远程调用
Spring远程支持是由普通(Spring)POJO实现的,这使得开发具有远程访问功能的服务变得相当容易 四种远程调用技术: ◆ 远程方法调用(RMI) ◆ Caucho的Hessian和Burlap ...
- (转)RabbitMQ消息队列(七):适用于云计算集群的远程调用(RPC)
在云计算环境中,很多时候需要用它其他机器的计算资源,我们有可能会在接收到Message进行处理时,会把一部分计算任务分配到其他节点来完成.那么,RabbitMQ如何使用RPC呢?在本篇文章中,我们将会 ...
- RabbitMQ消息队列(七):适用于云计算集群的远程调用(RPC)
在云计算环境中,很多时候需要用它其他机器的计算资源,我们有可能会在接收到Message进行处理时,会把一部分计算任务分配到其他节点来完成.那么,RabbitMQ如何使用RPC呢?在本篇 ...
- RabbitMQ 适用于云计算集群的远程调用(RPC)
在云计算环境中,很多时候需要用它其他机器的计算资源,我们有可能会在接收到Message进行处理时,会把一部分计算任务分配到其他节点来完成.那么,RabbitMQ如何使用RPC呢?在本篇文章中,我们将会 ...
- RabbitMQ学习总结 第四篇:发布/订阅 Publish/Subscribe
目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...
- [置顶] android调用第三方库——第四篇——调用多个第三方库
0:前言: 在前面三篇中我们介绍了android调用第三方库的形式,在这一篇中我们介绍调用多个第三方库的Android.mk的写法,由于其他三篇介绍的很详细,这里只给出Android.mk的内容. [ ...
- RabbitMQ远程调用测试用例
RabbitMQ远程调用测试,使用外部机器192.168.174.132上的RabbitMQ,使用之前需要对远程调用进行配置,操作过程见博文“解决RabbitMQ远程不能访问的问题”. SendTes ...
- 深入浅出Alljoyn——实例分析之远程调用(Method)篇
深入浅出就是很深入的学习了很久,还是只学了毛皮,呵呵! 服务端完整代码: #include <qcc/platform.h> #include <assert.h> #incl ...
随机推荐
- ProgressBar 详解
发现一个关于ProgressBar的网站,写得特别详细. 分享予大家: http://www.apkbus.com/android-735-1-1.html
- javascript变量问题
CMAScript变量包含两种不同数据类型的值: 基本类型值:简单的数据段:引用类型值:可能有多个值构成的对象. 5种基本类型:Undefined,Null,Bollean,Number,String ...
- 使用netty实现的tcp通讯中如何实现同步返回
在netty实现的tcp通讯中,一切都是异步操作,这提高了系统性能,但是,有时候client需要同步等待消息返回,如何实现呢?笔者已经实现,在此总结下重点要素 实现要点: 1.消息结构设计 消息头中需 ...
- Async/Await FAQ
From time to time, I receive questions from developers which highlight either a need for more inform ...
- Alamofire源码学习
Core文件夹: Alamofire.swift - - - 该文件中主要是给用户提供一些便利的调用方法,用户可以直接调用该文件中的便利方法来使用Alamofire相关功能. ...
- Webdriver实现原理
通过研究selenium-webdriver的源码,笔者发现其实webdriver的实现原理并不高深莫测无法揣度.在这里以webdriver ruby binding的firefox-webdrive ...
- IO-01. 表格输出(5)
本题要求编写程序,按照规定格式输出表格. 输入格式: 本题目没有输入. 输出格式: 要求严格按照给出的格式输出下列表格: ------------------------------------ Pr ...
- windows management instrumentation服务未启动-解决脚本
桌面新建.txt文件 将以下代码放入 保存为.bat文件 执行即可 @echo on cd /d c:\temp if not exist %windir%\system32\wbem goto Tr ...
- html中使用js实现内容过长时部分
有时数据内容太长时我们并不希望其全部显示出来,因为这样可能会导致用于显示这些内容的标签被撑开影响美观. 这时就希望能够实现默认只显示部分内容,在鼠标放上去的时候再将全部的内容显示出来. 这里提供一个简 ...
- xUtils 1.8.4 (Android工具库) 发布 - http模块优化
感谢关注xUitls的网友最近一段时间给予的热心反馈,xUtils近期做了很多细节优化,同时修复和优化了大家反馈的一些问题.重要的变化有http请求返回更全面的结果信息:下载设置断点续下时,如果服务器 ...