RPC设计概要

前言

RPC全程远程方法调用,已经在各大小公司被普遍使用,种类也是不少好比:Dubbo,Spring cloud那一套,GRPC,Thrift,可能还有不少公司自研的等等;每一个公司均可能根据本身的业务需求,场景选择本身合适的RPC框架;但大致的考察维度无非就这么几个:性能,可扩展性,跨平台,功能性,可监控,使用性;因此咱们若是要设计一个RPC框架,能够从这几个角度去考虑。面试

性能

做为微服务中的核心组件,在一个系统中RPC的调用量每每是很高的,因此性能是一个很重要的考虑点;既然是远程调用,必然牵扯到网络链接,而I/O模型的选择直接影响到性能,网络的长链接短链接,序列化方式也都影响性能;算法

1.I/O模型

常见的Unix5种I/O模型分别是:阻塞I/O,非阻塞I/O,I/O复用(select,poll,epoll等支持I/O多路复用),信号驱动I/O,异步I/O;从早期的阻塞I/O方式只能建立大量的线程来保证每一个用户互不影响,到如今普遍使用的I/O多路复用模型,再到异步I/O;从select模型到如今主流的epoll模型,性能有了质的升级;固然咱们不必本身去实现,能够直接使用网络通信框架Netty,Mina等;数据库

2.长链接短链接

短链接表示每次通信完就关闭链接,而长链接通信完继续保持链接,这样下次再通信就不须要从新创建链接了,若是通信频繁,很明显长链接性能更高;可是长链接须要作一些额外的工做,好比保活处理;另外就是若是客户端太多的话,服务器端是没法支撑的。编程

3.序列化方式

网络传输中的数据都须要通过序列化和反序列化处理,因此这一块的性能也很重要;常见的序列化包括:json和二进制方式,json常见的如fastjson,jackson等,二进制如protobuf,thrift ,kryo等;这个能够分别从序列化的性能,大小,以及使用方便性考虑;固然稳定性和安全性也须要考虑,好比fastjson频繁爆出安全漏洞;json

4.协议

这里主要讲的是应用层协议,RPC通常都会自定义协议,固然也有直接使用现有协议的好比http协议;自定义协议能够本身掌控,协议能够作的很小很精简,固然解码和编码须要本身去实现;若是使用现有的http协议,相对来讲整个协议包是比较大的,可是已是一种规范了,不少东西能够直接拿来用,更加通用;缓存

可扩展性

可扩展性能够从两个角度来看,一个是服务提供方和消费方的负载均衡策略;另外一个就是用户能够对框架进行自定义扩展;安全

1.负载均衡

RPC的两个核心组件服务提供方和消费方,须要提供横向扩展的机制,用以达到更高的负责,好比Spring Cloud、Dubbo提供的注册中心,而后再结合容错机制达到负载均衡的效果,很容易达到横向扩展;服务器

2.SPI机制

一个好的框架是支持用户自定义的,用户根据本身的需求实现自定义扩展;JDK提供了SPI机制,很常见的一个场景就是数据库驱动;另外Dubbo在此基础上提供了更增强大的SPI机制;这种扩展对RPC来讲是多方面的,能够是底层的通信框架扩展,序列化扩展,注册中心扩展,容错机制扩展,协议扩展等等;微信

跨平台

如今开发语言多种多样,若是能作成跨平台,固然是一大优点,可是可能每每为了跨平台,会在一些地方作权衡让步,固然难度也更大;因此咱们在实现一个RPC时须要明确本身的定位,就是针对某一种语言的仍是跨平台支持;常见的支持跨平台的RPC框架如GRPC,Thrift;
实现机制能够参考一下,都有本身的一套接口定义语言IDL而后经过不一样的代码生成器,生成各类编程语言消费端和服务器端代码,来保证不一样语言直接的相关通讯。网络

功能性

做为一个RPC框架,除了最核心的通讯模块,序列化模块以外,功能性模块也很重要,每每为开发者节省了大量的时间,开发者可能由于RPC的某个功能而选择用此框架;常见的功能包括:容错机制,负载均衡机制,同步异步调用,结果缓存,路由规则,服务降级,多版本,线程模型等;

1.容错机制

