目录

  • SOFARPC框架
  • SOFARPC 链路追踪
  • SOFARPC 连接管理与心跳
  • SOFARPC 同步异步实现
  • SOFARPC 线程模型
  • SOFARPC 单机故障剔除
  • SOFARPC 泛化调用实现
  • SOFARPC 数据透传
  • SOFARPC 序列化

SOFARPC框架

  在蚂蚁金服的分布式技术体系下,大量的技术产品(非网关类产品),都需要在内网,进行节点间通信。BOLT 提供了优秀的通信协议与通信框架,在 BOLT 的基础上,研发了自己的 RPC 框架,提供了负载均衡流量转发链路追踪链路数据透传故障剔除等基础能力。
  RPC框架应该包含的几个部分:User、User-stub、RPC-Runtime、Server-stub、Server。当 Client 想发起一个远程调用时,实际是通过本地调用 Client-stub,而 Client-stub 负责将调用的接口、方法和参数通过约定的协议规范进行编码并通过本地的 RPC-Runtime 实例传输到远端的实例。远端 RPC-Runtime 实例收到请求后交给 Server-stub 进行解码后发起本地端调用,在 Java中可以认为就是反射调用,调用结果再返回给 Client 端。

存在几个疑问:
1.Stub 怎么出现?         ——>创建代理解决了 Stub 的问题
2.怎么打包参数?          ——>序列化和网络协议编码解决了打包的问题
3.怎么传输?               ——>Bolt,Netty 等解决了网络传输的问题
4.怎么知道目标地址?       ——>服务发现与路由寻址解决了如何知道目标地址的问题
5.怎么发布一个 RPC 服务?  ——>Registry 来解决


SOFARPC 结构设计

其中 core和 core-impl 是核心的功能,包含 API 和一些扩展机制,extension-impl 中,则包含了不同的实现和扩展,比如对 http,rest,对 metrics,以及其他注册中心的集成和扩展。如 bootstrap 中对协议的支持,remoting 中对网络传输的支持,registry 中对注册中心的支持等。

客户端调用流程

当使用方对服务进行了引用配置之后:
1.RPC 生成 Proxy,作为用户可以操作的入口。
2.向服务中心订阅这个 RPC 的地址信息。
3.使用方发起调用,经过路由,负载均衡,各类 Filter 发起调用。

服务端处理流程

在服务端看来,通过 TCP 监听端口后:
1.接到 RPC 请求后,进行解码和反序列化。
2.选择线程池,进行分发。
3.经过 Filter,进行反射调用。
4.将结果序列化,编码,进行写回。

可扩展的机制
  为了对 RPC 各个环节的都有充足的可扩展性,提供 SPI 的能力。相比原生 SPI,实现了更强大的功能:按需加载、可以有别名、可以有优先级进行排序和覆盖、可以控制是否单例、可以在某些场景下使用编码、可以指定扩展配置位置、可以排斥其他扩展点。 SPI 机制的整个流程如图所示:

在启动加载阶段,RPC 会根据对应的配置,加载需要调用方法ExtensionLoader(Class<T> interfaceClass, ExtensionLoaderListener<T> listener)逻辑如下:首先读取rpc-config-default.jsonrpc-config.json,找到扩展描述文件存放的文件夹:extension.load.path属性。找到接口类对应的扩展描述文件的文件名(默认就是接口名,也可以自己指定)。循环加载这个文件下的扩展描述文件,按行读取。(同一个接口的同一个别名对应唯一的一个实现类,可以重复,允许覆盖。)保存扩展实现类的alias和实现类的对应关系。如果 ExtensionLoaderListener 不为空,则通知 Listener。最终,将会构造出各个不同的 Filter,Invoker 等等。

