• rpc


    RPC框架性能大比拼 :
    http://colobu.com/2016/09/05/benchmarks-of-popular-rpc-frameworks/

    百分点 harpc git:https://github.com/baifendian/harpc

    RPC 简介

          RPC(Remote Procedure Call,远程过程调用)是建立在Socket之上的,出于一种类比的愿望,在一台机器上运行的主程序,可以调用另一台机器上的程序,就像LPC(本地过程调用)
    越底层,代码越复杂、灵活性越高、效率越高
    越上层,抽象封装的越好、代码越简单、效率越差
         Socket和RPC的区别再次说明了这点。在传统的编程概念中,过程是由程序员在本地编译完成,并只能局限在本地运行的一段代码,也即其主程序和过程之间的运行关系是本地调用关系。因此这种结构在网络日益发展的今天已无法适应实际需求。传统过程调用模式无法充分利用网络上其他主机的资源(如CPU、Memory等),也无法提高代码在实体间的共享程度,使得主机资源大量浪费。
         通过RPC我们可以充分利用非共享内存的多处理器环境(例如通过局域网连接得多台工作站),这样可以简便地将你的应用分布在多台工作站上,应用程序就像运行在一个多处理器的计算机上一样。你可以方便的实现过程代码共享,提高系统资源的利用率,也可以将以大量数值处理的操作放在处理能力较强的系统上运行,从而减轻前端机的负担。
         RPC作为普遍的C/S开发方法,开发效率高效,可靠.但RPC方法的基本原则是:以模块调用的简单性忽略通讯的具体细节,以便程序员不用关心C/S之间的通讯协议,集中精力对付实现过程.这就决定了 RPC生成的通讯包不可能对每种应用都有最恰当的处理办法,与Socket方法相比,传输相同的有效数据,RPC占用更多的网络带宽.
    RPC是在Socket的基础上实现的,它比socket需要更多的网络和系统资源.另外,在对程序优化时,程序员虽然可以直接修改由rpcgen产生的令人费解的源程序,但对于追求程序设计高效率的RPC而言,获得的简单性则被大大削弱.
    RPC 这个概念术语在上世纪 80 年代由 Bruce Jay Nelson 提出。这里我们追溯下当初开发 RPC 的原动机是什么?在 Nelson 的论文 "Implementing Remote Procedure Calls" 中他提到了几点:
        1. 简单:RPC 概念的语义十分清晰和简单,这样建立分布式计算就更容易。
        2. 高效:过程调用看起来十分简单而且高效。
        3. 通用:在单机计算中过程往往是不同算法部分间最重要的通信机制。
    通俗一点说,就是一般程序员对于本地的过程调用很熟悉,那么我们把 RPC 作成和本地调用完全类似,那么就更容易被接受,使用起来毫无障碍。Nelson 的论文发表于 30 年前,其观点今天看来确实高瞻远瞩,今天我们使用的 RPC 框架基本就是按这个目标来实现的

    RPC 实现


    1、 服务调用方(client)调用以本地调用方式调用服务;
    2、 client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;在Java里就是序列化的过程
    3、 client stub找到服务地址,并将消息通过网络发送到服务端;
    4、 server stub收到消息后进行解码,在Java里就是反序列化的过程;
    5、 server stub根据解码结果调用本地的服务;
    6、 本地服务执行处理逻辑;
    7、 本地服务将结果返回给server stub;
    8、 server stub将返回结果打包成消息,序列化;
    9、 server stub将打包后的消息通过网络并发送至消费方
    10、 client stub接收到消息,并进行解码, 反序列化;
    11、 服务调用方(client)得到最终结果


    RPC框架的目标就是把2-10步封装起来,把调用、编码/解码的过程封装起来,让用户像调用本地服务一样的调用远程服务。要做到对客户端(调用方)透明化服务, RPC框架需要考虑解决如下问题:
    1、 服务端提供的服务如何发布,客户端如何发现服务;
    2、 如何对请求对象和返回结果进行序列化和反序列化;
    3、 如何更高效进行网络通信。

    rpc vs http

    RPC是一种编程模式,把对服务器的调用抽象为过程调用,通常还伴随着框架代码自动生成等功能。使用RPC做网络服务开发时,通常只需要实现服务器端的一个处理函数,其余的客户端调用,序列化反序列化,方法派发(收到什么样的消息,调用服务器端的什么函数)等都由框架或者生成的代码来完成,较大地减轻了网络服务开发和调用的复杂性。
    HTTP是一种应用层网络协议,RPC可以采用自定义协议,也可以通过HTTP协议来传输,thrift,grpc,xml-rpc,json-rpc都是通过HTTP传输的。HTTP既支持长连接,也支持短连接。

    常用的rpc框架
    Dubbo

    阿里巴巴公司开源的一个Java高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。不过,略有遗憾的是,据说在淘宝内部,dubbo由于跟淘宝另一个类似的框架HSF(非开源)有竞争关系,导致dubbo团队已经解散(参见http://www.oschina.net/news/55059/druid-1-0-9 中的评论),反到是当当网的扩展版本仍在持续发展,墙内开花墙外香。其它的一些知名电商如当当、京东、国美维护了自己的分支或者在dubbo的基础开发,但是官方的库缺乏维护,相关的依赖类比如Spring,Netty还是很老的版本(Spring 3.2.16.RELEASE, netty 3.2.5.Final),倒是有些网友写了升级Spring和Netty的插件。

    Motan

    新浪微博开源的一个Java 框架。它诞生的比较晚,起于2013年,2016年5月开源。Motan 在微博平台中已经广泛应用,每天为数百个服务完成近千亿次的调用。

    rpcx

    Go语言生态圈的Dubbo, 比Dubbo更轻量,实现了Dubbo的许多特性,借助于Go语言优秀的并发特性和简洁语法,可以使用较少的代码实现分布式的RPC服务。

    gRPC

    Google开发的高性能、通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发语言。本身它不是分布式的,所以要实现上面的框架的功能需要进一步的开发。

    thrift

    Apache的一个跨语言的高性能的服务框架,也得到了广泛的应用

    性能比较:

    吞吐率:rpcx > thrift > grpc > montan > dubbo
    平均响应时间: rpcx > thrift > grpc > montan > dubbo

    举个栗子

    一个非常简单的非分布式demo

    定义 server stub

    public class RPCServer {
        private ExecutorService threadPool;  
        private static final int DEFAULT_THREAD_NUM = 10;  
          
        public RPCServer(){  
            threadPool = Executors.newFixedThreadPool(DEFAULT_THREAD_NUM);  
        }  
        public void register(Object service, int port) {
             try {  
                    System.out.println("server starts...");  
                    ServerSocket server = new ServerSocket(port);  
                    Socket socket = null;  
                    while((socket = server.accept()) != null){  
                        System.out.println("client connected...");  
                        threadPool.execute(new Processor(socket, service));  
                    }  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }          
        }  
          
        class Processor implements Runnable{  
            Socket socket;  
            Object service;  
            public Processor(Socket socket, Object service){  
                this.socket = socket;  
                this.service = service;  
            }  
            public void process(){  
            }  
            @Override  
            public void run() {  
                try {  
                    ObjectInputStream in = new ObjectInputStream(socket.getInputStream());  
                    String methodName = in.readUTF();  
                    Class<?>[] parameterTypes = (Class<?>[]) in.readObject();  
                    Object[] parameters = (Object[]) in.readObject(); 
                    Method method = service.getClass().getMethod(methodName, parameterTypes);  
                    try {  
                        Object result = method.invoke(service, parameters);  
                        ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());  
                        out.writeObject(result);  
                    } catch (IllegalAccessException e) {  
                        e.printStackTrace();  
                    } catch (IllegalArgumentException e) {  
                        e.printStackTrace();  
                    } catch (InvocationTargetException e) {  
                        e.printStackTrace();  
                    }  
                } catch (IOException e) {  
                    e.printStackTrace();  
                } catch (NoSuchMethodException e) {  
                    e.printStackTrace();  
                } catch (SecurityException e) {  
                    e.printStackTrace();  
                } catch (ClassNotFoundException e1) {  
                    e1.printStackTrace();  
                }  
            }  
        }
    }
    View Code

    定义 client stub

    public class RPCClient {
        @SuppressWarnings("unchecked")  
        public static <T> T getClient(Class<T> clazz, final String ip, final int port){  
            return  (T) Proxy.newProxyInstance(RPCClient.class.getClassLoader(), new Class<?>[]{clazz}, new InvocationHandler() {  
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Socket socket = new Socket(ip, port);  
                        ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());  
                        out.writeUTF(method.getName());  
                        out.writeObject(method.getParameterTypes());  
                        out.writeObject(args); 
                        System.out.println(method.getName()+method.getParameterTypes()+args);
                        ObjectInputStream in = new ObjectInputStream(socket.getInputStream());  
                        return in.readObject();  
                }  
            });  
        }  
    }
    View Code

    定义接口 (server)

    public interface HelloService {
        public String hello(String name);
    }
    View Code

    定义实现类(server)

    public class HelloServiceImpl implements HelloService {
        @Override
        public String hello(String name) {
            return "hello "+name;
        }
    }
    View Code

    启动 rpc服务

    public class ServerStart {
    
        public static void main(String[] args) {
            HelloService helloService = new HelloServiceImpl();
            RPCServer server = new RPCServer();
            server.register(helloService, 5001);
        }
    
    }
    View Code

    调用rpc服务 (client)

    public class Client {
    
        public static void main(String args[]) {
            HelloService helloService = RPCClient.getClient(HelloService.class, "127.0.0.1", 5001);
            System.out.println(helloService.hello("young z"));
        }
    
    }
    View Code
  • 相关阅读:
    自动化CodeReview
    10个有关RESTful API良好设计的最佳实践
    ASP.NET Core 获取控制器上的自定义属性
    [转] Autofac创建实例的方法总结
    PetaPoco
    LogViewer
    hdoj:2047
    hdoj:2046
    hdoj:2045
    hdoj:2044
  • 原文地址:https://www.cnblogs.com/amei0/p/8569741.html
Copyright © 2020-2023  润新知