1 Star 0 Fork 587

可乐君 / guide-rpc-framework

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

guide-rpc-framework

guide-rpc-framework 是一款基于 Netty+Kyro+Zookeeper 实现的 RPC 框架。代码注释详细,结构清晰,并且集成了 Check Style 规范代码结构,非常适合阅读和学习。

由于Guide哥自身精力和能力有限,如果大家觉得有需要改进和完善的地方的话,欢迎将本项目 clone 到自己本地,在本地修改后提交 PR 给我,我会在第一时间 Review 你的代码。

介绍

我们先从一个基本的 RPC 框架设计思路说起!

一个基本的RPC框架设计思路

一个典型的使用 RPC 的场景如下,一般情况下 RPC 框架不仅要提供服务发现功能,还要提供负载均衡、容错等功能,这个的 RPC 框架才算真正合格。

一个完整的RPC框架使用示意图

简单说一下设计一个最基本的 RPC 框架的思路:

  1. 注册中心 :注册中心首先是要有的,推荐使用 Zookeeper。注册中心主要用来保存相关的信息比如远程方法的地址。
  2. 网络传输 :既然要调用远程的方法就要发请求,请求中至少要包含你调用的类名、方法名以及相关参数吧!推荐基于NIO 的 Netty框架。
  3. 序列化 :既然涉及到网络传输就一定涉及到序列化,你不可能直接使用 JDK 自带的序列化吧!JDK 自带的序列化效率低并且有安全漏洞。 所以,你还要考虑使用哪种序列化协议,比较常用的有 hession2、kyro、protostuff。
  4. 动态代理 : 另外,动态代理也是需要的。因为 RPC 的主要目的就是让我们调用远程方法像调用本地方法一样简单,使用动态代理屏蔽远程接口调用的细节比如网络传输。
  5. 负载均衡 :负载均衡也是需要的。为啥?举个例子我们的系统中的某个服务的访问量特别大,我们将这个服务部署在了多台服务器上,当客户端发起请求的时候,多台服务器都可以处理这个请求。那么,如何正确选择处理该请求的服务器就很关键。假如,你就要一台服务器来处理该服务的请求,那该服务部署在多台服务器的意义就不复存在了。负载均衡就是为了避免单个服务器响应同一请求,容易造成服务器宕机、崩溃等问题,我们从负载均衡的这四个字就能明显感受到它的意义。
  6. ......

项目基本情况和可优化点

最期初的是时候,我是基于传统的 BIO 的方式 Socket 进行网络传输,然后利用 JDK 自带的序列化机制 以及内存直接存储相关服务相关信息来实现这个 RPC 框架的。

后面,我对原始版本进行了优化,已完成的优化点和可以完成的优化点如下。

为什么要把可优化点列出来? 主要是想给哪些希望优化这个 RPC 框架的小伙伴一点思路。欢迎大家 Clone 本仓库,然后自己进行优化。

  • 使用Netty(基于NIO)替代BIO实现网络传输;
  • 使用开源的序列化机制 Kyro(也可以用其它的)替代 JDK 自带的序列化机制;
  • 使用Zookeeper管理相关服务地址信息
  • Netty重用Channel避免重复连接服务端
  • 使用 CompletableFuture 包装接受客户端返回结果(之前的实现是通过 AttributeMap 绑定到Channel上实现的) 详见:使用CompletableFuture优化接受服务提供端返回结果
  • 增加 Netty 心跳机制
  • 增加可配置比如序列化方式、注册中心的实现方式,避免硬编码 :通过API配置,后续集成 Spring 的话建议使用配置文件的方式进行配置
  • 客户端调用远程服务的时候进行负载均衡 :发布服务的时候增加 一个 loadbalance 参数即可。
  • 使用注解进行服务配置和消费
  • 处理一个接口有多个实现的情况 :对服务分组,发布服务的时候增加一个 group 参数即可。
  • 增加服务版本号 :建议使用两位数字版本,如:1.0,通常在接口不兼容时版本号才需要升级。为什么要增加服务版本号?为后续不兼容升级提供可能,比如服务接口增加方法,或服务模型增加字段,可向后兼容,删除方法或删除字段,将不兼容,枚举类型新增字段也不兼容,需通过变更版本号升级。
  • 客户端与服务端通信协议(数据包结构)重新设计 ,可以将原有的 RpcRequest RpcReuqest 对象作为消息体,然后增加如下字段(可以参考:《Netty入门实战小册》和Dubbo框架对这块的设计):
    • 魔数 : 通常是 4 个字节。这个魔数主要是为了筛选来到服务端的数据包,有了这个魔数之后,服务端首先取出前面四个字节进行比对,能够在第一时间识别出这个数据包并非是遵循自定义协议的,也就是无效数据包,为了安全考虑可以直接关闭连接以节省资源。
    • 序列化器编号 :标识序列化的方式,比如是使用 Java 自带的序列化,还是 json,kyro 等序列化方式。
    • 消息体长度 : 运行时计算出来。
    • ......