在错综复杂的网络环境中,远程调用失败再正常不过了,容错机制就显得很是有必要了,常见的容错机制好比:失败重试,快速失败,失败直接忽略,并行调用多个服务器只要一个成功即返回等;用户能够根据需求选择本身合适的容错方案;

2.负责均衡

上面提到服务提供方和消费方的可扩展性,消费方面对多个提供方的时候须要有必定的负载均衡策略,来保证系统的稳定性;常见的策略如:随机,轮询,最少活跃调用数,一致性hash等;

3.同步异步调用

常见的同步调用有些场景没法知足需求,好比同时须要调用多个远程方法,而这其中可能有些执行比较慢的;这时候异步调用就显得重要了,能够同时异步发送多个请求,等待时间就是响应最慢的请求;具体能够经过Future,CompletableFuture来实现;

4.结果缓存

缓存一直是性能的不二法宝,某些场景下可能对服务提供方响应的数据实时要求性并不高,这时候若是能够在服务提供端提供结果的缓存机制,那么在性能上是一个很大的提高;能够本身设计一个本地缓存,固然也能够直接整合第三方缓存框架好比ehcache,jcache等;

5.路由规则

服务提供方每每是不少的,用户可能有一些特殊的需求,能够按照本身定义个规则来作路由,好比咱们常常作的灰度发布,结合RPC提供的路由规则来实现会很简单;此规则多是条件表达式,脚本,标签等,咱们设计的RPC框架须要有一个给用户定义规则的地方,好比经过注册中心来实时推送,另外还须要相关的引擎来处理规则,好比脚本引擎;

6.服务降级

系统的高可用性原则中,很重要的一条就是降级处理,在一些非核心的功能中,能够在出现超时/故障时或者直接设置为降级服务,给一个统一的响应,这样能够把宝贵的资源留给那些核心的功能;能够参考Dubbo的实现,向注册中心写入动态配置覆盖规则,从而实现实时降级处理;

7.多版本

接口升级时常有的事情,咱们可能会为了兼容以前的版本绞尽脑汁,但有时候仍是无能为力,这时候多版本就显得很重要了,可让两个版本同时存在,等到合适的机会在慢慢升级;像dubbo这种服务的维度就是服务名+版本号,因此很好实现多版本;而Spring Cloud维度没有到版本号,能够经过路由规则去实现;

8.线程模型

在系统的高可用原则中,线程隔离是一条重要的原则,为何要作隔离,能够拿Dubbo及其底层通讯框架netty为例,netty做为通讯框架自己是有本身的线程模型,若是业务处理线程直接使用底层的通讯线程模型,这样就会出现由于业务阻塞而致使通讯线程模型阻塞;这时Dubbo提供本身的线程模型就尤其重要,能够作到线程隔离,业务线程不影响通讯线程;

固然做为一个RPC框架实现的功能能够不少,这里主要讲一些咱们日常用的比较多的功能;

可监控

一个运行稳定的系统,没有一个专门的监控平台是不行的,固然RPC也不例外,常见的好比dubbo的monitor模块,Spring Cloud Admin等;对于一个RPC咱们主要监控:服务提供者有哪些,服务消费者有哪些,以及它们的状态,最好还有一些统计功能好比一段时间内的调用量,成功率,失败率,平均响应时间,最大响应时间,最大并发量等等;

使用性

最后说一下,咱们设计出来的框架最终仍是要给用户使用的,因此用户是否能够方便的使用也是一个很重要的点,某些框架可能就是由于使用繁琐致使最终被弃用;好比注解的方式相比较xml的方式就简单很多;还有好比服务维度来讲:dubbo维度是接口,而Spring cloud维度是应用,总体来看Spring cloud使用起来更加方便;固然简单的API,文档以及Demo对开发者来讲也是必不可少的;

总结

RPC本质上其实就是一次网络调用,不少设计其实都是在围绕,如何把它变成一个高可用,高并发的框架;其实这些设计理论适用于大部分的系统,都在为达到此目标而努力。

感谢关注

能够关注微信公众号「 回滚吧代码」,第一时间阅读,文章持续更新;专一Java源码、架构、算法和面试。
相关文章
相关标签/搜索