Rabbitmq implements high-throughput RPC calls

The basic idea of ​​rabbitmq to implement rpc call:
client (client): the client initiates an rpc call, which is treated as a message and sent to the rabbitmq server. This message will carry two special (extra) information, one is the call sequence number and one is the callback queue name. The call sequence number needs to be returned by the server as it is, and the callback queue name is used by the server to put the result in this queue so that the client can retrieve the result.
Server (service): After the server receives an RPC call, it executes the calling code and returns the result to the specified callback queue.
Here we can agree on a data model, see the code:
public class RpcInvokeModel implements Serializable {
          //Real transmission data
private Object target;
          //Call serial number
private Long invokeFlag;
          //Callback queue name
        private String
callBackQueue
; The call is encapsulated into this model and sent out. The server is parsed into this model. Of course, you can add other parameters (such as method names, etc.) to this model.
Client code:
package com.pdy.rabbitmq.rpc;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

/**
* Represents a connection with a queue
*
* @author syntx
*
*/
public abstract class ClientEndPoint {

protected Channel producerChannel;
protected Channel consumerChannel;
protected Connection connection;
protected String endPointName;

public ClientEndPoint(String endpointName) throws IOException,
TimeoutException {
this.endPointName = endpointName;

// Create a connection factory
ConnectionFactory factory = new ConnectionFactory();

// hostname of your rabbitmq server
// factory.setVirtualHost("pdy");
factory.setHost("localhost");
// factory.setUsername("pdy");
// factory.setPassword("pdy");
// factory.setVirtualHost("pdy11");
// getting a connection
connection = factory.newConnection();
// creating a channel
producerChannel = connection.createChannel();
consumerChannel = connection.createChannel();

producerChannel.queueDeclare(endpointName, false, false, false, null);
}

/**
* 关闭channel和connection。并非必须,因为隐含是自动调用的。
*
* @throws IOException
* @throws TimeoutException
*/
public void close() throws IOException, TimeoutException {
this.producerChannel.close();
this.consumerChannel.close();
this.connection.close();
}
}

package com.pdy.rabbitmq.rpc;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeoutException;

import org.apache.commons.lang3.SerializationUtils;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.AMQP.Queue.DeclareOk;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.ShutdownSignalException;

public class Client extends ClientEndPoint implements Consumer, Runnable {

public Client(String endpointName) throws IOException, TimeoutException {
super(endpointName);
DeclareOk ok = super.consumerChannel.queueDeclare();
callBackQueue = ok.getQueue();
super.consumerChannel.basicConsume(callBackQueue, true, this);
}

@Override
public void handleConsumeOk(String consumerTag) {

}

@Override
public void handleCancelOk(String consumerTag) {

}

@Override
public void handleCancel(String consumerTag) throws IOException {

}

@Override
public void handleDelivery(String arg0, Envelope arg1,
BasicProperties arg2, byte[] arg3) throws IOException {

RpcInvokeModel invokeModel = SerializationUtils.deserialize(arg3);

synchronized (callResult) {

callResult.put(invokeModel.getInvokeFlag(), invokeModel.getObj());
callResult.notifyAll();
}

}

@Override
public void handleShutdownSignal(String consumerTag,
ShutdownSignalException sig) {

}

@Override
public void handleRecoverOk(String consumerTag) {

}

public void start() throws IOException {

Random random = new Random();
for (int i = 0; i < 10; i++) {

Double[] arr = new Double[10];

for (int j = 0; j < arr.length; j++) {
arr[j] = random.nextDouble();
}

System.out.println("调用rpc服务:" + Arrays.toString(arr));

RpcFuture<Double[]> result = invokeSort(arr);
Double[] obj = result.get();
System.out.println("调用rpc服务响应的结果:" + Arrays.toString(obj));
}
}

private RpcFuture<Double[]> invokeSort(Double[] arr) throws IOException {

RpcInvokeModel mo = new RpcInvokeModel();
mo.setInvokeFlag(++invokeFlag);
mo.setObj(arr);
byte[] body = SerializationUtils.serialize(mo);

BasicProperties basicProperties = new BasicProperties().builder()
.replyTo(callBackQueue).build();
super.producerChannel.basicPublish("", super.endPointName,
basicProperties, body);

return new RpcFuture<>(this, mo.getInvokeFlag());
}

private final String callBackQueue;
private final Map<Long, Object> callResult = new HashMap<>();
private volatile long invokeFlag = 0;

public Object getResultByFlagKey(Long flagKey) {

Object result = null;
while (true) {
synchronized (callResult) {
result = callResult.remove(flagKey);
if (result == null) {
try {
callResult.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
return result;
}
}
}
}

@Override
public void run() {

try {
start();
} catch (IOException e) {
e.printStackTrace();
}
}
}

package com.pdy.rabbitmq.rpc;

public class RpcFuture<T> {

private final Client client;
private final Long flagKey;

public RpcFuture(Client client, Long flagKey) {

this.client = client;
this.flagKey = flagKey;
}

public T get() {

return (T) client.getResultByFlagKey(flagKey);
}
}


服务端代码:
package com.pdy.rabbitmq.rpc;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

/**
* Represents a connection with a queue
*
* @author syntx
*
*/
public abstract class ServiceEndPoint {

protected Channel producerChannel;
protected Channel consumerChannel;
protected Connection connection;
protected String endPointName;

public ServiceEndPoint(String endpointName) throws IOException,
TimeoutException {
this.endPointName = endpointName;

// Create a connection factory
ConnectionFactory factory = new ConnectionFactory();

// hostname of your rabbitmq server
// factory.setVirtualHost("pdy");
factory.setHost("localhost");
// factory.setUsername("pdy");
// factory.setPassword("pdy");
// factory.setVirtualHost("pdy11");
// getting a connection
connection = factory.newConnection();
// creating a channel
producerChannel = connection.createChannel();
consumerChannel = connection.createChannel();

consumerChannel.queueDeclare(endpointName, false, false, false, null);
}

/**
* 关闭channel和connection。并非必须,因为隐含是自动调用的。
*
* @throws IOException
* @throws TimeoutException
*/
public void close() throws IOException, TimeoutException {
this.producerChannel.close();
this.consumerChannel.close();
this.connection.close();
}
}

package com.pdy.rabbitmq.rpc;

import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.TimeoutException;

import org.apache.commons.lang3.SerializationUtils;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.ShutdownSignalException;

public class Service extends ServiceEndPoint implements Consumer {

public Service(String endpointName) throws IOException, TimeoutException {
super(endpointName);
}

public void start() throws IOException {

super.consumerChannel.basicConsume(super.endPointName, true, this);
}

@Override
public void handleConsumeOk(String consumerTag) {

}

@Override
public void handleCancelOk(String consumerTag) {

}

@Override
public void handleCancel(String consumerTag) throws IOException {

}

@Override
public void handleDelivery(String arg0, Envelope arg1,
BasicProperties arg2, byte[] arg3) throws IOException {

RpcInvokeModel invokeModel = SerializationUtils.deserialize(arg3);
Double[] obj = (Double[]) invokeModel.getObj();

Arrays.sort(obj);

invokeModel.setObj(obj);

byte[] body = SerializationUtils.serialize(invokeModel);

String routingKey = arg2.getReplyTo();
super.producerChannel.basicPublish("", routingKey, null, body);
}

@Override
public void handleShutdownSignal(String consumerTag,
ShutdownSignalException sig) {

}

@Override
public void handleRecoverOk(String consumerTag) {

}
}

测试代码:
package test;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.pdy.rabbitmq.rpc.Client;
import com.pdy.rabbitmq.rpc.Service;

public class RpcTest {

public static void main(String[] args) throws IOException, TimeoutException {

String queue = "pdyRpc";
client(queue);
service(queue);
}

private static void service(String queue) throws IOException,
TimeoutException {

Service service = new Service(queue);
service.start();
}

private static void client(String queue) throws IOException,
TimeoutException {

Client client = new Client(queue);
new Thread(client).start();
}
}

The code is not yet thread-safe, but it's easy to make it thread-safe.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326788869&siteId=291194637