2016.9.12 游戏服务器基础设计文档和规范
基本概述
- Java作为主要开发语言
- 游戏服务器为单进程多线程的结构
- 项目采用gradle进行构建
- 数据库为mysql 5.7
- 网络层采用netty 4.1.4.Final
- 协议层采用protobuf-java 3.0.0
- 数据层目前采用spring-jdbc 4.3.2.RELEASE
- 支持hotswap(通过类重定义实现)
- 支持在线执行逻辑代码(在内存中执行一段逻辑代码)
- 支持游戏逻辑脚本(通过groovy作为内置脚本)
线程模型
- 主逻辑线程
- 目前主要执行玩家不在场景的逻辑以及后续的一些全局逻辑业务
- 直接利用JDK自带的单线程池实现
- 逻辑线程池
- 提供了两个模型,"分线"和"分场景"两种模型
- 分线模型即客户端与server建立连接后即将某个玩家固定到某个线程
- 分场景模型即根据场景进行划分,一个线程管理多个场景
- 尽量保证每个玩家的逻辑是单线程的
- 玩家之间的交互通过互相投递消息来实现
- 消息是放在玩家的消息队列中然后通过外部的线程驱动来执行消息
- 场景、分线调度线程
- 用来驱动整个游戏逻辑
- tick/heartbeat
- 目前基于固定sleep
- 异步线程池
- 所以的io耗时操作全部在异步线程池执行,然后异步回调调用线程
- 防止阻塞逻辑线程
- 如数据库操作,网络层操作,本地磁盘操作
- 调度线程
- IO线程池
Tick
while(!stop)
{
sceneExecutors.foreach(sceneExecutor.manageScenes.forEach(scene.tick))
sleep(25)
println isDoneAllIn25ms
sceneExecutors.foreach(sceneExecutor.manageScenes.forEach(scene.tick))
sleep(25)
if(isNotDoneAll) println "busy"
}
processMessage
-> 遍历场景内玩家身上的消息队列,每次最多处理15条
processHeartBeat
-> 处理场景内玩家的心跳
处理和关键相关的业务心跳
-> 处理场景内其他心跳(npc、怪物等)
if(player.isNotInScene)
主线程执行该消息
else
消息直接扔到玩家的消息队列(由玩家所在的场景的线程去执行)
逻辑开发人员如何写逻辑
- 制订协议和时序图
- 由server制订逻辑协议,编辑.proto,主要是定义协议号和协议号对应的消息体
- server制订逻辑时序图交互
- 和客户端同学根据协议和时序图以及逻辑来修改和确定协议和时序图
- server将协议源文件上传,通知客户端更新(外链),通过工具生成客户端协议
- server端也根据协议工具直接将协议生成在cavs-game-proto工程
- 双方各自开发、调试
- 建议server端核心逻辑和关键模块要画类图
- server实际开发
- MessageType中注册消息号、消息体和消息处理器三者之间的关系即可
- 从消息处理器写逻辑即可
- 目前大部分逻辑不用担心线程安全问题,比如单个玩家的逻辑,多个在同一个场景的玩家交互逻辑等
- 建议和玩家的逻辑管理器全部挂在角色上,如背包管理器、货币管理器等
- xxManager,xx为逻辑模块
- 该业务的逻辑数据并提供基础方法
- 消息处理器调用逻辑管理器的相关方法
- 建议非玩家个人逻辑以xxService命名,xx为逻辑模块
- 两个玩家不在同一个场景之间的逻辑交互通过玩家之间的消息队列互相投递消息实现
- 尽量面向接口编程
- 时序图例子
待优化及改进
- 无锁队列的引入
- 分布式日志系统的引入
- tick模型的优化
- 根据压力测试决定是否拆分多进程(更方便的扩展为多进程)
- 服务器的性能基准测试
- 引入缓存中间层
网友评论