1.介绍一下你的RPC项目

RPC就是远程调用过程,整个项目共有3个组件,分别是客户端、注册中心和服务端。
(1)注册中心是基于Nacos和zk来实现的,服务端注册服务到注册中心,注册中心有保活机制,它是一种被动感知服务端上线和下线的,所以会存在一个延时性;所以项目中还使用了一个钩子方法,
(2) 在start()时注册这个钩子,当服务端下线时,会调用钩子方法,将注册中心中当前服务端注册的服务都清除。
(3)然后客户端可以通过注册中心拉取服务列表,从服务列表中选择一个访问节点进行远程调用,具体的算法是通过负载均衡策略来进行的,在项目中我实现了随机、轮询、加权随机、加权轮询、一致性哈希等5种负载均衡策略。另外客户端可以将拉取的服务列表缓存到本地,来减少客户端与注册中心的通信开销,并且如果注册中心发生宕机,客户端依然可以通过本地缓存来进行远程调用, 不必通过注册中心。客户端这边的话,我使用了jdk的动态代理技术,封装了客户端与服务端之间的通信细节,这里面涉及到了容错机制,容错机制就是客户端向服务端发起RPC调用的时候,会可能会失败,那失败的话我们就需要按照策略来进行调用失败的处理,所以就实现了failover(失败自动切换)、failfast(快速失败)、failsafe(失败安全)、failback(失败自动恢复)等四种容错机制。客户端与服务端的通信模式是实现了socket与netty两种,本质上就是bio与nio,然后通信协议的话,我们实现了基于TCP的应用层协议,分为消息头和消息体,消息头中包含了报文的类型(介绍)….然后通过序列化的方式将rpc消息对象转换成字节流形式,序列化机制我们实现了Kyro、Json、Protobuf、Hession等四种序列化机制,默认使用Kryo作为序列化机制;转换成二进制字节流后再通过gzip压缩机制,压缩消息体积,提高传输效率。然后rpc消息中会涉及到full-length表示整个的报文长度,因为传输层是基于TCP协议会存在黏包、半包的现象,通过netty的解决。为解决客户端与服务端之间通信需要频繁建立连接、注销连接,使用了channel复用机制。

2.声哥RPC总结

https://www.nowcoder.com/discuss/588903?source_id=profile_create_nctrack&channel=-1&page=2

3.服务端注册的服务下线以后,客户端是如何感知的?

注册中心zookeeper有一个心跳检测机制,会在一定时间内向各个服务发送请求,如果长期没有响应,注册中心就会剔除服务地址信息,但是我在项目中做了服务自动注销,是实现了一个钩子方法,在服务端下线之前,也就是jvm关闭之前,调用钩子方法,主动的去剔除服务地址信息,这样就不用等到心跳超时。然后zookeeper中有一个watch机制,客户端监听服务端节点,当地址发生变化之后,zookeeper会发送消息给客户端,客户端就将本地缓存的服务地址信息剔除,这样客户端就感知到了服务下线。
image.png
image.png