服务器过载保护(上篇)——过载介绍 http://wetest.qq.com/lab/view/?id=69 前端
1 何为过载web
“过载”一词,在海量服务的后台开发中,基本都会遇到。何为过载,即当前负载已经超过了系统的最大处理能力。例如,系统每秒可以处理的请求是100个,但实际每秒的请求量倒是1000个,就能够断定系统出现了过载。算法
过载的定义看似简单,但倒是处理过载问题的关键。对于任何其余问题,一样得抓住问题的本质,方可不偏离问题核心,万变而不离其宗。后端
“过载”的出现,会致使部分服务不可用,若是处置不当,极有可能引发服务彻底不可用,乃至雪崩。安全
咱们的系统中,因为是单线程状态机的处理模式,顺序处理全部连接的缓冲区消息,当出现处理能力的降低或者请求量大幅增长,致使处理能力小于请求量的状况下,消息就会在系统缓冲区中堆积,形成消息处理的延迟会持续增长,在正式环境中,连接数目较多,系统缓冲区较大,最终会致使消息处理延迟大到不可接受的程度,最终会致使处理的都是无效消息,形成服务不可用。服务器
固然具体的业务须要具体的分析,把握住问题的影响,才可以作到一切尽在掌握,根据“墨菲定律”,一般对后果的判断不该过于乐观,谨慎行事、考虑充分才可以作到成竹在胸。网络
“过载”的出现,不一样系统模型的具体缘由都会有所不一样,例如CPU跑满,频繁读写致使IO瓶颈,内存耗尽,请求量突增等等。但究其根本缘由,能够归结为两点:多线程
1、处理能力的降低;负载均衡
2、请求量的上升。框架
只有对自身系统的有更深层和透彻的了解,才能更好地考虑如何处置问题。“头疼医头,脚疼医脚”的处理问题方式,只能解决一时之需,对症下药,才是解决问题的根本之道。
任何问题的保护行为能够依据事件发生的阶段分为:
一、 发生前,预防;
二、 发生时,处置;
三、 发生后,恢复。
但在保护的措施中,都和业务的模型有着相关性,没有彻底统一的方案,适合本身的才是最好的。
在过载发生前的预防,就需在系统设计之初,依据具体的业务模型能够考虑预防过载的措施:
一、 优化服务处理流程,下降处理资源消耗,提高自身处理能力;例如CPU消耗型服务,是否能够考虑优化算法,提高处理能力。
二、 分离处理模块;将负载分担到不一样的模块或者服务器;例如IO是瓶颈的服务,考虑是否能够将IO模块进行分离。
三、 负载均衡;将请求量分流,下降单服请求量。
四、 轻重模块分离;重要模块单独部署和处理,防止模块之间的互相影响。
五、 前端防护;在前端控制请求频率,缓解后端压力;例如客户端能够作保护措施,控制聊天频率,点击操做失败,能够延时一段时间,才容许用户继续点击;前端服务发现后端出现过载问题,可选择性拒绝服务,下降后端压力。
六、 使用缓冲区;缓冲区的使用,能够帮咱们抵挡请求量的抖动,但缓冲区的使用一样也有不少技巧,并不是越大越好。首先须要考虑内存,cpu等资源的开销,业务的模型是否须要这么大的缓冲区。例如缓冲区过大,处理完整个缓冲区,都须要几十秒,而前端等待超时则为几秒,那么每次处理缓冲区的内容,都是旧的,前端认为都是超时,服务彻底不可用。另外是后端却又处理成功,会致使系统信息不对称,从而致使更为严重的问题,例如,在游戏中购买道具的场景,前端扣用户的钱,认为超时失败而不给用户发对应的物品,后端却又执行成功了,严重运营问题就此产生。
七、 作好监控,及时告警;例如当CPU达到80%时,当处理请求超出必定阈值时,及时告警,作好扩容,优化等其余准备。
固然依据业务模型的不一样,还有不少预防的措施,依然是前述作到知底,才可以找出适合自身的方法。
处理过载的方法有许多,适用于不一样的业务场景,并没有绝对的最优方案,合适的才是最好的,但能匹配上“合适”一词,是对系统总体和经验的一个考验。下面介绍一些经常使用的处理方案以及咱们是如何作的:
Ø 请求量阈值控制
在系统部署上线以前,预估好系统的处理能力,限定最大同时可以处理的请求量、流量或者连接数。当请求量快接近于最大处理能力时,则告警,超过范围,则触发拒绝请求机制。因而可知对于阈值的设置是一个很关键的环节,阈值太高,依然可能致使过载,阈值太低,则又致使负载上不去。阈值的设置也会是一个不断调优的过程。该方法的优势和缺陷都很明显。
优势:识别和处理简单;
缺点:阈值的设定须要必定的经验,会有必定的难度,同时若是处理能力发生变化时,阈值就很难动态发生变化。
Ø 监控系统资源
服务器监控CPU,内存等资源的使用状况,设定阈值,超出阈值,则能够认为过载,从而触发拒绝请求机制。
优势:使用动态的资源数据,从相对根本的缘由上识别过载,而无需过多关心具体的业务处理;
缺点:一是处理相对复杂;二是在某些场景下,资源数据的耗尽并不意味着出现过载的状况。例如服务开了较大的内存池,看起来内存资源耗尽了,实际上负载是足够的,又如如今都是多核服务器跑着多进程或者多线程的服务,单一的CPU耗尽也不可以表明服务就出现过载,但又可能产生过载,这就和具体业务有关;三是在某些场景下,出现过载的状况,也不必定会耗尽资源,例如当前全部的服务都在等待之中(多是后端的回复或者其余),一样也不会对CPU、内存、io、网络等资源形成影响,但依然进入了过载。整体来讲该方式适合的场景相对会简单点。
Ø 检测请求到达时间
依据请求处理的时延来判断是否过载。记录请求到达的时间戳,和处理请求结束的时间戳,获得请求到达自身服务器处理的时延,超出阈值,则可断定为超时失效,能够直接丢弃。使用独立模块读取系统缓冲区中数据,打上时间戳,存入消息缓冲区,在处理时,超过必定时延的请求,则拒绝处理,由于能够认为即便处理了也是无用的。从中能够看出时间戳很关键(为啥会单独提出这个问题,由于在后续的方案设计中,时间戳依然是解决过载问题的关键点,此处先卖个关子)。
A、 时间戳若是使用本地读取时刻调用系统的时间函数获取,就没有考虑消息包到达系统缓冲区的时间,所以是万万不能这样作。
B、 到能够经过ioctl调用SIOCGSTAMP的接口,得到时间戳,但这会加大系统开销,缘由是每次recv完,都须要从新设置一下ioctl一次。而且不是线程安全的。
C、 使用socket选项SO_TIMESTAMP,经过带外数据获取到数据到达系统缓冲区的时间。
其处理方式以下图所示:
经过这种方式已经可以很好地解决负载问题,经过如此,并不须要设置过于繁琐的配置或者去识别过载的问题,目前此方法在SPP的框架中在使用。我的以为可能存在的一些问题在于:
一、 彻底使用时间戳过时的方式来判断,并不必定适合全部场景,假设处理耗时过长,而在缓冲区中也呆了较长时间,但请求量并不大,服务器未过载,在处理一些须要强写入的状况下,单靠该机制也会稍许欠妥。但若是加入一些协议上层机制,告诉该消息务必执行,也是可避免的。
二、 在出现过载的状况之下,极可能会致使总体的服务都会产生一个固定的延时,由于每次抛弃到可执行的范围内,至少会有一个超时时间范围内的延时,若是是较长的服务链的话,最前面的等待服务极可能会出现超时,所以其延时的设置相对也很困难,太小就太过灵敏,过大就会出现刚所述的问题。
三、 该方式只是管理了到达本服务器缓冲区以后的问题,并无考虑整条服务链上的延时,极可能到达本服务器缓冲区时,就已通过期了,而且有可能这些数据在对端缓冲区已经产生了堆积,但到本端,并不会判断其过时。
四、 剩下还有一些内容能够作更多优化:另外SO_TIMESTAMP使用的是系统时间,会受系统时间修改的影响,但这个问题也不大,由于即便修改了,影响的只是本次系统缓冲区的数据。其余能够考虑业务的轻重程度,作按服务来丢弃。
服务器过载保护(下篇)——过载处理新方案 http://wetest.qq.com/lab/view/?id=70