RPC的粗浅认识

再说RPC之前,先说一下同类的通信方式。
从单机走向分布式,产生了很多分布式的通信方式。

  •     最古老也是最有效,且永远不过时的,TCP/UDP的二进制传输。事实上所有的通信方式归根结底都是TCP/UDP。
  •     CORBA Common Object Request Broker Architecture。古老而复杂,支持面向对象的通信协议
  •     Web Service(SOA SOAP RDDI WSDL...协议):基于http + xml的标准化Web API。

        XML指的是接口文档以XML的形式进行展现,http指的是通信协议。

        通信协议是http,以json方式进行数据传出。

  •     RMI Remote Method Invocation:java内部的分布式通信协议,就是Java内部封装的RPC,不过名称叫做RMI摆了。
  •     JMS Java Message Service:JavaEE中的消息框架标准,为很多MQ所支持。
  •     RPC(Remote Procedure Call):远程过程调用,就是调用远程的方法。

远程方法调用,这只是一个统称,重点在于方法调用(不支持对象的概念),具体实现甚至可以用RMI RestFul等去实现,但一般不用,因为RMI不能跨语言,而RestFul传输效率过低。

RPC多用于服务器集群间的通信,因此常使用更加有效、短小精悍的传出模式以提高效率,如Thrift,Hessian,gooogle protobuf。

RPC根据序列化方式的不同,出现了多样的RPC序列化框架
    注意RPC序列化框架并不是RPC框架,RPC框架还包括服务发现,服务注册、服务治理等。。。

  • java.io.Serializable

        java原生序列化,不好,序列化时间长,且序列化后的字节也非常大。

  • Hessian
  • google protobuf
  • facebook Thrift
  • kyro
  • fst
  • json序列化框架

        1 jackson

        2 google gson

        3 Ali FastJson

  • xmlrpc(stream)

RPC通信协议

  •     http
  •     http2.0(gRPC)
  •     TCP

        同步/异步/阻塞/非阻塞

  •     WebService

根据序列化方式和RPC通信协议方式的组合,可以产生多样的RPC使用方式。

分布式通信最基本最核心的部分:两台/多台服务器之间的二进制数据的传出。

以下是单机的二进制数据传送与接收实例。

公共部分代码:

public interface IUserService {

    public User findUserById(Integer id);
}


public class User implements Serializable {
    private static final long serialVersionUID = 1;

    private Integer id;
    private String name;

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

服务端代码:


public class Server {
    private static boolean running = true;

    public static void main(String[] args) throws Exception{
        ServerSocket ss = new ServerSocket(8888);
        while(running){
            Socket s = ss.accept();
            process(s);
            s.close();
        }
        ss.close();
    }

    private static void process(Socket s)throws Exception{
        InputStream in = s.getInputStream();
        OutputStream out = s.getOutputStream();
        DataInputStream dis = new DataInputStream(in);
        DataOutputStream dos = new DataOutputStream(out);
        /*
        * 获取客户端的数据
        * */
        int id = dis.readInt();
        IUserService service = new UserServiceImpl();
        /*
        * 如何将对象写入到客户端呢?
        * 把对象的基本类型写到客户端。
        * */
        User user = service.findUserById(id);
        dos.writeInt(user.getId());
        dos.writeUTF(user.getName());
        dos.flush();
    }
}

User实现类

public class UserServiceImpl implements IUserService {
    @Override
    public User findUserById(Integer id) {
        return new User(id,"hello world");
    }
}

客户端代码:

/*
向外写的过程:
客户端的数据需要转换成二进制的过程,
    通过DataOutputStream的写入操作将123数值转成二进制的表示,然后
    通过调用toByteArray方式转成字节数组.
*/
public class client {
    public static void main(String[] args) throws Exception {
        Socket s = new Socket("127.0.0.1",8888);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(baos);
        dos.writeInt(123);
        s.getOutputStream().write(baos.toByteArray());
        s.getOutputStream().flush();

        /*上方的操作进行写出操作,下方读取服务器返回的数据,然后
        * 将基本类型进行拼接成User对象*/
        DataInputStream dis = new DataInputStream(s.getInputStream());
        int id = dis.readInt();
        String name = dis.readUTF();
        User user = new User(id,name);

        System.out.println(user);

        dos.close();
        dis.close();
    }
}

视频来源于马士兵老师的公开课

笔记参考:Java讲解RPC的基本实现

通过几段 Java 代码理解 RPC

这里仅是粗浅理解性,对于RPC而言,其中动态代理扮演了比较重要的角色。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章