概要陈述
后台服务里面,绕不开的几个主题:容灾、过载保护、柔性。所谓容灾,其实就是备份,逻辑层容灾保障节点故障服务不受中断,数据层容灾保障节点故障数据不至于丢失,读写服务仍可进行。过载保护,本质上则是让自身模块,服务于其能力所在的请求上限,对于服务能力之外的,尽早丢弃,以免引起队列挤压和上层模块雪崩。柔性,是在过载保护之上的一个命题。过载,其实已意味着服务对象受损,是经过筛检丢弃的,而柔性,旨在不影响主逻辑的情况下,以减少一定的逻辑开销,换取吞吐服务能力。某种意义上,它是服务质量受损。以腾讯IM通信为例,在数据下行可能会试图获取昵称,但是当模块过载,可以关闭这个逻辑,把系统资源留给主线逻辑。本文,则重点旨在对柔性做展开陈述,提出一种自适应柔性的框架概念,其在应用中,也得到了实战的验证。
背景:
“弃车保帅”, 是对柔性的一个最形象的描述。但是传统的柔性,一般存在各种缺陷。以下列举三种:
1. 服务柔性的触发机制和时机?面对网络服务的波动性和大型活动等不可控性,请求可能存在毛刺和突发,好点的系统有流水日志,自动化告警监控,但是等人为发现,然后操作配置甚至发布,事件已经过去,服务已受损相当一段时间。人工24小时关注视图是不可能的,这辈子都不可能的了。这留给我们一个问题:是否可能存在一种自动的监控方法?
2. 如何让柔性的代价最小?在实际部署应用中,因为地域园区部署的不均衡、活动源头的汇聚性、服务器自身性能的差异化等要素,带来的问题是,过载可能仅集中在若干几台服务器。而柔性的手段,像是开关、配置下发,往往是全局性的。一刀切的柔性,有损整体体验。这里说的全局性,指代全量服务器生效,全量的请求生效。这留给我们一个问题:是否可能存在一种可能的柔性方式,1)让柔性只在瓶颈服务器上生效;2)让柔性在本机上只生效一部分,换取的系统资源刚刚好能服务于过载的请求量。
3. 如何让服务模块联动起来,整体动态调整?传统的柔性往往是自身去降低本模块的服务质量,换取资源利用。是否存在一种可能的方式,把自身过载的信息传递到上游,换取上游降低对其的调用(如果非关键路径和重试的压力),间接地实现柔性的策略。
实现方式:
本文尝试提出一种柔性的框架体系,它简单而言可以用上面的模型去描述。对于某一个服务逻辑分支(比如,上面说的IM的拉取昵称),输入(uin)是号段,当然其他服务系统也可以是类似的离散区段的概念,用于对柔性进行分区区别对待(对应的是一刀切柔性);柔性范围(ctrlRange)反映的是柔性的区间,在此区间的号段,是需要启用柔性策略;监控事件(monitorEvent)是对过载事件的监控,他需要传递的信息的当前本服务器是否过载,如果过载,那么他是在持续/恶化(Positive事件),还是在缓和/恢复(Negative事件)。输出是对本次请求的这个行为,是否需要柔性处理(flexibility),比如,不做拉昵称。
1. input,这个不用多说了,视乎系统,可以是号段,也可以是sessionId。
2. monitorEvent,这个是描述系统过载是否发生,且发生的趋势。一般的后台服务框架,都存在类似一套KV存储(KV存储的载体、如何传输到监控系统这些都是开放的),用于监控和上报一些事件。类似于“打点”。那么过载事件的发生,也就可以认为是一种事件,作为打点一种key,value是其发生的次数。其共制的,都是反映的本服务器的过载事件,数据都在本机上有一份,都是能够有手段获取的,可监控到的。
像是一般的系统框架,在proxy层负责把包放入channel,worker层负责消费请求包。proxy在插入的时候打上收包时间戳。worker取包处理的时候发现当前时间间隔已过一个阈值,即表示发现队列挤压,需要丢弃该报文。此时可以往KV存储上报这个监控事件发生,过载已发生。当然了,定义过载的手段不局限上述实现方式,也可以是系统CPU使用率等,这个始终要的是一个过载事件的监控体系和KV存储模块。它需要实现的是,秒级的,本机负载的状态监控。
3. ctrlRange,它反馈的是当前,本机上,柔性的号段范围。是一个动态的、弹性伸缩的区间。旨在以最小的服务质量受损代价,换取服务的可用性。
void ModifyCtrlRange(eventValue)
{
if(IsPosive(eventValue))
{
ctrlRagne += positiveStep;
}else
{
ctrlRange -= negativeStep;
}
}
总的来说,需要定义一个模型函数(IsPositive),它描述了当前机器,过载是否在持续发生/恶化(Positive事件),又或者是在缓和/恢复(Negative事件),Positive事件发生时,应该逐渐增加柔性的区段范围,Negative事件发生时,应该减少柔性的区间范围。并且整体而言,Positive事件发生时应该迅速启用柔性(斜率大),Negative事件发生时则试探性地收窄柔性区间,缓慢探测回落(这个决策模型函数是开放的,自行定义即可)。
4. flexibility, 决策最后这个请求是否需要执行柔性策略,它的实现逻辑很简单,这里反映出来的特质是,他是一个渐变的区间,不是一个二元的配置。
bool NeedFlexibility(uin)
{
if(uin%MAX_RANGE < ctrlRange)
return true;
else
return false;
}
正常情况下,柔性的启用会引起负载的下降,而柔性的关闭则带来负载的上涨,因此这里会是一个反馈的过程
在柔性的范围上,反映出来的则是一个动荡收敛的过程:
这里的理念是,始终尝试以最小的服务质量代价,换取可用性。在此期间,试探性“牺牲”一些请求报文,去探测服务是否恢复可用,最后缓慢回落着地。
5. 模型的扩展性,至此,我们讨论的都是如何在单机上做负载的监控、柔性、调整。如何实现上下游节点的级联,让整个系统联动起来。
这里的理念还是用的上述的柔性模型,event换成下游是否过载(这个信息可通过过载的模块,在已处理的请求里面,在返回rsp里面把这个信息夹杂着盘带回去上游),而上游柔性的行为,则改为减少对过载模块的调用(如果非关键节点)或者减少重试以减轻对其的负荷。依然的,这套体系符合整个动态柔性调整的模型。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。