- RPC-KTY一款基于 Netty + Kyro / Protostuff + Zookeeper 实现的 RPC 框架。那么何为RPC框架呢?RPC(Remote Procedure Call)即远程过程调用,通过名字我们就能看出 RPC 关注的是远程调用而非本地调用。通过 RPC 可以帮助我们调用远程计算机上某个服务的方法,这个过程就像调用本地方法一样简单。并且我们不需要了解底层网络编程的具体细节😄😄😄
- 🎥Java基础:
- 动态代理机制(态代理 + JDK / CGLIB / Javassit 动态代理)
- Java I/O 系统
- Java 并发/多线程
- Java 网络编程(Socket 编程)
- Java 注解
- Java 反射
- 序列化机制以及序列化框架(Kryo / Protostuff )的基本使用
- 📙Netty:使 NIO 编程更加容易,屏蔽了 Java 底层的 NIO 细节
- 📑Zookeeper:提供服务注册与发现功能,开发分布式系统的必备选择,具备天生的集群能力
- 🗳Spring Framework(Spring):最强大的依赖注入框架,业界的权威标准
- 🐵使用 Spring 提供依赖注入与参数配置,集成 Spring 通过注解注册服务,集成 Spring 通过注解消费服务
- 🦍使用 Netty 进行网络传输,使 NIO 编程更加容易,屏蔽了 Java 底层的 NIO 细节
- 🦮基于开源的序列化框架 Protostuff / Kyro 实现消息对象的序列化/反序列化
- 🐈可优化:用户通过配置文件指定序列化方式,避免硬编码
- 🐴自定义编解码器(底层利用 Protostuff / Kyro )实现
- 🐂TCP 心跳机制
- 🐏使用 JDK / CGLIB 动态代理机制调用远程方法(调用远程方法像调用本地一样简单)
- 🐪使用 Zookeeper(ZkClient 客户端)实现服务注册和发现
- 🐹客户端调用远程服务的时候进行负载均衡 :调用服务的时候,从很多服务地址中根据相应的负载均衡策略选取一个服务地址。目前使用的策略为随机负载均衡
- 推荐使用 Zookeeper,注册中心负责服务地址的注册与查找,相当于目录服务。服务端启动的时候将服务名称及其对应的地址(ip+port)注册到注册中心,服务消费端根据服务名称找到对应的服务地址。有了服务地址之后,服务消费端就可以通过网络请求服务端了。
- ZooKeeper 为我们提供了高可用、高性能、稳定的分布式数据一致性解决方案,通常被用于实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。并且,ZooKeeper 将数据保存在内存中,性能是非常棒的。
- 既然要调用远程的方法就要发请求,请求中至少要包含你调用的类名、方法名以及相关参数吧!推荐基于 NIO 的 Netty 框架。
- Netty 是一个基于 NIO 的 client-server(客户端服务器)框架,使用它可以快速简单地开发网络应用程序,它屏蔽了 Java 底层的 NIO 细节
- 在网络传输的过程中,网络传输的数据必须是二进制的,所以 Java 对象在网络中传输我们需要将其序列化为二进制的数据,我们需要的还是 Java 对象,所以我们还需要将二进制反序列化为 Java 对象
- 既然涉及到网络传输就一定涉及到序列化,你不可能直接使用 JDK 自带的序列化吧!JDK 自带的序列化效率低并且有安全漏洞。 所以,你还要考虑使用哪种序列化协议,比较常用的有 hession2、kyro、protostuff。
- 另外,动态代理也是需要的。因为 RPC 的主要目的就是让我们调用远程方法像调用本地方法一样简单,使用动态代理可以屏蔽远程方法调用的细节比如网络传输,所以实际会通过代理对象来传输网络请求
- 当我们的系统中的某个服务的访问量特别大,我们将这个服务部署在了多台服务器上,当客户端发起请求的时候,多台服务器都可以处理这个请求,这时我们就需要负载均衡为我们避免单个服务器响应同一请求,容易造成服务器宕机、崩溃等问题
- 我们还需要设计一个私有的 RPC 协议(通信/传输协议),这个协议是客户端(服务消费方)和服务端(服务提供方)交流的基础。
- 通过设计传输协议,我们定义需要传输哪些类型的数据, 并且还会规定每一种类型的数据应该占多少字节。这样我们在接收到二级制数据之后,就可以正确的解析出我们需要的数据。
- 通常一些标准的 RPC 协议包含下面这些内容:
- 魔数 : 通常是 4 个字节。这个魔数主要是为了筛选来到服务端的数据包,有了这个魔数之后,服务端首先取出前面四个字节进行比对,能够在第一时间识别出这个数据包并非是遵循自定义协议的,也就是无效数据包,为了安全考虑可以直接关闭连接以节省资源。
- 序列化器编号 :标识序列化的方式,比如是使用 Java 自带的序列化,还是 json,kyro 等序列化方式。
- 消息体长度 : 运行时计算出来