SOFARPC 链路追踪

  微服务已经被广泛应用在工业界,微服务带来易于团队并行开发、独立部署、模块化管理等诸多优点。然而微服务将原单体拆分多个模块独立部署,各模块之间链接变得错综复杂,在大规模分布式系统中这种复杂链路给维护带来了诸多困难。 如果对整个微服务架构不能了然于胸,便很难理清各模块之间的调用关系。 例如修改一个服务接口,对哪些服务造成影响不能快速定位。SOFARPC 在5.4.0 以后提供了链路追踪技术,可以有效协助开发运营人员进行故障诊断、容量预估、性能瓶颈定位以及调用链路梳理。
  链路追踪技术主要是收集、存储、分析分布式系统中的调用事件数据,协助开发人员进行故障诊断、容量预估、性能瓶颈定位以及调用链路梳理。链路追踪技术包含了数据埋点、收集、存储、分析等相关技术,是一套技术体系。
  SOFARPC 作为一个基础的通讯中间件,对服务调用有很强的感知能力,容易获取链路追踪所需的服务调用信息。因此很多链路追踪系统都会选择RPC 作为埋点对象,通过对RPC中间件的埋点可以轻松做到对用户的无感知、透明化。

SOFARPC 连接管理与心跳

  在 RPC 调用过程中,我们经常会和多个服务端进行远程调用,如果在每次调用的时候,都进行 TCP 连接,会对 RPC 的性能有比较大的影响,因此,实际的场景中,我们经常要对连接进行管理和保持。SOFARPC 应用心跳包以及断线重连实现,结合系统 tcp-keepalive 机制,来实现对 RPC 连接的管理和保持。
TCP keep-alive
  tcp-keepalive 机制可以在连接无活动一段时间后,发送一个空 ack,使 TCP 连接不会被防火墙关闭。tcp_keepalive_time,在 TCP 保活打开的情况下,最后一次数据交换到 TCP 发送第一个保活探测包的间隔,即允许的持续空闲时长,或者说每次正常发送心跳的周期,默认值为 7200s(2h)。 tcp_keepalive_probes 在 tcp_keepalive_time 之后,没有接收到对方确认,继续发送保活探测包次数,默认值为 9(次)。 tcp_keepalive_intvl,在 tcp_keepalive_time 之后,没有接收到对方确认,继续发送保活探测包的发送频率,默认值为 75s。

SOFABolt 基于系统 tcp-keepalive 机制实现;SOFABolt 基于 Netty IdleStateHandler 心跳实现。

SOFARPC 连接管理断开重连实现
连接管理是客户端的逻辑,启动好,连接管理开启异步线程。

  其中,SOFARPC 连接管理 ConnectionHolder 维护存活的客户端列表healthConnections 和失败待重试的客户端列表 retryConnections,RPC 启动守护线程以默认 10 秒的间隔检查存活和失败待重试的客户端列表的可用连接:
1、检查存活的客户端列表 healthConnections 是否可用,如果存活列表里连接已经不可用则需要放到待重试列表 retryConnections 里面;
2、遍历失败待重试的客户端列表 retryConnections,如果连接命中重连周期则进行重连,重连成功放到存活列表 healthConnections 里面,如果待重试连接多次重连失败则直接丢弃。

SOFARPC 同步异步实现

  SOFARPC 以基于 Netty 实现的网络通信框架 SOFABolt 用作远程通信框架,使用者不用关心如何实现私有协议的细节,直接使用内置 RPC 通信协议,启动客户端与服务端,同时注册用户请求处理器即可完成远程调用:SOFARPC 服务调用提供同步 Sync、异步 Future、回调 Callback 以及单向 Oneway 四种调用类型。

【1】Sync 同步调用
  支持方法级别,接口级别的超时设置。同步调用是指的客户端发起调用后,当前线程会被阻塞,直到等待服务端返回结果或者出现了超时异常,再进行后续的操作

【2】Future 异步调用
  客户端发起调用后不会同步等待服务端的结果,而是获取到 RPC框架给到的一个Future 对象,调用过程不会阻塞线程,然后继续执行后面的业务逻辑。服务端返回响应结果被 RPC 缓存,当客户端需要响应结果的时候需要主动获取结果,获取结果的过程阻塞线程。

【3】Callback 回调调用
  客户端提前设置回调实现类,在发起调用后不会等待结果,但是注意此时是通过上下文或者其他方式向 RPC 框架注册了一个 Callback 对象,结果处理是在新的线程里执行。RPC在获取到服务端的结果后会自动执行该回调实现。

