基础
远程过程调用
是一种协议,允许程序在不同的计算机之间进行通信和交互,就像在调用本地方法一样
RPC允许程序(这里可以理解为服务消费者)像调用自己程序的方法一样,调用另外一个程序(这里可以理解为服务提供者)的接口。
在调用过程中,服务不需要了解数据的传输处理过程、底层网络通信的细节,这些全都有RPC框架统一进行处理。
基础设计
举个例子来分析RPC框架的流程
假设现在有两个web服务A和B,B提供了一个接口可以对外使用。
http请求
如果A想要调用B的接口,由于不在一个服务,如果要用,可以通过HTTP请求的方式进行调用B接口,这是常规思路。
那么当B提供的接口有很多,A想要使用不同的接口时候,是不是每次调用都要构建HTTP请求来做
请求处理器
这时候,为了减少重复代码,我们可以想到,服务提供者可以构建一个请求处理器,通过传入相应的参数,由请求处理器统一处理如何调用接口。而服务调用者统一调用这个请求处理的接口可以,只需要告诉处理器,你要调用的方法名字是什么,对应你传入的参数是什么。
服务注册器
这个时候,请求处理器拿到了要调用的方法的名字以及参数,但是如何去寻找到方法呢?
就需要在服务提供者的内部维护一个映射关系,即对外提供的接口名字和方法所在类的全路径名的映射关系,这样请求处理器通过接口名字找到类的全路径名,就可以通过反射机制调用方法
序列化
由于AB在不同的服务,之间的通信需要进行网络传输,但是JAVA对象本身是不可以进行网络传输的,就需要用到序列化和反序列化的知识。
请求代理
同时,在服务的调用端,为了简化服务调用者请求接口的代码复杂度,可以使用代理对象的形式,调用者只需要按正常调用接口的方式进行调用,由代理对象对其调用进行http包装,发起请求,返回结果。
扩展设计
服务注册发现-注册中心
消费者在调用接口的时候,怎么知道服务提供者所在的地址是什么?
当接口数量非常多的时候,当服务提供者非常多的时候,如何快速的找到哪个接口所在的服务在哪里呢?
当服务的地址发生变化的时候,提供者如何快速知道呢?
这时候可以引入一个第三方来维护这些内容,称为注册中心
当服务提供者服务启动时,将自己的基础信息注册到注册中心
服务消费者调用的时候,可以通过注册中心拿到对应的调用信息
当服务提供者发生变化的时候,也可以通知到注册中心自己的变化,便于提供者调用的时候从注册中心拿到最新的数据进行调用
常用的注册中心:redis、zookeeper、nacos
负载均衡
举个例子,现在有两个服务A和B,A在调用B的接口的时候,如果B服务只有一个实例,那直接调用即可。那如果B服务有多个实例B1-B9呢?A在调用的时候应该用哪个实例呢?
可以有以下几种策略:
轮询:比如说第一次调B1,第二次调B2,依次类推
随机:每次调用的时候,从1-9中随机选一个数字,然后调用对应的服务
权重:可以为每个实例根据情况设置不同的权重,比如性能,那么在调用的时候,根据权重去选择服务实例
容错
如果服务调用失败,应该怎么处理
调用失败后,可以选择性进行重试
重试失败后,可以对服务进行降级处理
其他问题
如果服务提供者的一个节点下线了,如何从注册中心剔除无效节点
服务提供者每次调用的时候都实时从注册中心拉取服务列表吗?可以使用缓存进行性能优化?
服务之间调用采用网络传输,需要考虑如何优化传输的性能?自定义协议?
如何让框架变得易于扩展?SPI机制?