开始之前我还是先抛出几个问题:
如何做到HA?
如何针对并发场景?
能不能做到服务超时处理、失败重试以及确定不可用之后的熔断保护?
如何做到将请求均匀分发(路由)到rpc服务上?
对于以上问题,我们先不做解答,画了一张图来帮助大家理解:
图中的大概思路是:
客户端消费时,先从zk注册中心拿到可用的服务列表
接口动态代理类将请求信息(接口名,方法名,方法参数类型,方法参数,服务器地址)使用Netty客户端连接Netty服务端并发送
Netty服务端解析请求并调用响应的Handler处理请求并相应
使用Netty代替之前的jdk自带bio来提高性能
接下来我们就一步一步按照上述图中的描述来实现一款新的rpc框架。
①新建如下图的项目结构
rpc是聚合项目,提供版本管理通用依赖管理;rpc-common提供通用变量和一些工具类的管理;rpc-registry是一个注册中心接口声明;rpc-registry-zk提供zk版本的默认注册中心实现;rpc-server提供rpc服务的启动与服务信息注册以及服务调用的处理。
注:项目依赖spring,netty,zk等
项目之间的依赖关系图如下:
②编写rpc-common中的工具
RpcEncoder继承Netty提供的MessageToByteEncoder并重写encode方法:
RpcDecoder继承Netty提供的ByteToMessageDecoder,重写解码decode方法:
RpcRequest是rpc服务调用请求封装类:
RpcResponse是rpc服务调用后的响应:
工具类SerializationUtil,提供了两个方法,将对象序列化成字节数组和将字节数组反序列化成对象(使用Protostuff序列化工具,性能比较好):
③编写注册中心rpc-registry及其实现rpc-registry-zk(也可以其他实现):
ServiceDiscovery定义根据接口发现服务的功能:
ServiceRegistry定义将服务注册到注册中心的功能:
ZkServiceDiscovery从zk中查找并返回可用的服务对应的address:
ZkServiceRegistry提供将服务注册到zk的功能:
多个服务注册后zk中的节点tree结构如下:
每个节点存储的数据是类似127.0.0.1:8000
④编写rpc服务端rpc-server:
@RpcService注解标注一个服务
RpcServer是服务端最核心的一个类,通过spring扩展接口的特性自动启动服务器(Netty):
RpcServerHandler Netty服务器接收到消息之后具体的处理器:
⑤编写rpc客户端rpc-client:
RpcProxy动态代理类:
RpcClient是与rpc服务器(Netty)打交道的客户端:
现在rpc框架已经大致写好了,那接下来就是应用与测试了,我们创建三个项目rpc-sample-api服务接口定义,rpc-sample-server服务实现及提供者,rpc-sample-client服务消费者:
①rpc-sample-api中定义一个简单接口:
②rpc-sample-server中定义①中的接口实现以及程序启动功能:
log4j.properties是日志相关属性定义,rpc.properties中定义zk地址和rpc服务绑定地址端口
spring.xml中定义注册中心bean,以及rpc服务器bean
当然这所有的配置需要有一个门面类来启动(RpcBootstrap):
③rpc-sample-client充当消费者并编写测试逻辑:
log4j.properties以及rpc.properties和②中相似,spring.xml中定义服务发现bean和动态代理工具类bean
服务消费测试类Consumer
④这样服务端和消费端的逻辑都编写好了,接下来启动服务端和消费端测试。
先运行rpc-sample-server中的RpcBootstrap,再运行rpc-sample-client中的Consumer:
看到如上结果,可以认定服务启动成功,然后运行Consumer
可以看到服务已经调用成功并且返回正确结果,到此我们的“屌丝版”rpc已经编写完成和测试通过。
经过改进后的rpc框架虽然变得有模有样,但是仔细的看官仍会发现其存在很多不足,总结出来大概有以下几点:
服务调用失败没有重试机制
没有熔断保护机制
没有很优秀的路由机制
服务调用链不健壮:如果zk失去连接(宕机),消费端没有缓存机制来保持rpc服务端地址,当然服务端也无法继续注册服务
注册中心比较单薄,并且消费端和服务端对zk过度依赖,这个和④优点类似,注册中心没有集群做HA
消费端调用接口服务生成的动态代理类是手动创建,没有和spring融合实现@Autowired自动注入
这一篇利用Netty和spring实现了一款简单的rpc框架,相信大家对rpc的原理有了更深层次的认识和理解,接下来我们会对市面上比较流行的开源rpc框架针对其优缺点做分析。
代码地址:https://gitee.com/ScorpioAeolus/myRpc
创作不易,请多多支持!
附带公众号:
领取专属 10元无门槛券
私享最新 技术干货