【4】Oneway 单向调用
客户端发送请求后不会等待服务端返回的结果,并且会忽略服务端的处理结果

SOFARPC 线程模型

I/O模型 JAVA NIO 和多路复用结合起来就是是最简单的 Reactor 模式:注册所有感兴趣的事件处理器,单线程轮询选择就绪事件,执行事件处理器。

Reactor 线程模型
Reactor 中定义了三个角色:

而一个标准的操作流程则是:步骤1:等待事件到来(Reactor 负责);步骤2:将读就绪事件分发给用户定义的处理器(Reactor 负责);步骤3:读数据(用户处理器负责);步骤4:处理数据(用户处理器负责)。在这个标准之下,Reactor 有几种演进模式:单线程模型、多线程模型、主从多线程模型。主从多线程模型是目前大部分 RPC 框架,或者服务端处理的主要选择。Reactor 主从多线程模型的特点:服务端用于接收客户端连接的不再是个1个单独的 NIO 线程,而是一个独立的 NIO 线程池。

主要的工作流程:
1、MainReactor 将连接事件分发给 Acceptor
2、Acceptor 接收到客户端 TCP 连接请求处理完成后(可能包含接入认证,黑名单等),将新创建的 SocketChannel 注册到 IO 线程池(sub reactor线程池)的某个 IO 线程上,Acceptor 线程池仅仅只用于客户端的登陆、握手和安全认证。
3、SubReactor 负责 SocketChannel 的读写和编解码工作。其 IO 线程负责后续的 IO 操作。

  对于 SOFARPC 来说,和底层的 SOFABolt 一起,在使用 Netty 的 Reactor 主从模型的基础上,支持业务线程池的选择。

SOFARPC 单机故障剔除

  SOFARPC 提供了自动单机故障剔除能力,能够自动监控 RPC 调用的情况,对故障节点进行权重降级,并在节点恢复健康时进行权重恢复,提高系统可用性。
  在分布式架构中常见可用性方案的是 集群(冗余),即将一个服务部署在多个机器上,通过硬负载或软负载实现服务的均衡负载。硬件负载因每次请求都需要经过硬件负载,承担所有的访问压力,当集群规模增加、流量增多,硬件负载可能因无法支撑所有流量而导致系统不可用。软负载则提供注册中心,并将负载能力转移到服务调用方( Consumer ),注册中心只有在 Consumer 首次订阅或服务发生变化时才会发生交互,避免了并发访问下的单点问题。虽然软负载可以避免单点问题,但可能存在以下场景导致服务不可用:
1、Provider 出现单点故障或宕机,与 Consumer 的长连接已断开,但注册中心尚未摘除或未及时通知Consumer。
2、Consumer 和 Provider的长连接还在,注册中心未下发摘除,但服务器端由于某些原因,例如长时间的 Full GC, 硬件故障(后文中为避免重复,统一描述为机器假死)等场景,处于假死状态。

这两种场景都是服务端出现故障,但由于长连接还保留等原因注册中心未摘除服务,导致服务调用失败。针对第一种情况 Consumer 不应调用出现故障的 Provider,否则会引起部分服务不可用;针对第二种情况,这个 Consumer 应该不调用或少调用该Provider,可以通过权重的方式来进行控制。目前 SOFARPC 5.3.0 以上的版本支持RPC 单机故障剔除能力。SOFARPC 通过服务权重控制方式来减少异常服务的调用,将更多流量打到正常服务机器上,提高服务可用性。

SOFARPC故障剔除 vs 注册中心故障剔除
  SOFARPC 的故障剔除与注册中心故障服务剔除不同,它们从不同的维度来完成故障剔除提高服务可用性。主要两方面的区别:故障剔除的时机、故障剔除的细粒度。
  故障剔除的时机:SOFARPC 的故障剔除与注册中心故障服务剔除不同,它们从不同的维度来完成故障剔除提高服务可用性。注册中心服务管理关注 Provider 与注册中心的心跳或长连接。如果 Provider 出现心跳异常或长连接不存在,则及时将服务从注册中心剔除,并告知 Consumer 移除本地缓存的故障 Provider 信息。Comsumer 在负载均衡选择时则不考虑被剔除的 Provider。而 SOFARPC 单机故障剔除针对的场景不同,针对的是注册中心还未剔除的服务,这些服务与 Consumer 仍然保持长连接,但由于机器假死,不能提供正常服务。
  故障剔除的细粒度:注册中心剔除的是粒度是针对单机上的某个服务进程,属于进程级别。一旦这个进程和注册中心断开连接或心跳无感应,则将其从注册中心剔除。SOFARPC 故障剔除并控制精度会更精细一些,会细致到进程对外暴露的服务。

服务权重降级 vs 服务降级
  服务降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。这里的降级级别是整个系统服务,而不是针对接口级别。
  SOFARPC 的服务降级,是指当某些个别机器因为存在机器假死,导致处于假死状态,导致一些服务接口响应异常,通过 SOFARPC 的故障剔除和服务权重降级来减少对这些异常机器接口的访问,而将更多的流量打到正常的机器上。 这里针对的维度主要还是 IP + 服务维度,如部署在 xxx 机器上交易系统对外提供的 TransQueryService 服务。

  通常一个服务有多个服务提供者,其中部分提供者可能由于机器假死等导致长连接还存活但是程序已经无法正常响应 。 故障剔除功能会将这部分异常的服务提供者进行降级,使得客户端的请求更多地指向健康节点。当异常节点的表现正常后,故障剔除功能会对该节点进行恢复,使得客户端请求逐渐将流量分发到该节点。
  SOFARPC 单机故障剔除模块是 FaultToleranceModule, 通过SOFARPC 的 SPI 机制完成模块的自动化加载,以完成该功能的插入。 FaultToleranceModule 模块包含了两个重要部分:
1、subscriber 事件订阅器 。 通过订阅事件总线 EventBus 的事件,以零侵入方式完成 RPC 调用的统计和信息收集。
2、regulator 调节器 。 根据收集的 RPC 调用信息,完成服务调用或服务权重的调节,达到服务降级和服务恢复的目的。内置了信息收集器、计算策略、度量策略、恢复策略, 是单机故障剔除的核心实现。

FaultToleranceModule 主要关心两种调用事件:
1、同步结果事件: ClientSyncReceiveEvent, 收集和统计 RPC 同步 调用次数和出现异常的次数。
2、异步结果事件: ClientAsyncReceiveEvent,收集和统计 RPC 异步 调用次数和出现异常的次数。

如图所示是整个 SOFARPC 故障自动剔除功能的整体结构:

整体流程如下:
1、在 RPC 同步或异步调用完成后会向事件总线 EventBus 发送对应事件。
2、FaultToleranceModule 的订阅者收到对应事件,开始进行调用统计,将统计结果存储到 信息收集器中。并在第一次存储时触发 Measure 定时任务。
3、Measure 定时任务会在指定窗口时间定时执行。获取信息收集器的所有信息并交给 度量策略 做度量计算,并开启计算线程负责进行计算和服务调节。
4、计算线程首先会 调用 计算策略,计算策略根据 度量策略的计算结果判断是否执行降级或恢复。
5、如果进行降级,则调用降级策略执行降级操作,如打印日志或降低故障服务权重。
6、如果进行恢复,则调用恢复策略执行恢复操作,如打印日志或恢复故障服务权重。
7、最后在 RPC 调用的时候,负载均衡器(默认是 random + weight 负载均衡)会根据根据权重来选择服务。权重越低的服务被调用概率越小,流量流入更少;权重越大的服务,被调用概率越大,流量流入增多。

SOFARPC 泛化调用实现

  使用泛化调用,将相应的请求包装成泛化调用,就能够实现不依赖接口 jar 包,多语言调用 RPC 服务,避免重复开发。泛化调用的关键就是对象表示和序列化,SOFARPC 提供了 GenericObject 等对象来表示参数对象或者返回值对象,而将GenericObject 对象序列化成目标对象,或者将返回值反序列化成 GenericObject 对象,是 SOFARPC 实现泛化的关键。如图所示为SOFARPC 泛化调用的流程图:

1.泛化 API 调用时,会加载泛化过滤器,作用是做一些参数转换,同时设置序列化工厂类型。
2.SOFARPC 在使用 SOFABolt 进行网络调用前,会创建 context 上下文并传递给 SOFABolt,上下文中包含着序列化工厂类型信息,这个信息将决定使用何种序列化器,同时这个上下文将流转于整个调用期间。
3.在 SOFABolt 正式发送数据之前,会将 GenericObject 对象序列化成普通对象的字节流,这样,服务提供方就不必关心是否为泛化调用,从图中可见,提供方不用对泛化调用做任何改变 —— 这是 SOFARPC 泛化区别于其他 RPC 泛化的关键。
4.当提供方成功接收请求后,使用普通序列化器即可反序列化数据,只需要正常调用并返回即可。
5.当消费者的 SOFABolt 接收到响应数据后,便根据 context 的序列化类型,对返回值做反序列化,即将普通的字节流反序列化成 GenericObject 对象 —— 因为客户端有可能不知道返回值的 Class 类型。
6.最终,泛化 API 即可得到 GenericObject 类型的返回值。

  相比较其他 RPC 框架两端都需要对泛化进行支持,SOFARPC 显得要友好的多。服务端无需感知是否泛化,一切都是由客户端进行处理。带来的好处是:应用如果想要支持泛化,不需要改动服务端,只需要修改客户端即可。这是和其他 RPC 框架泛化调用最大的区别。
  实现方式:通过SOFA-Hessian 序列化支持泛化序列化,在进行泛化调用时,bolt 会根据上下文的序列化标记来使用对应的序列化器,SOFA-Hessian 特有的泛化序列化器可将 GenericObject 对象序列化成目标对象的字节流,服务端按正常反序列化即可。SOFA-Hessian 特有的泛化反序列化器也可将目标返回值反序列化成 GenericObject 等对象。

SOFARPC 数据透传

  在 RPC调用中,数据的传递,是通过接口方法参数来传递的,需要接口方定义好一些参数允许传递才可以,在一些场景下,我们希望,能够更通用的传递一些参数,比如一些标识性的信息。业务方可能希望,在每一次调用请求中都能够传递一些自定义的信息到下游。甚至也希望下游能够将一些数据传递回来。
  而数据透传功能,就是指数据不需要以作为方法参数的形式在调用链路中进行传递,而是直接存储到调用上下文中,之后通过 RPC 的内置对象,进行传递,调用双端可从上下文中获取数据而不需要去关注数据的传输过程。
  SOFARPC 提供的数据透传支持请求数据透传(客户端向服务端)和响应数据透传(服务端向客户端)。

1、用户通过 SOFARPC 提供的 API 进行数据传递设置
2、SOFARPC 在调用传输前,将透传的数据进行打包获取
3、进行正常的序列化和反序列化
4、SOFARPC 在反序列化时将用户设置的透传数据写回 Context
5、服务端用户即可进行获取使用

SOFARPC 序列化

  RPC 调用通过网络传输相关的调用方法及参数,在这个网络传输过程中,内存中的对象是无法直接传输的,只有二进制字节才能在网络上传输。而为了实现调用对象在网络上的传输,必须通过序列化实现对象 -> 字节的过程,以及反序列化实现字节 -> 对象的过程。在网络协议模型中,序列化属于应用层协议的一部分。SOFARPC 支持的序列化协议有:SOFA-Hessian、Protobuf、Json。

