GoWorld – 用Golang写一个分布式可扩展、可热更的游戏服务器
GoWorld代码:https://github.com/xiaonanln/goworld
Golang具有运行效率高、内存安全等优良特性,因此是非常适合用来进行服务器开发。使用Golang开发游戏服务器有如下的优点:
- 运行效率远高于各种脚本语言,大幅度提升服务器承载能力
- 内存安全,不会像C++服务器那样出现内存错误导致服务器down机
- Goroutine能够很好地利用多核计算能力,提升承载能力
- Golang本身非常简单好用,大家都喜欢
然而使用Golang编写游戏服务器也面临一定的困难,主要是两个方面:
- Golang是静态编译语言,难以为提供方便的语法糖从而简化开发工作
- Golang无法支持语言层面的热更新,可能因为频繁关服带来玩家流失
GoWorld是一个使用Golang实现的可扩展的分布式游戏服务器引擎,并致力于解决以上的这些问题。首先,GoWorld提供对象(Entity)框架来为服务端逻辑开发提供便利。Entity可以在多个场景(Space)之间进行跳转,并且提供AOI支持,因此GoWorld可以很好的支持各种MMORPG游戏服务器所需要的功能。另外一方面,GoWorld通过进程替换来实现游戏逻辑的热更新。在热更新过程中,玩家的客户端连接和各种游戏状态会被保持,并在热更新结束之后恢复正常游戏。
进程结构
一个GoWorld系统包括一个dispatcher进程、一个或者多个game进程以及一个或者多个gate进程。dispatcher负责game之间以及gate和game之间的消息转发,并对一些基础功能提供支持。Game进程负责Entity对象的管理和所有游戏逻辑的运行,Gate进程负责管理客户端连接,并将客户端请求通过dispatcher转发到game进程。Gate还需要负责对客户端数据进行压缩和加解密(尚未实现)。GoWorld可以通过增加更多的game进程或者gate进程来增加服务器的负载能力。虽然dispatcher进程是GoWorld服务器中的单点,但是初步的测试和推算表明一个多核高性能的主机上运行dispatcher可以支持100万以上的同时在线。
热更新
GoWorld使用Hot-Swappaing的方式实现游戏逻辑的热更新。在Game进程收到SIGUSR1信号的时候,就会把当前所有Entity以及其他相关状态保存到一个文件中,并结束进程。此时可以使用最新的可执行镜像重启game进程,并从保存的文件中恢复所有的Entity和游戏状态,并恢复执行。在热更新的过程中,玩家客户端的连接不会中断,玩家角色的状态也会保持不变,只是会感受到一点卡顿,并在热更新结束后恢复。
Entity架构
Entity RPC
在GoWorld中,我们使用一个Entity来代表游戏场景中的玩家、怪物、NPC之类的对象。GoWorld还支持从客户端到服务端的RPC通信,以及服务端Entity之间的RPC通信。
GoWorld在RPC数据的封包和解析上使用了MessagePack格式,并会在将来支持Google Protobuf。
场景
场景(Space)是GoWorld中一个非常重要的概念。每个Entity都属于一个场景。同一个场景的Entity之间可以直接调用相互的函数,而跨场景的Entity之间需要使用RPC来进行通信。Entity可以通过迁移(Migrate)函数来跳转到别的场景中,跳转场景后Entity的所有属性数据都将保持不变。
AOI
GoWorld提供了一套简化的AOI机制。同场景的Entity之间会根据距离维护一个邻居列表。GoWorld使用十字列表维护场景里的所有Entity,从而根据Entity的位置变化实时更新所有Entity的AOI信息。
属性同步
GoWorld为Entity提供了属性机制。属性分为服务端属性、客户端属性和全局属性。服务端属性只有在服务端可以访问,客户端属性可以在客户端和服务端同时访问。每次服务端对其进行修改的时候,属性的变化会立刻被同步到客户端,从而保持客户端数据的实时更新。全局属性是对所有Entity都可见的数据,包括其他玩家。全局属性在发生变化的时候会被广播到AOI范围内的所有玩家,从而使得玩家可以实时获取AOI范围内其他Entity的属性变化。
Entity自动存盘
GoWorld支持Entity的自动存盘。持久化(persistent)的Entity会按一定的时间间隔进行存盘。GoWorld还提供了对已存盘Entity的载入功能。目前GoWorld支持MongoDB和Redis两种不同的底层数据库。
客户端连接和通信
每个server都会创建一个监听端口用于接收来自客户端的连接。客户端和服务端之间也采用一个RPC的通信方式。客户端可以对玩家和玩家AOI里的其他Entity发起RPC调用。
GoWorld支持对客户端通信进行压缩。加密功能还有待添加。。。
适用场合
GoWorld游戏服务器引擎的开发目标是能够很好地支持常见的MMORPG类游戏。在这类游戏里,玩家往往控制一个角色,并可以在不同的场景之间进行切换,并且通过和周围的其他对象(包括NPC、怪物、其他玩家等)进行交互进行游戏内容。GoWorld所提供的场景-对象机制能够很好地支持这些功能。对于其他类似卡牌、棋牌类游戏,也可以使用GoWorld提供的对象机制进行逻辑开发。
安装和运行
下载GoWorld游戏服务器
请前往github下载GoWorld:https://github.com/xiaonanln/goworld/
或者使用go get工具:
go get github.com/xiaonanln/goworld
下载GoWorld依赖的库
go get -u github.com/xiaonanln/go-xnsyncutil/xnsyncutilgo get -u github.com/xiaonanln/goTimergo get -u github.com/xiaonanln/typeconvgo get -u golang.org/x/net/contextgo get -u github.com/Sirupsen/logrusgo get -u github.com/garyburd/redigo/redisgo get -u github.com/google/btreego get -u github.com/pkg/errorsgo get -u gopkg.in/eapache/queue.v1go get -u gopkg.in/ini.v1go get -u gopkg.in/mgo.v2go get -u gopkg.in/vmihailenco/msgpack.v2go get -u gopkg.in/natefinch/lumberjack.v2
运行GoWorld测试服务端和客户端
1. 启动MongoDB或者Redis作为数据库
2. 拷贝goworld.ini.sample为goworld.ini,并进行配置
编译并运行中心分发器(dispatcher)
make dispatcher
components/dispatcher/dispatcher
4. 编译并运行网关服务器(gate)
make gate
components/gate/gate -gid 1
5. 编译并运行测试逻辑服务器(test_game)
make test_game
examples/test_game/test_game -gid 1
make test_clientexamples/test_client/test_client -N 500
还在开发阶段,更多内容有待补充,敬请关注 ……
QQ讨论群:662182346