2022-05-21
高效游戏服务器感想

为了同时服务更多玩家,采用多网关; 一个游戏服务分N个工作线程加一个网络线程一个定时器线程,通过互斥锁,条件变量对其进行控制,没消息的时候所有工作线程睡眠,当网络线程有消息投递到一个消息队列里的时候就唤醒一个线程去从消息队列里读取并处理,当又有消息来了的时候继续去消息队列里读取消息,以此类推,定时器线程亦是如此,当所有消息读取并处理完后所有工作线程就再次睡眠,N个工作线程就这样被消息驱动的方式高效运转下去。这样如果逻辑复杂处理速度大于N个工作线程读取消息速度之和的话还好,否则处理速度时间消耗短就会造成浪费一部分时间都在忙等和线程切换,因为消息队列需要加锁,而且需要是自旋锁,所以此方案缺点就呈现出来了。正确方案是将这消息队列改为一个二级消息队列,首先是一个全局消息队列管理所有用户的消息队列,全局队列里的每个元素都是一个用户的消息队列,当某个用户的消息队列里有数据就挂到全局消息队列里等待等待闲下来的线程处理,某个线程抢到此用户的处理权限就将其从全局消息队列里拿下来,然后一次性将此用户的消息处理干净。就这样以用户消息队列为单位处理相比以单个消息为单位处理完成忙等的时间更短,也就降低了CPU浪费。

涉及到多人共享的模块,比如战斗模块,场景模块可以将其像用户一样对待,它有自己的消息队列,所有人都可以投递关于这个模块的消息到全局消息队列,然后由工作线程去处理,这样游戏逻辑以模块划分,所有用户属于用户类模块,还可以加数据模块,排行榜模块,公会模块等等,都可以按照这种方式来做。这里模块向全局队列里投递消息可以通过管道,网络线程中epoll也可以监听这个管道中的数据,收到数据后再将其放到对应模块的消息队列,同时挂到全局消息队列,唤醒工作线程去处理。

灵感来自skynet,如果喜欢C++或Go语言以及其他非lua语言写的话可以采用这个思想


知识共享许可协议
本站文章采用知识共享署名 4.0 国际许可协议进行许可。

samoyedsun.github.io