使用Avro可实现如下几种方式的轻量级RPC, 每种方式都可用动态编码和静态编码来实现:
HTTP:
HttpServer
HttpTransceiver
UDP
DatagramServer
DatagramTransceiver
Netty
NettyServer
NettyTransceiver
TCP
SocketServer
SocketTransceiver
安全TCP
SaslSocketServer
SaslSocketTransceiver
1. 添加maven依赖包
<dependency>
<groupId>org.apache.avro</groupId>
<artifactId>avro</artifactId>
<version>1.8.1</version>
</dependency>
<dependency>
<groupId>org.apache.avro</groupId>
<artifactId>avro-ipc</artifactId>
<version>1.8.1</version>
</dependency>
2. 静态方法实现Netty RPC
2.1 下载 avro-tools-1.8.1.jar
2.2 编译mail.avpr, 生成java代码Message.java 和 Mail.java
mail.avpr:
{"namespace": "org.hdp.practice.rpc.netty",
"protocol": "Mail",
"types": [
{"name": "Message", "type": "record",
"fields": [
{"name": "to", "type": "string"},
{"name": "from", "type": "string"},
{"name": "body", "type": "string"}
]
}
],
"messages": {
"send": {
"request": [{"name": "message", "type": "Message"}],
"response": "string"
}
}
}
运行命令: java -jar avro-tools-1.8.1.jar compile protocol mail.avpr .
2.3 java代码
public class MyServer {
public static class MailImpl implements Mail{
@Override
public Utf8 send(Message message) {
System.out.println("Sending message");
return new Utf8("Sending message to " + message.getTo().toString()
+ " from " + message.getFrom().toString()
+ " with body " + message.getBody().toString());
}
}
public static void main(String[] args) throws IOException {
System.out.println("Starting server");
NettyServer server = new NettyServer(new SpecificResponder(Mail.class, new MailImpl()), new InetSocketAddress(65111));
System.out.println("Server started");
}
}
public class MyClient {
public static void main(String[] args) throws IOException {
if (args.length != 3) {
System.out.println("Usage: <to> <from> <body>");
System.exit(1);
}
NettyTransceiver client = new NettyTransceiver(new InetSocketAddress(65111));
Mail proxy = (Mail) SpecificRequestor.getClient(Mail.class, client);
System.out.println("Client built, got proxy");
Message message = new Message();
message.setTo(new Utf8(args[0]));
message.setFrom(new Utf8(args[1]));
message.setBody(new Utf8(args[2]));
System.out.println("Calling proxy.send with message: " + message.toString());
System.out.println("Result: " + proxy.send(message));
client.close();
}
}
3. 动态方法实现HTTP RPC
3.1 message.avpr
{
"namespace": "cn.slimsmart.avro.demo",
"protocol": "messageProtocol",
"doc": "This is a message.",
"name": "Message",
"types": [
{"name":"message", "type":"record",
"fields":[
{"name":"name", "type":"string"},
{"name":"type", "type":"int"},
{"name":"price", "type":"double"},
{"name":"valid", "type":"boolean"},
{"name":"content", "type":"string"}
]
}
],
"messages": {
"sendMessage":{
"doc" : "message test",
"request" :[{"name":"message","type":"message" }],
"response" :"message"
}
}
}
3.2 java 代码
public class Server extends GenericResponder {
private Protocol protocol = null;
private int port;
public Server(Protocol protocol, int port) {
super(protocol);
this.protocol = protocol;
this.port = port;
}
@Override
public Object respond(Message message, Object request) throws Exception {
GenericRecord req = (GenericRecord) request;
GenericRecord reMessage = null;
if (message.getName().equals("sendMessage")) {
GenericRecord msg = (GenericRecord)req.get("message");
System.out.print("接收到数据:");
System.out.println(msg);
//取得返回值的类型
reMessage = new GenericData.Record(protocol.getType("message"));
//直接构造回复
reMessage.put("name", "苹果");
reMessage.put("type", 100);
reMessage.put("price", 4.6);
reMessage.put("valid", true);
reMessage.put("content", "最新上架货物");
}
return reMessage;
}
public void run() {
try {
HttpServer server = new HttpServer(this, port);
server.start();
server.join();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Server(Utils.getProtocol(), 9090).run();
}
}
public class Client {
private Protocol protocol = null;
private String host = null;
private int port = 0;
private int count = 0;
public Client(Protocol protocol, String host, int port, int count) {
this.protocol = protocol;
this.host = host;
this.port = port;
this.count = count;
}
public long sendMessage() throws Exception {
GenericRecord requestData = new GenericData.Record(protocol.getType("message"));
requestData.put("name", "香梨");
requestData.put("type", 36);
requestData.put("price", 5.6);
requestData.put("valid", true);
requestData.put("content", "价钱便宜");
// 初始化请求数据
GenericRecord request = new GenericData.Record(protocol.getMessages().get("sendMessage").getRequest());
request.put("message", requestData);
Transceiver t = new HttpTransceiver(new URL("http://" + host + ":" + port));
GenericRequestor requestor = new GenericRequestor(protocol, t);
long start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
Object result = requestor.request("sendMessage", request);
if (result instanceof GenericData.Record) {
GenericData.Record record = (GenericData.Record) result;
System.out.println(record);
}
}
long end = System.currentTimeMillis();
System.out.println((end - start)+"ms");
return end - start;
}
public long run() {
long res = 0;
try {
res = sendMessage();
} catch (Exception e) {
e.printStackTrace();
}
return res;
}
public static void main(String[] args) throws Exception {
new Client(Utils.getProtocol(), "127.0.0.1", 9090, 5).run();
}
}
public class Utils {
public static Protocol getProtocol() {
Protocol protocol = null;
try {
String url = Utils.class.getResource("").getPath()+"message.avpr";
protocol = Protocol.parse(new File(url));
} catch (IOException e) {
e.printStackTrace();
}
return protocol;
}
}
参考:
https://github.com/phunt/avro-rpc-quickstart/
https://my.oschina.net/tearsky/blog/509610
http://blog.jobbole.com/92290/
本文介绍如何使用 Apache Avro 实现轻量级的远程过程调用(RPC),包括通过 Netty 和 HTTP 的静态及动态方法实现,并提供具体的 Java 代码示例。
352

被折叠的 条评论
为什么被折叠?



