moon介绍
moon
是一个轻量级在线游戏服务器框架,基于 Actor
模型构建,秉承 "Keep it simple, stupid" 设计原则。通过精简的核心代码实现了 Actor 调度系统和 Lua API 封装。
后续文章中用
服务
(Lua Service
)来代表Actor
。
核心特性
框架优势
- 核心代码精简,易于学习和掌握
- 全平台支持(Windows、Linux、MacOS)
- 完整的网络协议支持体系
- TCP
- UDP/KCP
- WebSocket
- HTTP
- 基于 Lua 协程实现的全套异步功能:
- 协程 Socket
- 定时器系统
- 服务间通信
- 进程内通信
- 集群间通信
- 异步数据库驱动
- Redis
- MySQL
- PostgreSQL
- MongoDB
- 性能优化组件
- 高性能 JSON 处理
- Protocol Buffers 支持
- 文件系统操作
- RecastNavigation 寻路
- ZSet 排行榜
架构设计
moon
设计时希望能充分利用多核的优势,采用了单进程多线程模式。为了简化设计,使用Asio
库作为网络和线程通信的基础组件,Asio
是一个成熟的跨平台异步IO库,使我们不必关心平台相关的细节,把复杂度限制在可控的范围内。moon
采用了One Thread One IoContext
的线程调度模型,Lua
服务作为Actor
的载体,每个线程可以有一个或者多个Lua Service
,这样的好处是可以实现独占线程服务和共享线程服务:
-
独占线程服务 可以表示运行期常驻的服务,如网关,DB Proxy等,这种服务很容易成为整个系统的的热点,希望它们能独占线程,提高响应能力,避免受到其它服务调度的影响
-
共享线程服务 可以表示运行期间动态创建和销毁的服务,如一个玩家,一个组队副本场景等,这种服务功能上通常彼此之间是独立的,天然可拆分,可以多线程负载提高处理能力
moon
提供的核心功能就是创建服务,并为它提供一个进程内不重复的ID
, 服务间可以互相发送消息, 每个服务可以注册消息回调,来接收发送给它的消息, 每个服务都是被消息驱动的, 定时器
也是一种消息。对于单个游戏服,推荐把业务逻辑尽量集中在同一个(节点)进程中, 按需求拆分不同的服务
,这些服务协同工作构成单个游戏服务器节点进程,多个节点进程组成游戏服务器集群。服务间通信不必时刻关心对方是否还活着,通讯数据能否正确到达等问题。进程内的所有服务是同生共死的,对于游戏业务某个环节出了错都可能都是致命的,没必要把问题隐藏起来, 系统处于不完整状态可能会造成更大的损害。框架采用Lua
编写逻辑代码C++
编写少量核心库的开发方式,Lua
作为脚本语言弥补了C++
开发效率低,对于健壮性,采用Lua
沙盒基本上能隔绝逻辑层的bug。
在Lua
层API
的封装参考了skynet
, 所以和skynet
有许多相似的地方, moon
和skynet
最大区别是的调度方式,skynet
使用了调度队列和服务消息队列实现了近似均衡的调度,同一个服务可能会切换不同的线程间调度(One queue, many processors)。
moon
每个线程都拥有自己的消息队列(Many processors, each with their own run queue),服务是固定在某个线程中的,这样就可以独占或共享线程,独占线程的服务可以有更高的响应能力
,并且不受其他服务的影响。对于游戏业务,一般会出现难以拆分的热点服务, 如大地图战斗场景,这种服务的处理能力往往就是游戏服务器的上限,独占线程能最大程度发挥这种服务的性能。而服务切换不同线程调度,往往会降低响应能力,影响处理性能。
核心概念
游戏服务器面临的主要问题包括进程间通信和逻辑模块之间的通信。在进程层面,需要处理与客户端、服务器集群、数据库和平台之间的远程过程调用。在逻辑层面,需要划分模块并确保它们之间的通信便利且高效,以利用多核CPU。moon
通过抽象出三大基础设施来处理这些问题:
-
节点(Node)
- 表示独立 Moon 进程
- 通过
cluster.send/call
实现进程间服务通信
-
服务(Service)
- Actor 的载体
- 通过
moon.send/call
实现进程内服务间通信
-
模块(Module)
- 服务内逻辑单元
- 通常对应单个 Lua 文件
这三大设施也是灵活搭建不同类型游戏的基础。示例DEMO可以作为参考,你也可以基于它实现适合自己游戏类型的服务器。