最近服务器出现了一点问题,就是在开服的头一两天,人数较多时会导致登陆不上。
基于我处于空闲状态,这个任务就肯定是落在我头上了。
接到这个任务,我就在想,登陆不上,而且还没提示,肯定就是网关服务器的问题。接着便把可能发生的问题罗列了一下:
1、配置没有配好,导致人数超过了上限;
2、网关服务器负载均衡部分写得有问题,导致人数多了就奔溃了;
3、服务器物理机有问题,开的服数多,导致内存不够用;
4、网络线路抽风。
针对这几个问题,我问了运维一些问题,以及把出问题的log要过来看。首先,先确定物理机的配置:CPU是8核16线程,内存64G,最大网速10Gbps。然后运维告诉我,一般开4~6个服务器,内存使用率约为56%,CPU和网速使用率都非常低,这样就排除了问题3。然后游戏服务器出问题时,同一台物理机,只有一个服出问题,其他都没事,那就排除了问题4。接着运维还告诉我,配置已经从500人提到800人了,但是还是会出现这个问题,因而问题1也可以排除了。
好的,接下来就全身心研究负载均衡的问题了。
先大概说一下网关服务器的架构。
首先它是基于事件驱动模型设计的,简单点说,就是有一条主线程,循环处理各种事务,其中最重要的事务就是从消息缓冲区中提取消息,并处理之。那么这些消息从哪里来的呢?从另外的线程来的,叫WorkThread。
网关服务器启动时,发起了1条MainThread,用于不停地Accept底层IOCP建立的连接。连接建立起来后,就将该客户端的信息(socket什么的)放在一个自定义类WSAContent里面。WSAContent不仅保存了和客户端通信的socket,还有双缓冲区(一个读缓冲,一个写缓冲)。
发起1条SwitchThread线程,用于交换双缓冲区的内容。检测到读缓冲区已经空了,那么就把写缓冲区和读缓冲区的内容交换。如果读缓冲区不为空,那么就提取一条消息,调用IOCP相关的接口(一时忘了)把消息放到队列里面。
发起了CPU核数*2+2(+2是为了处理峰值并发量)条WorkThread,里面其实就是调用GetQueuedCompletionStatus()来获取SwitchThread线程放进队列里面的消息,如果消息没出错,就进行业务处理。
主要的框架就这样,那么说好的负载均衡呢?
其实就是在MainThread提到的WSACotent类,开启服务器时,就会创建和配置的Client数一样多(甚至会再多点,为了处理峰值并发)的WSAContent实例。每次Accept都会选取空闲的WSAContent实例来专门应付一个Client,这样就能够将每个客户端的独立开来处理了。
然而这并没有什么卵用!因为有些玩家操作少,有些操作多。当玩的人数多时,网关服务器的负载多了,处理消息速度就难免跟不上来,这时刻肯定会卡的。而玩家一卡的话,肯定就是不停地动来动去,那么负载压力就更大的。这时候处理不过来的消息都会被丢掉,有些重要的消息就不会被丢,但是双缓冲区都爆满了,肯定也是处理不了只能丢了。那么断线重连的消息肯定是没得响应了,就造成了断线后连接不上的现象。如果此时退出到登陆界面,在重新进入游戏的话,应该是可以进去的,但是无奈服务器处理不过来,要等待比较久才登陆得上。但是登陆是有时限的,连接上一段时间不操作,就会断开,那就造成了登陆不上的效果。那这么说来,就是还是可能登陆得上咯?是的,我看了log后,发现出现问题(登陆不上)的时候,在线人数仍然在增加。
那么说到底,怎么解决呢?个人觉得这个是服务器写得烂而导致的,尤其是在网络不好的情况下,屯了一大堆的消息,防抖动性太差而导致的。目前最好的解决方法就是把网关服务器关了再开,那就ok了。至于进一步的解决方法,我得要仔细想想,毕竟实在资历尚浅,重新写一个估计没那么容易。
明天就搜一些优秀的网关服务器来研究!