RPC原理以及实践

1. 认识RPC

RPC(Remote Procedure Call)是指远程过程调用,在微服务架构中,各个微服务之间的通信一般使用RPC,比如用户微服务和订单微服务,需求是在用户微服务中查询当前用户的订单,此时用户服务是RPC的请求端,订单微服务是RPC的服务端。

2. RPC原理

2.1 要实现RPC有3个难点问题:
①如何让客户端知道服务端提供的RPC接口以及方法?
方法一:客户端和服务端在pom文件中同时依赖定义了接口的依赖,服务端需要实现这些接口,提供服务
方法二:比如Spring Cloud Feign是将请求通过动态代理加工成HTTP请求,返回时再将Response反加工过程
②客户端和服务端如何通信?
方法一:Java可以通过NIO/BIO
③客户端如何将参数传递到服务端?
将数据序列化获得二进制数据进行传输 序列化的技术也很多java默认序列化/Json/XML/Protobuf/Hessian 序列化和反序列化效率对比
RPC原理以及实践_第1张图片

3. 手写RPC框架

3.1 RPC Client

main线程

public static void main( String[] args )
{
     
	IOrderService orderService = null;
	RpcProxyClient rpcProxyClient = new RpcProxyClient();
    //代理类的实现
	orderService = rpcProxyClient.clientProxy(IOrderService.class,"localhost",8080);
	System.out.println(orderService.getOrderList());
}

代理类

public class RpcProxyClient {
     
    public <T>T clientProxy(final Class<T> interfaceCls, String host, int port){
     
    //为了更简洁,创建一个继承InvocationHandler的子类实现具体逻辑
        return (T)Proxy.newProxyInstance(interfaceCls.getClassLoader(), new Class<?>[]{
     interfaceCls}, new RpcInvocationHandler(host, port));
    }
}

InvocationHandler的子类

public class RpcInvocationHandler implements InvocationHandler {
     
    private String host;
    private int port;

    public RpcInvocationHandler(String host, int port) {
     
        this.host = host;
        this.port = port;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     
        //通过socket创建连接
        RpcNetTransport rpcNetTransport = new RpcNetTransport(host,port);
        rpcNetTransport.createSocket();
        //传输请求的数据 请求接口名称,方法名称,参数等
        RpcRequest request = new RpcRequest();
        request.setArgs(args);
        request.setMethodName(method.getName());
        request.setTypes(method.getParameterTypes());
        request.setClassName(method.getDeclaringClass().getName());
        return rpcNetTransport.send(request);
    }
}
3.2 服务端

main线程

public static void main( String[] args ) throws IOException {
     
	IOrderService service = new OrderImpl();
	RpcProxyServer rpcProxyServer = new RpcProxyServer();
	rpcProxyServer.publisher(service,8080);
}

RpcProxyServer接收客户端请求并处理

public class RpcProxyServer {
     
    //使用多线程防止阻塞
    private final ExecutorService executorService = Executors.newCachedThreadPool();
    
    public void publisher(Object service, int port){
     
        ServerSocket serverSocket = null;
        Socket socket = null;
        try {
     
            serverSocket = new ServerSocket(port);
            while (true){
     
                socket = serverSocket.accept();
                //具体的处理类
                executorService.submit(new ProcessHandler(socket, service));
            }
        } catch (IOException e) {
     
            e.printStackTrace();
        }
    }
}

ProcessHandler 反序列化处理以及反射调用目标方法

public class ProcessHandler implements Runnable {
     

    private Socket socket;
    private Object service;

    public ProcessHandler(Socket socket, Object service) {
     
        this.socket = socket;
        this.service = service;
    }

    @Override
    public void run() {
     
        ObjectInputStream objectInputStream = null;
        ObjectOutputStream objectOutputStream = null;
        InputStream inputStream = null;

        try {
     
            inputStream = socket.getInputStream();
            objectInputStream = new ObjectInputStream(inputStream);
            RpcRequest request = (RpcRequest)objectInputStream.readObject();
            //反射调用目标方法
            Object rs = invoke(request);
            System.out.println("服务端处理执行的结果" + rs);
            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(rs);
            objectOutputStream.flush();
        } catch (IOException e) {
     
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
     
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
     
            e.printStackTrace();
        } catch (IllegalAccessException e) {
     
            e.printStackTrace();
        } catch (InvocationTargetException e) {
     
            e.printStackTrace();
        } finally {
     
            //TODO 关闭流
        }
    }

    private Object invoke(RpcRequest request) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
     
        Class clazz = Class.forName(request.getClassName());
        Method method = clazz.getMethod(request.getMethodName(),request.getTypes());
        return method.invoke(service, request.getArgs());
    }
}

4. 改进的方向

  • 只支持java语言,耦合性比较强。可以采用json或者xml进行数据传输
  • Java NIO/BIO效率比较低,可以采用Netty BIO传输
  • Java序列化数据量大,可以考虑其他方式Hessian/Protobuf/Avro
  • 使用注解方式标识需要RPC的服务端和客户端
  • 考虑如何做成中间件的形式

5. 现有的RPC框架

  • Hessian
  • Thrift
  • Dubbo
  • Motan
  • gRPC

代码github链接:RPC V1

你可能感兴趣的:(分布式基础,rpc,java,socket)