rpc · 2022-06-30 0

avro rpc 简单使用

一、概述

Apache Avro不仅仅是一个数据序列化协议,更提供一个良好定义的IPC消息协议,同时提供更高级别的RPC封装,使得基于Apache Avro的RPC调用变得更快捷。

Apache Avro 提供了三种不同的文件格式分别用来定义数据序列化协议(Schema ),接口协议(Protocol ),接口定义语言(IDL)分别以.avsc,.avpr,.avdl作为文件标识。

二、maven引入

    <dependencies>

        <dependency>
            <groupId>org.apache.avro</groupId>
            <artifactId>avro</artifactId>
            <version>1.11.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.avro</groupId>
            <artifactId>avro-ipc</artifactId>
            <version>1.11.0</version>
        </dependency>
    </dependencies>

三、编写 avsc 文件和 avdl 文件

在src/main下新建目录avro,avro目录下新建文件user.avsc

{
    "namespace": "com.example.avro", // 相当于声明一个包
    "type": "record", // 相当于Java中的class
    "name": "User", // 类名
    "fields": [
        {"name": "name", "type": "string"},
        {"name": "age",  "type": "int"},
        {"name": "address",  "type": ["string", "null"]}
    ]
}

avro目录下新建文件 userprotocol.avdl

@namespace("com.example.protocol")
protocol UserProtocol {
    import schema "user.avsc";
    string hello(com.example.avro.User user);
}

四、avro-tools编译

1.编译 avsc 文件

下载avro-tools.jar,使用avro-tools.jar编译avsc文件,
编译到java目录下

java -jar avro-tools-1.11.0.jar compile schema src/main/avro/user.avsc src/main/java

src/main/avro/user.avsc 源目录;src/main/java目标目录

2.编译 avdl 文件

avdl文件转化为avpr文件

java -jar avro-tools-1.11.0.jar idl src/main/avro/userprotocol.avdl src/main/avro/userprotocol.avpr

生成 userprotocol.avpr

{
  "protocol" : "UserProtocol",
  "namespace" : "com.example.protocol",
  "types" : [ {
    "type" : "record",
    "name" : "User",
    "namespace" : "com.example.avro",
    "fields" : [ {
      "name" : "name",
      "type" : "string"
    }, {
      "name" : "age",
      "type" : "int"
    }, {
      "name" : "address",
      "type" : [ "string", "null" ]
    } ]
  } ],
  "messages" : {
    "hello" : {
      "request" : [ {
        "name" : "user",
        "type" : "com.example.avro.User"
      } ],
      "response" : "string"
    }
  }
}

3.编译 avpr 文件

编译到java目录下

java -jar avro-tools-1.11.0.jar compile protocol src/main/avro/userprotocol.avpr src/main/java

五、使用maven插件编译

    <dependencies>

        <dependency>
            <groupId>org.apache.avro</groupId>
            <artifactId>avro</artifactId>
            <version>1.11.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.avro</groupId>
            <artifactId>avro-ipc</artifactId>
            <version>1.11.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.avro</groupId>
                <artifactId>avro-maven-plugin</artifactId>
                <version>1.11.0</version>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>schema</goal>
                            <goal>idl-protocol</goal>
                        </goals>
                        <configuration>
                            <sourceDirectory>${project.basedir}/src/main/avro/</sourceDirectory>
                            <outputDirectory>${project.basedir}/src/main/java/</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

六、使用

会在 java目录下生成 User.java 和 UserProtocol.java 文件

1.接口实现

public class UserProtocolImpl implements UserProtocol {

    @Override
    public CharSequence hello(User user) {
        return "hello, " + user.getName();
    }
}

2. server

public class Server {

    public static void main(String[] args) throws IOException, InterruptedException {
        Responder responder = new SpecificResponder(UserProtocol.class,new UserProtocolImpl());
        SaslSocketServer server = new SaslSocketServer(responder,new InetSocketAddress(9999));

        server.setDaemon(false);
        server.start();
    }
}

3. client

public class Client {

    public static void main(String[] args) throws IOException {
        SaslSocketTransceiver transceiver = new SaslSocketTransceiver(new InetSocketAddress(9999));
        UserProtocol client = SpecificRequestor.getClient(UserProtocol.class, transceiver);

        User user = new User();
        user.setName("zhang san");
        CharSequence msg = client.hello(user);

        System.out.println(msg);
    }
}

对于server的client的实现有如下几种

  1. 基于jetty的http实现:HttpServer 和HttpTransceiver
  2. 基于netty的实现:NettyServer和NettyTransceiver
  3. 基于TCP的实现:SocketServer和SocketTransceiver
  4. 基于UDP的实现:DatagramServer和DatagramTransceiver
  5. 基于加密的TCP实现:SaslSocketServer和SaslSocketTransceiver