RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。
上边是百度百科上边的解释,比较抽象。说一下我个人的理解:
- 从代码层面,是一种拆分,原本一个大项目拆分成多个
- 从业务层面,业务上的解耦,基于上一点,形成多个独立的功能模块(业务域)
- 从架构维护层面,是一种化整为零的思想,原本一个大项目,所有的代码和业务都在里边,启动需要半个小时甚至一个小时以上,rpc的出现就是把一个点打散到多个点
- 从性能&可用性层面,原本大项目所有的业务可能共享各种资源(DB,缓存),并发量足够大的情况下,由于后端资源紧张或者本身jvm资源问题,导致请求延迟严重,甚至单操作拖垮整个系统
总结出来,rpc的出现时为了实现业务代码解耦,项目架构分层。当然这也是概念层面的描述。引用rpc框架中一句比较经典的话,rpc使服务调用方像调用本地服务一样调用远程服务。
目前市面上比较流行的开源rpc框架有dubbo(x),gRpc,motan,thrift等,衡量一款好的rpc框架,至少应该具备以下特点:
- 简单使用:项目容易接入
- 性能好:使用rpc框架不会让请求响应能力出现断崖式下降
- 扩展性好:可以与其他流行开源产品糅合
为了更好更深入的了解rpc框架的原理,我们根据rpc的思想,使用原生java实现一版简单版的rpc框架,不引入任何框架。
① 新建如下项目结构:
rpc是聚合项目,server-interface是服务提供方的接口定义项目,server-provider是对server-interface中接口的实现,consumer是rpc服务的依赖调用方,pom中依赖service-interface不依赖实现。
② 在service-interface中定义一个简单的接口UserService:
③ server-provider中引入server-interface依赖,并定义UserService的实现:
<dependency>
<groupId>com.typhoon</groupId>
<artifactId>server-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
④既然是rpc服务,也就是说服务提供者是一个能够独立启动的程序,我们使用jdk自带的bio实现服务端启动:
⑤运行启动类,启动服务端:
这样的话,名义上我们rpc框架的服务端已经启动。接下来继续编写消费端项目并测试。
①consumer项目引入服务接口依赖,并编写逻辑:
<dependency>
<groupId>com.typhoon</groupId>
<artifactId>server-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
此处使用了jdk自带的动态代理。
②模拟客户端服务调用&测试
运行main方法,可以看到如下结果:
这样,我们就简单实现了rpc框架,对于上边的流程,我们做如下分析:
消费方通过上述图中描述的方式实现了对rpc服务的调用。
到这里我们实现了一个“乞丐版”的rpc框架,并且通过这个简单的流程分析,我们队rpc的原理一定有了更深刻的认识,但是真正的优秀的rpc框架绝对不止上述这些内容,回到文章开头,我们说到一款优秀的rpc框架一定会满足优秀框架所具备的标准的。就上述“乞丐版”rpc框架我们看到有以下问题:
①bio是单线程阻塞处理任务,不适合并发场景
②消费端到服务端调用时点到点的,不具备HA特性
③虽然代码和业务被拆分出来,但是服务端不可用依旧拖垮整个应用,没有熔断保护机制
④客户端到服务端单向没有一种嗅探机制,也就是说对于服务端可用性状态变更,客户端无感知,无法在一个列表中摒弃不可用服务,调用可用服务
⑤在并发场景下,无法将rpc请求调用均匀或者按照一定规则路由到rpc服务器上。如果所有consumer的rpc调用落到某一台服务器上,无法承受压力,会出现“旱的旱死涝旳涝死”现象。
此篇暂且讲到这里,下一篇我们会接着讲rpc框架,会在“乞丐版”基础上做一些优化。
原创不易,请多多支持!
附带公众号: