RPC框架实现 - 容灾篇 - bangerlee

标签: rpc 框架 bangerlee | 发表时间:2015-04-28 23:36 | 作者:bangerlee
出处:

RPC(Remote Procedure Call,远程过程调用)框架是分布式服务的基石,实现RPC框架需要考虑方方面面。其对业务隐藏了底层通信过程(TCP/UDP、打包/解包、序列化/反序列化),使上层专注于功能实现;框架层面,提供各类可选架构(多进程/多线程/协程);应对设备故障(高负载/死机)、网络故障(拥塞/网络分化),提供相应容灾措施。

 

分布式服务后台Server通常基于普通的x86_64服务器,单机设备故障是常态,同时网络也不能确保100%服务可用,交换机重启引起下联设备断连,流量挤占导致链路拥塞,甚至整个机房通信 光缆断开都有一定概率发生, RPC框架在实现时需要考虑以上情况,在框架层面具备容灾措施。

 

超时与重试

大家知道,RPC调用结果分成功、失败、超时三种状态,其中调用失败的一般原因是Server设备故障(connect失败,我们又称这类调用失败为系统失败),这时Client可以通过挑选其他Server,进行请求重试。超时的原因可能有多种,如网络拥塞、所选Server设备过载等,Client也可以通过重试尽量让请求得到处理。超时和重试的配置形式如下:

[ClientTimeout]
ConnRetryCount = 3
ConnTimeoutMS = 50
SockTimeoutMS = 500

以上配置表示如果调用失败或超时,Client将选不同Server重试3次,连接(connect调用)的超时时间是50MS,请求的超时时间(包括发包->Server处理->收包的时间总和)是500MS。

 

以上连接超时(ConnTimeoutMS)可以根据网络情况进行设定,但请求超时(SockTimeoutMS)包含了Server的处理时长,情况就变得复杂。单从一层调用看,请求超时应该略大于Server处理时长,从一条调用链看,上一层的超时设定应大于下一层的超时设定,以下图为例:

对于 user -> A -> C -> E 这条调用链,AC间超时设定需大于CE间超时设定;从调用网的角度看,AC间超时设定不仅需大于CE间超时设定,还需要大于CD间超时设定。 联级超时的设定是RPC框架实现中的经典问题,解决超时配置和维护问题可借鉴 Google DapperTwitter zipkin等分布式跟踪系统的思路。

 

以上提到系统失败、超时都可以通过重试尽量让请求得到处理,但重试次数并非越大越好,考虑Server整体服务过载的情形,过多重试可能引发后端Server 雪崩

 

Client端屏蔽策略

重试仅针对单次请求,如果一台Server异常,一次请求踩过的坑后续请求还要再踩一遍。为解决重复踩坑的问题,RPC框架需实现Client对异常Server的自动屏蔽。

 

屏蔽策略可以这样实现,Client对每个后端Server(IP/port)维护一个评分,每次请求失败(系统失败或超时)则将分数减一,当分数为0时,将IP/port、当前时间戳(timestamp)信息写入一块共享内存(block_shm),Client上各进程访问Server前,先跳过block_shm中记录的IP/port,在一段时间后(如10分钟)再放开该IP/port的访问。

以上屏蔽策略,做到了单机内进程/线程间信息共享,但在模块内甚至全网,Server异常信息依然没有共享,一台机器趟过的坑其他机器也会趟一遍。为解决机器间Server异常信息共享问题,我们可以对上面的实现做一些修改:将屏蔽信息上报到 Zookeeper中心节点,各台机监听相应路径节点,当有新增节点时拉取IP/port、timestamp信息到本机,存入block_shm,从而实现机器间屏蔽信息共享。我们把Client端的这种屏蔽策略称为 漏桶屏蔽

 

Server端反馈机制

Client端屏蔽策略是从调用方的角度保证服务质量,被调方Server也可以从自己的角度尽量保证服务可用。

 

设想一台Server服务过载,落到这台Server上的请求有较大概率得不到处理或处理超时,Server可以提前预判自己的服务状况,当Server认为自身服务能力达到瓶颈时,在Accept或读取请求包的阶段即丢弃请求并给Client一个约定的返回码。

预判的条件可以是历史请求在请求队列中的滞留时长、本机CPU占用率、Server系统失败率等。我们把Server端的这种反馈机制称为 快速拒绝,快速拒绝在Server服务能力达到瓶颈时生效,但明明是Server拒绝了请求,怎么能说是保证了服务可用呢?正如快速拒绝这个名称所指,在Accept或读取请求包这个阶段即把请求拒绝,减轻了Server的负担,同时更快地通知到Client,让其更换Server进行请求重试。

 

同一个Server可能为归属不同业务类型的Client提供接口,不同业务的重要性不同,快速拒绝也可以分业务的重要性进行拒绝。Server优先拒绝重要性低的请求,过载时尽量保证重要业务的服务质量。

 

雪崩

最后我们聊聊分布式服务出灾的一种极端情况——雪崩。 

当某个Server服务过载,大量请求处理失败时,用户行为带来的重试、客户端/后台Server的重试带来翻倍的请求,进一步加重该Server的负担。调用量翻倍上涨,但Server有效输出接近零,这是雪崩的标志现象。主要有两种措施应对雪崩,一是通过扩容提升Server服务能力,二是通过柔性措施,丢弃一部分请求,并且应该尽量在调用链的前端丢弃。

 

小结

本文讨论了RPC框架中的几种容灾措施,包括超时设置、重试、Client端屏蔽策略与Server端反馈机制,最后谈到分布式服务的雪崩。雪崩的处理涉及柔性,对用户体验有损,需要人为决策参与实施。

 


本文链接: RPC框架实现 - 容灾篇,转载请注明。

相关 [rpc 框架 bangerlee] 推荐:

RPC框架实现 - 容灾篇 - bangerlee

- - 博客园_首页
RPC(Remote Procedure Call,远程过程调用)框架是分布式服务的基石,实现RPC框架需要考虑方方面面. 其对业务隐藏了底层通信过程(TCP/UDP、打包/解包、序列化/反序列化),使上层专注于功能实现;框架层面,提供各类可选架构(多进程/多线程/协程);应对设备故障(高负载/死机)、网络故障(拥塞/网络分化),提供相应容灾措施.

JAVA RPC 通讯框架

- - 经验沉淀 知识结晶
Bison 是一个JAVA 程间的通信框架,基于apache mina 实现,对mina进行了byteBuffer 缓冲区重用以及半包出处时减少拷贝. 客户端(bison-client) 功能点. 2 支持高用性:高可用的一个基本原则,可以接受快速的失败,但不能接受长时间的等待. Githup地址:https://github.com/gavenpeng/Bison.

【RPC框架HttpInvoker一】HttpInvoker:Spring自带RPC框架

- - 开源软件 - ITeye博客
HttpInvoker是Spring原生的RPC调用框架,HttpInvoker同Burlap和Hessian一样,提供了一致的服务Exporter以及客户端的服务代理工厂Bean,这篇文章主要是复制粘贴了Hessian与Spring集成一文,. 【RPC框架Hessian四】Hessian与Spring集成.

zmq-rpc:基于zeromq网络层编写的protobuf RPC框架

- Shengbin - codedump
阅读过zmq的代码之后,感觉这个网络层是我目前见过最高效的–线程之间使用lockfree的消息队列保存消息,可以启动多个I/O线程分担压力等等特性.于是决定基于它写一个protobuf RPC的框架.. 另外,这里使用的protobuf是旧版本2.3.0,新版本2.4.1的生成的RPC service接口跟原来不太一致,暂时还没有去研究它.BTW,升级版本之后导致原来的接口发生变化这是一个很操蛋的事情..

集成libevent,google protobuf的RPC框架

- goodman - C++博客-那谁的技术博客
chenshuo的evproto同样也是集成libevent与google protobuf的RPC框架,不过在对libevent的使用上,这里的做法与他不尽相同:. 1) 他使用了libevent自带的RPC功能, 而这里只使用到libevent对网络I/O进行的封装的最基本的功能.. eventrpc项目目前是avidya下的一个子项目,avidya项目的定位是实现一些分布式的玩具系统(比如google已经公开论文的chubby,mapreduce,GFS等),也许以后不一定能被用上,但是也要实践做一把.由于有一个好用的RPC框架是做分布式的必需品,所有首先实现eventrpc这个子项目了,以后也许还会实现其他语言的版本,如python,java..

NFS-RPC框架优化过程

- EricSheng - BlueDavy之技术blog
NFS-RPC框架从编写之初,到现在为止(应该还会有些提升,不过估计不大),每秒支撑的请求数上升了好几倍,测试结果的演变为:. 以上测试结果为在100并发、100 request byte、100 response byte以及单连接下的背景下得出的,在这篇blog中来分享下这个框架所做的一些优化动作,希望能给编写rpc框架或使用mina/netty/grizzly的同学们一点点帮助,也希望得到高手们更多的指点.

RPC调用框架比较分析

- - 开源软件 - ITeye博客
RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议. 简言之,RPC使得程序能够像访问本地系统资源一样,去访问远端系统资源. 比较关键的一些方面包括,通讯协议,序列化,资源(接口)描述,服务框架,性能,语言支持等.

基于hessian和netty的RPC框架设计和实现

- - Java - 编程语言 - ITeye博客
基于hessian和netty的RPC框架设计和实现.         对系统进行服务化改造,或者构建一个分布式系统,RPC是核心的组件,目前主流的RPC框架有hessian\thrift\ avro等,如果不考虑跨语言的话thrift\ avro使用起来稍显复杂,要写IDL序列化配置,hessian又依赖servlet容器,于是使用netty和hessian构建了一个的RPC框 架.

分布式RPC框架性能大比拼

- - 鸟窝
Dubbo 是阿里巴巴公司开源的一个Java高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成. 不过,略有遗憾的是,据说在淘宝内部,dubbo由于跟淘宝另一个类似的框架HSF(非开源)有竞争关系,导致dubbo团队已经解散(参见 http://www.oschina.net/news/55059/druid-1-0-9 中的评论),反到是当当网的扩展版本仍在持续发展,墙内开花墙外香.

基于Netty的异步Rpc调用的小框架

- - Java - 编程语言 - ITeye博客
基于netty写的一个异步Rpc调用小框架,欢迎拍砖,新手. private String methodName;//调用的方法名称. private Class[] types;//参数类型. private Object[] objects;//参数列表.  框架类,有两个静态方法,regist(在服务器上注册服务)和getobjt(获得接口的代理类).