Alibaba(实习准备)—SOFARPC学习总结相关推荐

  1. sofa-rpc 学习总结

    sofa-rpc 学习总结 如下是client调用流程图: client调用样例代码: @Testpublic void testHelloSyncService() {// 指定注册中心Regist ...

  2. 远程实习第一周学习总结

    远程实习第一周学习总结 本周的主要学习内容内容如下: 1.掌握AndroidStudio,项目结构以及SDK 2.掌握Git以及项目忽略表 3.熟悉Android 设计规范:Material Desi ...

  3. 远程实习-第二周学习报告

    远程实习-第二周学习报告 本次为远程实习的第二周学习总结报告,以下是本周的任务目标: 熟悉使用Android四大组件和Fragment 熟悉常用View控件,support包新控件 1. Androi ...

  4. 春招收获阿里腾讯实习offer,学习、面试经验分享

    先说一下自己的情况,本人今年大四,双非一本学校,计算机相关专业,从大一开始加入学院创业团队的 Android 开发组. 去年过年后不久开始投简历,前后投了腾讯.阿里.美团.CVTE 这几家公司,拿到了 ...

  5. 【学习路线】2022届校招C++后端服务器开发/实习,个人学习路线总结/记录

    2022届秋招学习路线/计划 学习目标:2022届(2021年)秋招面试 1 编程语言(C++)篇 2 计算机网络篇 3 计算机操作系统篇 4 数据结构及算法 5 数据库 6 工程实践篇 7 其他/项 ...

  6. SpringCloud(H版以及Alibaba版本)的学习笔记(三)

    本笔记学习自B站尚硅谷Springcloud时所记录 学习视频链接 源码地址[码云] 笔记内容包括了:Springcloud的H版以及Alibaba版本 H版具体内容包括:Eureka.Zookeep ...

  7. unity实习生简历_实习生与Unity学习

    unity实习生简历 Working with video games doesn't sound like a terrible idea, does it? Expressing your cre ...

  8. 尚硅谷2020最新版周阳SpringCloud(H版alibaba)框架开发教程 学习笔记

    前言:今天看到周阳老师出了新课,十分欣喜,很喜欢周阳老师的讲课风格,内容也充实,我也算是周阳老师忠实粉丝啦. 新出的springcloud第二版很符合我现阶段的学习需求.但美中不足的是,目前只有视频资 ...

  9. 实习or在校学习or签约or考公务员or……

    转眼,大学四年马上就要结束了.有的同学已经在开始找工作,并且有的已经签约了不错的公司.我也去面试了3家公司,有2家抛来了橄榄这.但是还是很纠结. 对于生活在西部地区,云娜昆明,虽然这几年发展的还是很快 ...

  10. 实习之前及实习时的学习计划

    最近的一系列面试颇让人感到劳累,也了解到许多不足,深感在程序员的道路上还有更多需要去了解,需要去理解的知识. 而一味的去面试笔试,充实自己的曲线也趋向平滑,实则帮助不大. 近日10.26,感慨于时间的 ...

最新文章

  1. java 导出pdf_一次java导出pdf的经历
  2. SharedPreferences的使用
  3. if (argc == 1) 到底有什么作用?
  4. vim选中字符复制/剪切/粘贴
  5. 将系统默认记事本替换成自己喜欢的文本编辑器
  6. 分享一个数据产品经理的PRD
  7. 判断sem信号量为零_kernel.sem信号量调优
  8. 问题:Cannot assign a device for operation Variable
  9. python-Pandas库
  10. Tortoiser三十集脱壳教程__ZC
  11. python3 extract_model.py对应代码解读抽取式提取+生成式提取摘要代码解读------摘要代码解读3
  12. error in opening zip file
  13. FedEx v20.0.7654的CData驱动程序
  14. 大数据面试重点之kafka(七)
  15. 呼叫中心系统的基本构成和二次开发思路
  16. 【运筹学】对偶理论 : 对偶性质 ( 对称性质 | 对称性质推导 )
  17. Unity中替换模型的方法
  18. 02高级语言及其语法描述
  19. 用matlab模拟机械运动
  20. 打造人民的5G:展锐第二代5G芯片平台实现客户产品量产

热门文章

  1. 键盘怎么按出计算机,怎么在电脑键盘上打出艾特@键? 原来是这样的
  2. Java项目:jsp+servlet网上会议室预约系统
  3. 计算机术语一种单向密码体制,密码体制有哪五部分
  4. curl encode
  5. python格式化百分比输出,如何将浮点数输出为百分数,不需要额外代码的简便方法
  6. 使用Tale搭建个人博客网站(基于java)
  7. 临床数据库挖掘系列3-手把手教你使用R语言对seer数据库清洗
  8. 服务器防火墙如何开放端口?常见的服务器端口有哪些?
  9. 女生学计算机专业好吗_百度文库,没考上高中的女生学什么最好
  10. 搜狗主动推送python脚本(自动登录免验证码)