项目-RPC框架
被问到项目了,答得很差,单独开贴总结项目
介绍一下这个项目,有什么亮点?
这是一个自行实现的远程过程调用框架demo
OS:眼不瞎也不需要你告诉我是个远程调用框架,干巴巴一句
功能是:实现在一台机器上(也就是客户端),像调用本地方法一样,通过传参,可以调用另一台机器(也就是服务器)上的函数或方法,并得到返回结果
Tips:一句话讲明白RPC是什么,让面试官知道你能清楚阐释这一概念
Ques:穿插八股文:那为什么不用Http请求?和Http的方式有什么区别?
场景上:RPC主要用于公司内部服务间的调用,而Http主要用于对外的异构环境
技术细节上:它相较于直接使用Http请求的优势在于:
- 一是传输效率上:
- 如Http/1.1协议请求头中包含了很多冗余的字段信息,这些冗余信息会增大传输的负担、降低效率,而自定义的RPC协议可以最大化传输效率
另值得一提的是,Http/2.0已经引入头部压缩机制优化了这方面的问题 - 而传输格式上RPC可以使用序列化后的二进制传输,性能上优于Http的JSON格式传输,本项目中采用了四种序列化方式
- 二是在通信传输的基础上,可以提供一些增强的功能特性,比如:
- 负载均衡策略,本项目中也实现了随机和轮转两种负载均衡算法
- 再比如服务治理,本项目中就使用了Nacos对服务上下线做了管理,这是HTTP不支持的
Tips:
- 让面试官知道你对Http协议有一定的了解,同时也是往这方面引
- 点一点,将八股联系到自己的项目细节
Ques:那讲一讲你项目里定义的传输协议
项目中关于传输的格式,严格来说并不能算是一个协议,而是定义了RpcRequest
和RpcResponse
两个对象作为请求和相应的规范形式
传输时直接传输序列化后的这两个对象
其中,RpcRequest
对象中的属性包括:
- 请求号:与相应对应
- 待调用方法的相关参数,包括:
- 接口名
- 方法名
- 方法参数
- 方法参数类型
- 最后是一个是否心跳包的bool值,用于心跳检测
RpcResponse
对象中的属性包括:
- 请求号:与请求对应
- 状态码和补充信息
- 响应数据
这里还封装了success和fail两个快速响应模板的方法
Ques:为什么要用到RPC,RPC的作用是什么?
在实现像本地调用一样调用远程方法,非常方便、可用
屏蔽了实现与调用过程、以及网络通信的复杂性
Ques:那你讲一讲各版本的Http协议有什么区别?Https了解吗?
主要包括了三个角色:注册中心,客户端和服务端
- 服务端将可提供的服务暴露给注册中心,客户端从注册中心发现已注册的服务,同时注册中心还使用了心跳检测机制以确保注册服务的可用
- 然后负载均衡这边是在客户端自行简易实现的,通过不同策略生成随机数,从发现的服务列表中选择一个
客户端通过JDK动态代理生成接口实现类对象,即RpcRequest
对象,这里用到了构造者模式然后发送给服务端
Ques:八股文:讲一讲动态代理
- 服务端会有一个线程池来处理接收到的请求,这里用到了多线程设计模式中的工作线程模式,然后通过反射生成
RpcRequest
对象,获取方法调用参数和参数类型,调用方法并返回RpcResponse
对象
Ques:讲一讲工作线程模式
其实就是线程池的核心思想:使用有限数量的线程去轮流处理任务
Ques:八股文:讲一讲线程池
在这个项目中最重要的两个点是:
- 序列化
这边采用了四种序列化方式,包括Json、Kyro以及另外两种序列化协议
默认采用的是Kryo对象序列化框架,主要基于亮点优势
- 是基于字节的序列化方式,空间效率好
- 序列化时记录了属性对象的类型信息,不会出现想JSON丢失对象类型,需要额外参数指定反序列化对象类型的情况
- 网络传输
网络传输采用了Java默认的Socket和Netty两种方式
相较于Socket的BIO,Netty采用了更高效的NIO传输方式
讲一讲BIO、NIO区别
- BIO是阻塞的,数据读取必须阻塞在一个线程内等待其完成,NIO是非阻塞的
- BIO是面向流的,只能单向读写;NIO是面向缓冲的,可以双向读写
- BIO为每一个连接新建线程;NIO多路复用,使用一个线程来监听所有的Socket连接
了解有哪些开源的RPC框架吗?它们有什么区别?
- Dubbo:阿里巴巴开源,国内知名度最高,但是不维护了
- gRPC:Google开源,主要面向移动应用而且基于Http/2.0,但是生产使用需要扩展开发
grpc基于http2,更容易跨语言支持
- thrift:Apache开源,跨语言但是不支持服务治理
- rpcx:Go语言实现,支持多种服务发现和服务路由方式,性能最好的RPC框架之一
为什么要做这个项目?你收获了什么?
能够更好地理解分布式-微服务体系中通信远程调用的实现原理
整合练习了Netty网络通信、Java中的序列化和反射
讲一讲实现的负载均衡策略
负载均衡是由customer端实现的,从Nacos注册中心获取到服务列表中根据负载均衡策略选择其中某一个服务
这边的是随机和轮转这两种最简单的负载均衡算法的简单实现,当然还有更复杂效果更好的,只是个人很难实现
随机是通过生成随机数的方式实现的
轮转是通过遍历服务列表实现的
Ques:这两种负载均衡方式的优点和缺点是什么?
- 随机说简单也简单,说难主要在于依赖随机算法实现对请求分配的均匀程度,做不好的话可能会导致一些极端情况出现,通常不直接使用,而是作为其他策略的补充
- 对于轮询而言,实现简单,而且可以使得分配到各个服务器的请求数量相对均衡,但是缺点也恰恰在于均衡分配了请求量,因为后端服务器的性能往往会有差异,会希望性能好的机器能够多承担一部分。
也不适合对长连接和命中率有要求的场景
Quse:那你还知道有哪些负载均衡算法?
- 加权轮询:就是对上面轮询的改进,权重与请求分配数成正比,但同样不适合对长连接和命中率有要求的场景
- Hash绑定:根据IP、Url等算出一个哈希值,并维护一个哈希值与服务器绑定的映射表,实现请求与固定服务器绑定,这样可以解决像Session不跨域的问题,非常适合维护长连接和提高命中率
缺点是如果某台服务器宕机,或是要扩容的饿情况,造成哈希算法变动,需要重新计算哈希值,会几乎影响到所有的请求路由
另外如果热点数据被绑定到了一台机器上,就可能会发生雪崩,这种情况下就需要额外的处理分散压力- 最短响应时间:响应快、响应时间短的优先访问,可以提高用户的体验
- 一致性Hash:可以解决上面Hash绑定中服务器集群数量变动导致的问题,被广泛运用,像nginx、memcached都采用了它作为集群负载均衡的方案
Ques:讲一讲一致性Hash
首先,相对于传统的线性数组,一致性Hash的空间被构建成了一个“环”,并对节点做两步映射
- 给每个节点(集群)计算Hash值并记录,这就是它们在环上的位置
- 给每个key计算Hash,然后沿着顺时针方向找到环上第一个节点,这就是key储存对应的集群
本文作者:YaosGHC
本文链接:https://www.cnblogs.com/yaocy/p/16828075.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步