项目模块概览

运行项目

1.导入项目

克隆项目到自己的本地:git clone git@github.com:Snailclimb/guide-rpc-framework.git

然后使用 IDEA 打开,等待项目初始化完成。

2.初始化git hooks

以下演示的是 Mac/Linux对应的操作,Window 用户需要手动将 config/git-hooks 目录下的pre-commit 文件拷贝到 项目下的 .git/hooks/ 目录。

你需要以此执行下面这些命令:

➜  guide-rpc-framework git:(master)chmod +x ./init.sh
➜  guide-rpc-framework git:(master) ✗ ./init.sh 

init.sh 这个脚本的主要作用是将 git commit 钩子拷贝到项目下的 .git/hooks/ 目录,这样你每次commit的时候就会执行了。

cp config/git-hooks/pre-commit .git/hooks/
chmod +x .git/hooks/pre-commit

抱怨:项目上一直用的 Gradle,很久没用 Maven 了,感觉 Maven很多方面都比 Maven 要更好用!比如Gradle的项目依赖文件build.gradle 比 Maven 的pom.xml更加清晰简洁(Maven是因为xml的锅)、Gradel还可以使用 groovy 语言......

pre-commit 的内容如下,主要作用是在提交代码前运行 Check Style检查代码格式问题。

#!/bin/sh
#set -x

echo "begin to execute hook"
mvn checkstyle:check

RESULT=$?

exit $RESULT

效果展示:

3.CheckStyle 插件下载和配置

IntelliJ IDEA-> Preferences->Plugins->搜索下载CheckStyle 插件,然后按照如下方式进行配置。

CheckStyle 插件下载和配置

配置完成之后,按照如下方式使用这个插件!

插件使用方式

4.下载运行zookeeper

这里使用 Docker 来下载安装。

下载:

docker pull zookeeper:3.4.14

运行:

docker run -d --name zookeeper -p 2181:2181 zookeeper:3.4.14

使用

服务提供端

实现接口:

public class HelloServiceImpl implements HelloService {
   @Override
    public String hello(Hello hello) {
      ......
    }
}

发布服务(使用Netty进行传输):

HelloService helloService = new HelloServiceImpl();
NettyServer nettyServer = new NettyServer("127.0.0.1", 9999);
nettyServer.publishService(helloService, HelloService.class);

服务消费端

ClientTransport rpcClient = new NettyClientTransport();
RpcClientProxy rpcClientProxy = new RpcClientProxy(rpcClient);
HelloService helloService = rpcClientProxy.getProxy(HelloService.class);
String hello = helloService.hello(new Hello("111", "222"));

相关问题

为什么要造这个轮子?Dubbo不香么?

写这个 RPC 框架主要是为了通过造轮子的方式来学习,检验自己对于自己所掌握的知识的运用。

实现一个简单的RPC框架实际是比较容易的,不过,相比于手写AOP和IoC还是要难一点点,前提是你搞懂了RPC的基本原理。

我之前从理论层面在我的知识星球分享过如何实现一个RPC。不过理论层面的东西只是支撑,你看懂了理论可能只能糊弄住面试官。咱程序员这一行还是最需要动手能力,即使你是架构师级别的人物。当你动手去实践某个东西,将理论付诸实践的时候,你就会发现有很多坑等着你。

大家在实际项目上还是要尽量少造轮子,有优秀的框架之后尽量就去用,Dubbo 在各个方面做的都比较好和完善。

如果我要自己写的话,可以参考哪些资料?

代办~~~

空文件

简介

一款基于 Netty+Kyro+Zookeeper 实现的自定义 RPC 框架(附详细实现过程和相关教程)。 展开 收起
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
1
https://gitee.com/yiyang6code/guide-rpc-framework.git
git@gitee.com:yiyang6code/guide-rpc-framework.git
yiyang6code
guide-rpc-framework
guide-rpc-framework
master

搜索帮助