001--RPC是什么鬼?

2018-05-11  本文已影响76人  糖纸疯了

1.单体架构和分布架构对比?

  • 1.单体架构
    - 创建接口oper,然后接口实现operImp
    - new operImp().run()!(同一块内存上面,可以直接调用内存中的方法)
    - 完美实现本地方法调用!
  • 2.分布架构:
    - 服务分别放置在不同的服务器上(不是同一块内存地址)
    - 如果服务A想调用服务B的new operImp().run()方法,不可能new operImp(),因为服务A根本没有operImp()的接口实现
    - 怎么办?搞一个WebService可以吗?搞一个Restful接口共外部调用可以吗?--都可以
    - 那为什么还要搞一个RPC?

2.RPC是什么鬼?

“RPC,就是Remote Procedure Call的简称呀,翻译成中文就是远程过程调用!”

1.解决分布式系统中,服务之间的调用问题。
2.远程调用时,要能够像本地调用一样方便,让调用者感知不到远程调用的逻辑。

3.RPC大致是什么样的运行机制?

那么如何实现远程过程调用,也就是RPC呢,一个完整的RPC流程,可以用下面这张图来描述

其中左边的Client,对应的就是前面的Service A,而右边的Server,对应的则是Service B。
下面一步一步详细解释一下。

4.如何实现一个RPC

核心内容解说:
 - 服务提供端
      - 1.创建接口
      - 2.用Socket进行监听请求,并判断请求的方法名,将结果传回Socket返回值中
- 服务消费端
      - 1.获取Socket
      - 2.从Socket返回值中将数据取出来
- 最本质东西
      - 请求时:将 "方法名+参数"  序列化,Socket通信传递
      - 接受时:将 "方法名+参数"  反序列化,然后进行还原方法的真实调用
服务提供者核心代码
public class Provider {
    public static void main(String[] args) throws Exception {
        // 将服务提供出去,使用Socket进行模拟
        new Provider().privoderServer();
    }
    private void privoderServer() throws Exception{
        // 创建Socket监听器
        ServerSocket listener = new ServerSocket(CalculateRpcRequest.PORT);
        Calculator calculator = new CalculatorImpl();
        System.out.println("----------成功将服务发布");
        try {
            // 然后执行监听外界的请求
            while (true) {
                Socket socket = listener.accept();
                // 将请求反序列化
                ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
                Object object = objectInputStream.readObject();

                // 调用服务
                int result = 0;
                if (object instanceof CalculateRpcRequest) {
                    CalculateRpcRequest calculateRpcRequest = (CalculateRpcRequest) object;
                    if ("add".equals(calculateRpcRequest.getMethod())) {
                        result = calculator.add(calculateRpcRequest.getA(), calculateRpcRequest.getB());
                    } else {
                        throw new UnsupportedOperationException();
                    }
                }

                // 返回结果
                ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
                objectOutputStream.writeObject(new Integer(result));
            } 
        } catch (Exception e) {

        } finally {
            listener.close();
        }
    }
}
服务消费者核心代码
public class CalculatorRemoteImpl implements Calculator {
    public int add(int a, int b)  {
        String address = "127.0.0.1";// 因为现在是一个服务,所以地址是写死的,以后用负载的话,对比Eureka,根据服务名,去找对应的端口,然后进行负载
        Socket socket = null;
        try {
            socket = new Socket(address, CalculateRpcRequest.PORT);
            // 将请求序列化
            CalculateRpcRequest calculateRpcRequest = new CalculateRpcRequest("add", 1, 2);
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            // 将请求发给服务提供方
            objectOutputStream.writeObject(calculateRpcRequest);
            // 将响应体反序列化
            ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
            Object response = objectInputStream.readObject();
            System.out.println("消费者进行服务调用,结果为:" + response);
            if (response instanceof Integer) {
                return (Integer) response;
            } else {
                throw new InternalError();
            } 
        } catch (Exception e) {
        }finally{
            if (null!=socket) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return 0;
    }
}

5.难道创建一个RPC模型就无敌了?

1.要实现一个RPC不算难,难的是实现一个高性能高可靠的RPC框架。
2.既然是分布式了,那么一个服务可能有多个实例,你在调用时,要如何获取这些实例的地址呢?

这时候就需要一个服务注册中心,比如在Dubbo里头,就可以使用Zookeeper作为注册中心,在调用时,从Zookeeper获取服务的实例列表,再从中选择一个进行调用。

3.那么选哪个调用好呢?

这时候就需要负载均衡了,于是你又得考虑如何实现复杂均衡,比如Dubbo就提供了好几种负载均衡策略。

4.总不能每次调用时都去注册中心查询实例列表吧,这样效率多低呀

这时候就需要缓存,有了缓存,就要考虑缓存的更新问题

5.客户端总不能每次调用完都干等着服务端返回数据吧,于是就要支持异步调用;

服务端的接口修改了,老的接口还有人在用,怎么办?总不能让他们都改了吧?这就需要版本控制了;

6.服务端总不能每次接到请求都马上启动一个线程去处理吧?

于是就需要线程池;

  1. 服务端关闭时,还没处理完的请求怎么办?是直接结束呢,还是等全部请求处理完再关闭呢?

6.博客参考网址

上一篇下一篇

猜你喜欢

热点阅读