之前写过三四篇关于服务器过载时的文章,这里总结下上周和本周关于阅读论文DAGOR:微信「大规模微服务过载控制系统」及DAGOR:微信「微服务过载控制系统」,有兴趣的可以去看下。想到什么就写些自己的想法,个人理解可能有偏差。
这里简单列一下核心思想:“DAGOR设计使用等待队列中请求的平均等待时间(或排队时间)来分析服务器的负载状态。请求的排队时间是由请求到达服务器与其在服务器上被启动处理之间的时间差来衡量的。另一个问题是:为什么不使用CPU利用率作为过载指示?诚然,服务器中CPU利用率高表明服务器正处于高负载状态。然而,高负载并不一定意味着过载。只要服务器能够及时地处理请求(例如,排队时间较短反映了这一点),即使其CPU利用率保持较高,也不应该认为服务已经过载。以及一组服务准入控制策略等”
由于以上论文实现针对SOA微服务,当然对于其他业务场景应该也有类似的思想。论文中还有具体的分析可以思考下,挺适合学习下。这里分析下游戏业务中是如何处理过载的,因为平时遇到过这种情况,只是调整框架和其他手段来解决负载但还可能存在隐患。
一般网上介绍的游戏框架是分层解耦结构,即前端的接入网关层,负责连接的管理,消息的收发以及加解密等,并不需要关心消息的业务相关,那么这里存在一个问题是,和后端进程通信时,投放的消息如果后端来不及处理,该怎么办?即收消息的缓存区没有足够的空间,此时是丢弃此条消息?如果这条消息的业务需求比较重要,比如花钱操作或登陆请求。这里的游戏框架不像其他服务,不可能在收消息投放失败时,再给client回个包,说,你重试其他server,对于游戏来说,后台业务进程是有状态的,本进程有角色的数据;当然可能不回包,然后客户端支持超时重传,也是一种处理。
因为网关层是不知道此条消息的重要性即优先级,都一视同仁,当缓存区满时直接丢弃,这是简单的做法。如果要分消息优先级则可能会引入足够的复杂度,首先网关层可能要解析消息并和具体的业务耦合在一起,来判断哪此消息是丢还是留,当然网关层首先要导入一些规则来判断。再然后,如果后台架构是这种类型:gatesvr->gamesvr->globalsvr,gatesvr->gamesvr这里没有出现负载,但gamesvr->globalsvr出现负载,即内部比如gamesvr请求处理某类消息,此时globalsvr出现死循环,那么到globalsvr的消息缓存区立即满了,那么可能导致gamesvr上的消息只处理到一半永远等不到后续,如果业务这么设计是有问题的,即论文中“在图2.a中,箭头表示一种通过服务A调用服务M的请求类型。当服务M过载时,发送到服务M的所有请求都会受到影响,从而导致响应延迟甚至请求超时。更糟糕的是,过载服务的上游服务(如服务A)也会受到影响,因为它们在等待过载服务的响应。这将导致过载从过载服务向其上游服务进行逆向传播。”
如果某个客户端使用加速器,大量的发移动包到gatesvr导致消息缓存区立即满了从而导致其他client合理的正常请求被丢,这里类似syn flood攻击,当然具体怎么解决再说。这里假设从client来的请求都是合法的。我见过好多设计当消息缓存区满了后,直接丢的,不会再扩容,这样是为了保证后台服务的稳定性及可能在一定的时间内恢复并处理其他后续的请求。这样,当客户端收不到心跳的情况下,可能会走断线重连的情况,或者心跳时间过久,而客户端进行同步请求包,此时等不到响应,再超时重传,比如三次后还是失败则进行断线重连这样。若是异步请求则不知道这些包是否被服务器处理(不管是处理成功还是处理失败),比如移动包,一秒发了四个,可能前三个因为消息缓存区满被丢,而后面的被处理,那么server可能要特殊处理下,包括其他client看到该client实体时的移动处理,这块属于移动同步延迟处理,不在这里的讨论范围。
当一个请求需要两个server协作时,如果server1处理一半并转发到server2,而server2此时消息缓存区满,那么该如何处理?因为这个过程被打断了,并非是那种处理失败,而server2根本没有机会处理,所以这里server1上的状态因为超时回滚?但超时设置多久又是个问题。这里的主要问题是server1处理该请求时并不知道server2的情况,如果知道的话,server1不会处理请求并再转发到server2。原论文中建议给每个请求加个优先级,并server2每处理上游转发来的请求,server1会带上优先级并在响应中带上server2的负载信息,这样server1在入口就把不该处理和转发的请求早点拒绝掉,server2保证能处理优先级高的请求。
这里再考虑一种消息缓存区不限长的情况,比如开源框架skynet,虽然可以在上层加个service作中转,加上超时来实现负载信息,但底层框架现有的实现,是网络线程收到消息后,直接push到相关的消息队列,这样如果有恶意client一直猛发包,很可能出现问题。如果有同学愿意改源码的话,这块还是很好处理的。当然,阻止client端的不断请求,还有要注意内部service不断的发消息到其他service这样的情况,造成负载。之前线上出现过这样的情况,后来还是差不多解决了,但并不彻底。
负载这问题网上有很多话题,解决方案也不一样,有的简单粗暴,有的优雅,体验性更好,如论文里说的,不过也复杂。当然游戏业务早期没必要考虑这种情况,一般优先业务正确性和稳定性。当然,也见过好的游戏获得苹果推荐后,server频繁宕机的情况。
网友评论