这些都好解决的,就是换个服务器或者换个托管的机房就ok了.
不过,你需要先考察一下自己网站的语言架构,动态页面会额外增加服务器的负载.一般都是采用asp+html的方式来达到优化.
首先要谈到架构,微信后台系统的模型大致理解为三层架构,接入层(proxy)、逻辑层(CGI)、存储层(后台模块)。啥意思呢?由接入层mmproxy调用逻辑层的CGI,比如摇一摇或者发消息的CGI,逻辑层再和存储层通信,比如存取账户信息,文件,地址信息等等。这是常规主流的架构没有什么特别需要说明的了,这边采用的是微服务架构,通信使用RPC框架,调用下级模块过多,就有 高扇出 问题。
我们先来理一下过载可能导致的一些现象。假设后台模块系统极限请求量是60万,我们知道当实际请求量超过这个数值就会过载,那么过载会发生什么情况?是不是发送了70万请求过来,只有60万之外的那10万请求不能被处理?答案显然不是,实际情况要比这个糟很多。很显然系统一旦过载,可能就只能正常处理20万的请求,原来的60万极限值处理能力是保不住的,甚至还有可能雪崩,直至毫无处理能力。当然,这里面的原因有很多,比如无效响应,失败重试,级联传递等等。
假如一时间好多人发送了摇一摇请求,这些请求都依次入队准备去调用寻找同摇好友的CGI并等待响应结果。但是队列很长,假设这些请求的超时时间是5秒,等待时间如果6秒过长就会导致RPC超时,一旦超时调用方可能直接关闭不再等待响应,等队列排到后执行完逻辑返回的响应调用方此时并不接收也等于是属于无效的响应了。来举个栗子,春运快到了,你挤在车站排队买车票,假设最后一班发车只有60分钟了,窝了个大叉,当你排队了半天到达售票窗口时已经用时80分钟了,这时候售票员再给你吐出一张车票已经毫无意义了,车都跑了。这也叫“无效输出”。
当然除了大部分无效的响应处理耗走了资源,别忘了还有失败重试。一般RPC框架都会设置失败重试机制,当请求得不到响应调用端会重试,如果一时间失败过多将会导致短时间内大量重试请求的发起,导致进一步过载,无疑是对本已经并无富裕的系统负载雪上加霜,滚雪球效应。
由于采用微服务架构,各模块之间的调用相互影响。由于服务依赖的复杂性当前模块的雪崩会导致上游模块的变慢,性能下降,如果此时上游模块也开始过载,继续向上级联,从而导致整个系统崩溃。怎么理解呢?假设一个餐厅里的2个厨师,A桌定了2个大菜烹饪时间很长,那么就会影响传菜员的上菜速度,传菜员要等待,假设全店传菜员有限只有2个都在等厨师出A桌的2个菜后才能去服务其他桌,这个时候就影响了整个餐厅的顾客的用餐速度,最终可能导致好几桌的顾客都吃不上菜且骂骂咧咧跑了。其实这个在Hystrix里采用了资源隔离来解决这个问题,即一个传菜员只服务于一桌,A服务员只服务A桌,B服务B桌,A慢的话就A这一桌慢,B桌的传菜员只传他B桌的菜哪怕闲着玩手机也不理其他桌。
谈完原因谈解决方法。该怎么处理呢?其实Hystrix的这套思想很好了,基本思想核心也相似,但今天主要是谈微信后台实践的解决方案。
常见的过载保护方法
1.减少需求:调用端的请求限速
2.避免响应超时:根据调用端超时,设置T超时时间;控制队列长度,容纳T超时时间内的请求。
调用端限速
限多了,服务器能力没有充分利用,限少了,过载问题没解决。而且过载时,响应时间会阶梯式上涨,这样超时时间就会 波动 ,队列长度难设定。虽然极限能力 绝对值 比较难找,但服务器最佳负载点容易找。所以过载保护的目标:尽量让服务端维持在最佳负载点, 让有效输出接近最佳吞吐 。
古希腊水钟
那如何维持在最佳负载点呢?水钟的启示:反馈控制系统。
如图,图中的浮子上浮,上水箱下水减速,相反如果下沉则加速上水箱下水。浮子起到了稳定液位的作用,使得中水箱的水位相对稳定,往下水箱的滴水速率自然也相对稳定,使得计时相对准确。
那么OK啦,也就搞一个像浮子一样的机制,多了及早拒绝,降低通过率,少了缓慢提升通过率。
1、通过反馈动态调整通过率:及早拒绝
根据CPU使用率和队列等待时间,控制输入,这里有个算法FastReject V1计算的是 通过率 ( 过载时 按一定概率通过请求),算法公式暂不展示,主要讲究的是快降慢升。触发降低通过率的场景比如有:比如每隔一秒统计一下队列等待时间,超过n豪秒就降低通过率,或者当前CPU使用率超过阈值(比如85%)也降低通过率。及时反馈控制,不让队列等很久等到轮到自己被处理后前端已经关闭了请求,导致无效的响应。这样请求要么超载被直接拒绝,要么是有效响应,保持原来的处理能力,不让过载雪崩。这就是出队时再判断超时还是入队时就判断的区别。记得这个在Hystrix限流熔断里叫做“降级返回”。
2、同时计算业务的优先级权重:优先服务重要业务
这有点类似早高峰的公交专用道了,由公交车优先通行。实现其实也比较简单,为每个业务(CGI)指定一个优先级(这个优先级可以由后台根据业务实际配置),每个请求带个是属于什么业务的标识,FastReject对每个业务优先级维持一个通过率,低优先级通过率降为0,开始拒绝更高优先级。比如聊天消息发送的优先级为1,上传文件为2,数字越小优先级越高。当上传文件的通过率降为0后开始降聊天消息的通过率,这样保证了优先服务重要业务。这个在Hystrix里类似服务的“优雅降级”。
这里的优先级信息传递用的是RPC COOKIE。因为RPC框架支持cookie,那就刚好借用类似http cookie 的思想,请求/响应包预留cookie 字段,请求携带cookie跨模块自动传递。比如CGI_ID标识或者下面分组提到的用户ID。
3、用户分组:保证要不过第一次就不过
注意了,这里的内容大家可能会比较感兴趣。这里要从刚刚上面的那个优先级说起。我们知道,微服务架构各模块之间的调用相互影响,如果一个请求服务端需要请求多个模块才能处理完逻辑返回结果。那假如说请求R需要经过A模块请求B模块,B模块再请求C,B再请求D等等(注意这里B需要同时请求C、D两个模块获取结果),那么如果请求通过了A模块的通过率,C模块的通过率,到D模块没通过,那么前面的处理是不是都白费了,又违背了我们之前所做的及时拒绝无效响应的原则。那怎么解决呢?这里采用了用户分组的方式。举个例子,比如现在根据QQ号对用户进行分组,从0-9取尾号散列分为10组。QQ号为123的请求过来,首先用户是被分到3组的,如果在C模块被拒绝,那么该用户乃至该组的其他用户直接在D模块或者后续E,F等模块的调用都会被全部拒绝,这就是按组拒绝。保证一个用户要不过第一次请求就不过,不会说在聊天聊一半发不了消息了或者消息在中途某个服务才开始失败。 用户分组思想类似单双号限行。
这里有个有趣的事情,比如某用户被分到3组,3组被拒,那么他是不是每次过来都是被拒的,这要是抢红包那你不是会直呼“不公平”。所以这里做个小调整,如果这里每隔一段时间变换散列算法,前一分钟123可能是3组,后面可能是7组,这样来解决同一个用户每次来都被拒的情况,而其他用户都不会被拒的情况,也算是公平了。
4、让调用端也带FastReject接收服务端反馈:服务不行调用端就直接不发起请求了
这一点也很好理解,RPC将每次返回信息也反馈给调用端,调用端在调RPC前先自我检查,看看服务是不是已经不行了,如果不行了就干脆直接不发起请求过来了,避免请求过多。这一点有点类似Hystrix的熔断器机制,接收反馈并自动作熔断操作,服务降级。
总结:实际上,这和Hystrix思想其实大同小异,可以看下 《通俗一点讲“限流熔断之Hystrix”》 就会发现太多的异曲同工之妙。就到这里,说好的浅谈辄止的,感谢品阅~~。
恭祝大家新年快乐!万事大吉!
相关文献:
《Overload control for scaling WeChat microservices》
《10亿红包从天而降,揭秘微信摇一摇背后的技术细节》
欢迎分享,转载请注明来源:夏雨云
评论列表(0条)