0%

游戏服务器基础结构

每个项目开始,我都会对服务器的结构做一番思考,想说累积的经验可能会激发一些新的思路。这一次的梳理感觉变化比较大,在此做个记录。


关于 skynet

其实不是第一此接触 skynet 了,2013 年的时候曾经用它做过一个棋牌大厅的服务。现在想来那个时候真的经验尚浅,很多设计上的想法都比较稚嫩,而且对 skynet 本身的设计初衷的理解也不够,加上 skynet 也是刚刚开源不久,完整度和稳定性上还有一些欠缺,结果就是用起来感觉束手束脚,所以之后的项目就没在用它。

这次也是工作的原因,又遇上了,花了一些时间,也算做了一个比较深入的了解,看完之后确实受益匪浅。


单线程 vs 多线程

早期接触的游戏服务器大多都是分服的结构,所有游戏逻辑都在一个进程内,多线程的优势在于可以利用更多的cpu核心提高单服的在线,但是太过彻底的独立计算逻辑会导致锁的泛滥无形中提高了开发和维护的复杂度。这个时期我见过更多的做法是,将大部分游戏逻辑放在主线程中执行,然后把一些耗时的独立的计算分离出来给辅助线程执行。

到后来手机游戏的时代,更多的是共服的结构。这个时期很多的公共服务都被从游服中剥离出来,比如公会、聊天、地图、副本等等,都被独立出来放到另外一个实例中运行。公共服务被剥离,那游服内的用户之间又互不干扰,天生就应该是多线程发光发热的地方。

c++ 还是 lua

这里说 lua,其实并不特指 lua,脚本语言很多特点都是类似的,只不过这里是基于 skynet 来说明,所以只好拿 lua 来说事了。

lua 的优势在于它是动态语言,加上有 coroutine 的支持,为实现 rpc 提供了极大的便利。特别是在共服结构下 rpc 是非常常见的,如果每次 rpc 调用实现起来都很繁杂,业务开发的时候就非常难受了。
劣势也在于它是动态语言,没有编译期,很多错误只能在运行期发现;另外对多线程开发天生不友好,由于虚拟机的独立性,多线程间的数据共享会是一个问题,比如大量的配置数据。

c++20 也开始支持 coroutine 了,这个有待考察。如果就 coroutine 而言 lua 是有优势的,lua 的 coroutine 是可以嵌套的,其它很多语言包括很多脚本语言都没有这个支持。

如果用 skynet

现在的 skynet 的生态算比较完整,我的顾虑有一下几点:

  • 定制的 lua 源码
    受限于这个定制,就算将来 luajit 支持新版本的 lua,大概率也是用不上了。
    另外 lua 本身也还在更新,许多新特性需要等云风去同步 lua 版本。
    还有就是如果定制有什么限制,如果云风自己遇到的,我相信他可以搞定,但是如果是自己的需求呢?

  • 多线程间共享配置数据
    skynet 提供了一个叫 sharetable 的功能可以解决这个问题,但是这个 sharetable 是要基于定制版的 lua 的。

  • 每个用户一个独立服务
    这个机制本身没有什么问题,包括性能上也不存在问题,但是要受限于上面两点。如果想脱离这种限制,我可能会考虑一个服务多个用户,然后多开几个这样的服务,由于线程数有限,就算配置数据较多,能被浪费的内存也有限,而且这种做法也不会影响多线程的发挥。当然也可以一个 skynet 进程开一个这样的服务,然后一台机器开多个这样的进程,但如果真的这样做,还需要用 skynet 吗?

  • 服务权重问题
    这一点我还需要再深入下,但是直觉上,由于服务数量比重不同会造成负载消耗速度有差异,可能会造成某些服务的负载堆积,进而影响整体的性能。

  • 集群支持
    skynet 是提供了 cluster 支持的,但是这种支持是基于服务的,我更希望的是基于 实体 的支持,这种实体可能存在于同一个服务之中,当然这也只是初步的构想,需要找时间实现看看。