微服务架构之 —— RPC框架
RPC简介RPC是什么Remote Procedure Call,远程过程调用。首先来说本地方法调用,假设在main方法中调用一个本地的方法multiply(同一个进程内的方法调用)。无非是做了内存寻址和一些堆栈操作。而假设main方法和multiply方法不在同一个进程中,两者则通过RPC的方式进行调用(通信)。由于是跨网络通信,需要考虑将方法调用和参数,如何变成网络上可传输的二进制流(涉及到参
RPC简介
-
RPC是什么
Remote Procedure Call,远程过程调用。
首先来说本地方法调用,假设在main方法中调用一个本地的方法multiply(同一个进程内的方法调用)。无非是做了内存寻址和一些堆栈操作。
而假设main方法和multiply方法不在同一个进程中,两者则通过RPC的方式进行调用(通信)。由于是跨网络通信,需要考虑将方法调用和参数,如何变成网络上可传输的二进制流(涉及到参数和结果的序列化,反序列化,socket网络编程等细节)。而这就是RPC框架的意义,它帮助开发人员,屏蔽了网络编程和网络传输的细节,让开发人员像调用本地方法一样,调用远程方法。
需要注意,RPC并不是一种具体的技术框架,而是一种技术思想。
广义上讲,任何通过网络,远程调用另一个进程中的方法的技术,都可以称为RPC。
RPC并不是一个新的概念,也不是和微服务同一个时代的概念。
在微服务之前,就有很多可以称之为RPC的技术理念。比如RMI,WebService。
-
RMI
Remote Method Invocation。比较古老。是EJB的通信基础,是实现RPC的一套Java Api,依赖JVM,所以仅支持Java应用之间的方法调用,不能实现跨语言调用。
-
WebService
跨语言,跨平台。因为WebService底层依赖的是HTTP和XML,这两者都是语言无关的。
-
-
RPC有哪些具体的例子
随着时代的发展,越来越多优秀的RPC框架进入我们的视野,如
- gRPC:谷歌开源的高性能RPC框架。基于HTTP2协议,以protobuf作为序列化协议。使得其具有很好的跨平台特性。
- dubbo:阿里开源的RPC框架,已捐赠给Apache
- Finagle:twitter的RPC框架
- Thrift:Facebook的RPC框架
- Tars:腾讯的RPC框架
-
引入RPC后会给项目带来什么
当我们引入RPC框架,并对整体系统进行了微服务化的拆分。会导致:
-
提升系统的扩展性(优点)
-
提升了系统的可维护性(优点)
-
系统变得复杂(缺点)
引入新的组件,导致在调试代码,维护系统时会变得更加复杂
-
跨网络调用可能会增加性能开销(缺点)
所以,引入RPC框架对系统进行微服务化的拆分时,一定要综合扩展性,维护性,复杂度,成本,性能等多方面的考虑。需要慎之又慎。
-
RPC基本原理
RPC主要是为了解决服务的远程调用问题,即客户端和服务器之间的通信问题。当设计一款RPC框架时,主要有如下几个方面需要考虑
- 通信协议
- 序列化
- IO模型
RPC调用的通信过程是怎样的?
- 首先,客户端和服务端需要约定一种通信协议,按照此种协议来组织数据
- 在组装数据时,需要将数据序列化为二进制流,以便在网络上进行传输
- 随后,客户端组织好方法名和参数等数据,将二进制流通过网络进行发送
- 服务端接收到数据后,按照通信协议解析数据,并把二进制流反序列化为方法名和参数
- 服务端执行业务逻辑,得到结果后,将结果以同样的方式,返回给客户端
这样就完成了一次RPC通信
通信协议
需要注意处理TCP粘包的问题。解决方案通常有
- 发送和接收定长的数据(会浪费网络带宽)
- 在数据包中额外携带长度信息(需要一个固定的空间来传输长度信息)
- 使用特定的magic number作为数据的分界(无法判断某个数据包是否传输完)
通常使用第2种方式,或者第2和第3种结合的方式,来设计通信协议。
序列化
序列化,是将数据和二进制流进行相互转换的方式。
每次RPC调用,都会涉及到2次序列化和2次反序列化的过程(共4次)。
所以,选择序列化方式时需要注意,要避免让序列化成为整个RPC通信的性能瓶颈。在选择序列化方式时,需要关注:
-
性能
(反)序列化执行的耗时
-
序列化后的包的大小
因为网络带宽是一定的,选择压缩比较高的序列化方式,可以减少高并发下RPC通信对带宽的占用
-
可读性
类似json,xml,是可读性较强的序列化方式,它们序列化后的结果都是文本。良好的可读性,主要是便于调试和问题排查。
需要在这3者之间做取舍和权衡。
常见的序列化方式
- java serializable(不能跨语言)
- json,xml(可读性较好,通用性高,但体积较大)
- hessian,protobuf,thrift(二进制的序列化,性能高,序列化后的包体积小)
IO模型
常见的IO模型,如下
- 阻塞IO
- 非阻塞IO
- 多路复用IO(对应Java的NIO)
- 信号驱动IO
- 异步IO(Java的AIO)
通常使用较多的是多路复用IO。异步IO还不够成熟
服务治理
目前业界开源的RPC框架中,更多的都是属于服务框架,而不是单纯的RPC框架。
服务框架和RPC框架的区别在于:RPC框架只是简单的解决通信问题,而服务框架,除了解决通信问题,还需要解决服务管理的问题。
所以我们需要了解,服务治理需要解决什么问题,以及它是如何解决的。
服务治理有哪些方面?
- 服务注册与发现
- 服务追踪(分布式追踪)
- 配置管理
- 服务熔断,降级,分流
- 服务负载均衡
- 服务监控
注册中心
过程
- 服务启动时向注册中心注册服务节点地址
- 客户端从注册中心获取服务的地址列表
- 有新的服务注册上来后,客户端可以得到通知
- 有服务出现故障或者关闭时,客户端也可以得到通知
- 服务节点间隔固定时间向注册中心发送心跳,表明健康状况
优点
- 客户端无需重启就能感知服务节点的动态变化
- 可以通过为服务节点增加权重,来辅助负载均衡
选型
-
分布式一致性协调系统
zookeeper,etcd,consul
可以当作注册中心使用,但可能功能不是很齐全,比如无法对服务做健康检测
-
开源的,专门的注册中心
nacos(阿里开源),eureka(springCloud),vintage(微博使用)
功能比较完善
服务追踪
分布式追踪系统,主要是用于解决分布式环境下的问题排查的问题。
当我们把一个系统,拆成多个微服务之后,一次来自客户端的请求,可能会引发微服务之间的十几次,甚至几十次请求,才能得到最终的结果。
比如系统的响应时间变慢了,或者系统出了一些问题,那么我们需要知道是具体哪个微服务导致的,这就需要对整个调用链进行追踪。
分布式追踪的基本原理是:
-
一次来自客户端的调用,对应一个唯一的traceId,用这个traceId来标识整个完整的调用链路
-
用另外一个spanId来标识一次微服务的调用。通过spanId来标识微服务之间的层级关系。
比如微服务A被调用,产生一个spanId为2,A又调用了另外2个微服务B和C,产生的spanId分别为2.1和2.2。这样就能清晰的知道微服务之间调用的层级关系
-
对这些调用日志进行收集,进行简单的聚合操作后, 写入到NoSQL数据库中
-
使用traceId就可以从NoSQL数据库中跟踪整个请求的链路,并得到各个链路的耗时
注意:由于一次客户端调用会导致很多次的微服务之间的调用,所以调用日志的量是巨大的。我们可以在收集调用日志后,进行一些简单的聚合操作,来减少日志量,或者通过采样的方式,只采样1%的调用日志。
配置管理
项目所使用的一些配置文件的管理。
将配置做成文件,这样是静态的配置。将配置放到一个服务上,这样可以实现动态的配置管理和更新。
配置主要分为两种:
- 静态配置:比较固定的,不会经常发生变动的配置。比如数据库地址
- 动态配置之:可能会经常发生变动的配置。比如超时时间。
静态配置通常放在项目的配置文件中即可,而动态的配置则通常放到配置服务中。
选型
- zookeeper,etcd,consul
- apollo(携程),diamond(淘宝),disconf(百度),都是以mysql为存储
- vintage(微博),以redis为存储
服务容错
一个系统拆成了多个服务。原本只有1个可能出现问题的点,现在变成了多个。
当系统出现未知问题,或者系统流量超出极限时,要如何应对?常见方式如下
- 熔断:当下游服务不可用时,暂时屏蔽下游服务,以保障整体服务可用的方法
- 降级:当流量激增时,对于某些页面或者服务,暂时屏蔽,以减轻服务器压力的方法
- 限流:限制瞬时大流量以保护整体服务的方法
选型
- hystrix
- sentinel(阿里)
- dubbo
负载均衡
为了应对大流量,通常对于一个服务会部署多台节点。那么此时就需要将流量分配到多个服务节点。
常见负载均衡算法
- 一致性哈希
- 随机
- 轮询(加权轮询)
- 最少连接(选择当前连接数最少的节点)
服务监控
从运维上对服务进行监控。
通常关注2个方面:需要监控什么?怎么监控?
服务监控的指标:
- 请求量:接口请求量,缓存请求量,数据库请求量
- 响应时间:接口响应时间,缓存响应时间
- 错误率:调用第三方服务错误率
监控系统构成
- 数据采集:flume,filebeat
- 数据处理:storm,spark
- 数据存储:mysql,hbase,influxDB
- 数据展示:grafana
RPC实例分析
以dubbo为例,进行分析
- dubbo的微内核架构是如何设计的
- dubbo是如何调用服务的
- dubbo内嵌的服务治理策略是怎样的
dubbo介绍
- dubbot是一款高性能的服务框架
- 在2021年由阿里开源
- 2018年,阿里将dubbo捐赠给Apache
- 借鉴dubbo的RPC框架还有dubbox(当当),motan(微博)
dubbo架构特点
- 微内核+扩展点架构
- 微内核负责组装扩展点,实现整体逻辑
- 扩展点可以让功能点被用户自定义实现
dubbo的扩展点是通过SPI(Service Provider Interface)机制实现的(借鉴了JDK的SPI机制)。dubbo会从以下目录加载实现类
META-INF/services/*
META-INF/dubbo/*
META-INF/dubbo/internal/*
格式:key=实现类的全限定名
在代码中即可通过这个key
来加载某个接口的某个特定的实现类
dubbo的服务调用
略
更多推荐
所有评论(0)