【游戏后端】游戏服务器端开发的⼀些建议
摘要: 本⽂作为游戏服务器端开发的基本⼤纲,是游戏实践开发中的总结。第⼀部分专业基础,⽤于指导招聘和实习考核, 第⼆部分游戏⼊门,讲述游戏服务器端开发的基本要点,第三部分服务端架构,介绍架构设计中的⼀些基本原则。希望能帮到⼤家
⼀专业基础
1.1 ⽹络
1.1.1 理解TCP/IP协议
⽹络传输模型
滑动窗⼝技术
建⽴连接的三次握⼿与断开连接的四次握⼿
连接建⽴与断开过程中的各种状态
TCP/IP协议的传输效率
思考
1)请解释DOS攻击与DRDOS攻击的基本原理
2)⼀个100Byte数据包,精简到50Byte, 其传输效率提⾼了50%
3)TIMEWAIT状态怎么解释?
1.1.2 掌握常⽤的⽹络通信模型
Select
Epoll,边缘触发与平台出发点区别与应⽤
Select与Epoll的区别及应⽤
1.2 存储
计算机系统存储体系
程序运⾏时的内存结构
计算机⽂件系统,页表结构
内存池与对象池的实现原理,应⽤场景与区别
游戏免费源码分享网站
关系数据库MySQL的使⽤
共享内存
1.3 程序
对C/C++语⾔有较深的理解
深刻理解接⼝,封装与多态,并且有实践经验
深刻理解常⽤的数据结构:数组,链表,⼆叉树,哈希表
熟悉常⽤的算法及相关复杂度:冒泡排序,快速排序
⼆游戏开发⼊门
2.1防御式编程
不要相信客户端数据,⼀定要检验。作为服务器端你⽆法确定你的客户端是谁,你也不能假定它是善意的,请做好⾃我保护。(这是判断⼀个服务器端程序员是否⼊门的基本标准)
务必对于函数的传⼈参数和返回值进⾏合法性判断,内部⼦系统,功能模块之间不要太过信任,要求低耦合,⾼内聚
插件式的模块设计,模块功能的健壮性应该是内建的,尽量减少模块间耦合
2.2 设计模式
道法⾃然。不要迷信,迷恋设计模式,更不要⽣搬硬套
简化,简化,再简化,⽤最简单的办法解决问题
借⼤宝⼀句话:设计本天成,妙⼿偶得之
2.3 ⽹络模型
⾃造轮⼦: Select, Epoll, Epoll⼀定⽐Select⾼效吗?
开源框架: Libevent, libev, ACE
2.4 数据持久化
⾃定义⽂件存储,如《梦幻西游》
关系数据库: MySQL
NO-SQL数据库: MongoDB
选择存储系统要考虑到因素:稳定性,性能,可扩展性
2.5 内存管理
使⽤内存池和对象池,禁⽌运⾏期间动态分配内存
对于输⼊输出的指针参数,严格检查,宁滥勿缺
写内存保护。使⽤带内存保护的函数(strncpy, memcpy, snprintf, vsnprintf等),严防数组下标越界
防⽌读内存溢出,确保字符串以’\0’结束
2.6 ⽇志系统
简单⾼效,⼤量⽇志操作不应该影响程序性能
稳定,做到服务器崩溃是⽇志不丢失
完备,玩家关键操作⼀定要记⽇志,理想的情况是通过⽇志能重建任何时刻的玩家数据
开关,开发⽇志的要加级别开关控制
2.7 通信协议
采⽤PDL(Protocol Design Language), 如Protobuf,可以同时⽣成前后端代码,减少前后端协议联调成本, 扩展性好
JSON,⽂本协议,简单,⾃解释,⽆联调成本,扩展性好,也很⽅便进⾏包过滤以及写⽇志
⾃定义⼆进制协议,精简,有⾼效的传输性能,完全可控,⼏乎⽆扩展性
2.8 全局唯⼀Key(GUID)
为合服做准备
⽅便追踪道具,装备流向
每个⾓⾊,装备,道具都应对应有全局唯⼀Key
2.9 多线程与同步
消息队列进⾏同步化处理
2.10 状态机
强化⾓⾊的状态
前置状态的检查校验
2.11 数据包操作
合并, 同⼀帧内的数据包进⾏合并,减少IO操作次数
单副本, ⽤⼀个包尽量只保存⼀份,减少内存复制次数
AOI同步中减少中间过程⽆⽤数据包
2.12 状态监控
随时监控服务器内部状态
内存池,对象池使⽤情况
帧处理时间
⽹络IO
包处理性能
各种业务逻辑的处理次数
2.13 包频率控制
基于每个玩家每条协议的包频率控制,瘫痪变速齿轮
2.14 开关控制
每个模块都有开关,可以紧急关闭任何出问题的功能模块
包频率控制可以消灭变速齿轮
包id⾃增校验,可以消灭WPE
包校验码可以消灭包拦截篡改
图形识别吗,可以踢掉99%⾮⼈的操作
魔⾼⼀尺,道⾼⼀丈
2.16 热更新
核⼼配置逻辑的热更新,如防沉迷系统,包频率控制,开关控制等代码基本热更新,如Erlang,Lua等
2.17 防刷
关键系统资源(如元宝,精⼒值,道具,装备等)的产出记⽇志资源的产出和消耗尽量依赖两个或以上的独⽴条件的检测
严格检查各项操作的前置条件
校验参数合法性
2.18 防崩溃
系统底层与具体业务逻辑⽆关,可以⽤⼤量的机器⼈压⼒测试暴露各种bug,确保稳定
业务逻辑建议使⽤脚本
系统性的保证游戏不会崩溃
2.19 性能优化
IO操作异步化
IO操作合并缓写 (事务性的提交db操作,包合并,⽂件⽇志缓写)
Cache机制
减少竞态条件 (避免频繁进出切换,尽量减少锁定使⽤,多线程不⼀定由于单线程) 多线程不⼀定⽐单线程快
减少内存复制
⾃⼰测试,⽤数据说话,别猜
2.20 运营⽀持
接⼝⽀持:实时查询,控制指令,数据监控,客服处理等
实现考虑提供Http接⼝
2.21 容灾与故障预案
三服务器端架构
3.1 什么是好的架构?
满⾜业务要求
能迅速的实现策划需求,响应需求变更
系统级的稳定性保障
简化开发。将复杂性控制在架构底层,降低对开发⼈员的技术要求,逻辑开发不依赖于开发⼈员本⾝强⼤的技术实⼒,提⾼开发效率
完善的运营⽀撑体系
3.2 架构实践的思考
简单,满⾜需求的架构就是好架构
设计性能,抓住重要的20%, 没必要从程序代码⾥⾯去抠性能
热更新是必须的
⼈难免会犯错,尽可能的⽤⼀套机制去保障逻辑的健壮性
游戏的设计是⼀项颇有挑战性的⼯作,游戏服务器的发展也由以前的单服结构转变为多服机构,甚⾄出现了bigworld引擎的解决⽅案,最近了解到Unreal的服务器解决⽅案atlas也是基于集的⽅式。
是⼀个很复杂的课题,这⾥暂不谈bigworld和atlas的这类服务器的设计,更多的是基于功能和场景划分服务器结构。
⾸先说⼀下思路,服务器划分基于以下原则:
1. 分离游戏中占⽤系统资源(cpu,内存,IO等)较多的功能,独⽴成服务器。
2. 在同⼀服务器架构下的不同游戏,应尽可能的复⽤某些服务器(进程级别的复⽤)。
3. 以多线程并发的编程⽅式适应多核处理器。
4. 宁可在服务器之间多复制数据,也要保持清晰的数据流向。
5. 主要按照场景划分进程,若需按功能划分,必须保持整个逻辑⾜够的简单,并满⾜以上1,2点。
服务器结构图:
各个服务器的简要说明:
Gateway 是应⽤⽹关,主要⽤于保持和client的连接,该服务器需要2种IO,对client采⽤⾼并发连接,低吞吐量的⽹络模型,如IOCP等,对服务器采⽤⾼吞吐量连接,如阻塞或异步IO。
⽹关主要有以下⽤途:
1. 分担了⽹络IO资源
2. 同时,也分担了⽹络消息包的加解密,压缩解压等cpu密集的操作。
3. 隔离了client和内部服务器组,对client来说,它只需要知道⽹关的相关信息即可(ip和port)。
4. client由于⼀直和⽹关保持常连接,所以切换场景服务器等操作对client来说是透明的。
5. 维护玩家登录状态。
World Server 是⼀个控制中⼼,它负责把各种计算资源分布到各个服务器,它具有以下职责:
1. 管理和维护多个Scene Server。
2. 管理和维护多个功能服务器,主要是同步数据到功能服务器。
3. 复杂转发其他服务器和Gateway之间的数据。
4. 实现其他需要跨场景的功能,如组队,聊天,帮派等。
Phys Server 主要⽤于玩家移动,碰撞等检测。
所有玩家的移动类操作都在该服务器上做检查,所以该服务器本⾝具备所有地图的地形等相关信息。具体检查过程是这样的:⾸
先,Worldserver收到⼀个移动信息,WorldServer收到后向Phys Server请求检查,Phys Server检查成功后再返回给world Server,然后world server传递给相应的Scene Server。
Scene Server 场景服务器,按场景划分,每个服务器负责的场景应该是可以配置的。理想情况下是可以
动态调节的。
ItemMgr Server 物品管理服务器,负责所有物品的⽣产过程。在该服务器上存储⼀个物品掉落,服务器初始化的时候载⼊到内存。任何需要产⽣物品的服务器均与该服务器直接通信。
AIServer ⼜⼀个功能服务器,负责管理所有NPC的AI。AI服务器通常有2个输⼊,⼀个是Scene Server发送过来的玩家相关操作信息,另⼀个时钟Timer驱动,在这个设计中,对其他服务器来说,AIServer就是⼀个拥有很多个NPC的客户端。AIserver需要同步所有与AI相关的数据,包括很多玩家数据。由于AIServer的Timer驱动特性,可在很⼤程度上使⽤TBB程序库来发挥多核的性能。
把⽹络游戏服务器分拆成多个进程,分开部署。这种设计的好处是模块⾃然分离,可以单独设计。分担负荷,可以提⾼整个系统的承载能⼒。
缺点在于,⽹络环境并不那么可靠。跨进程通讯有⼀定的不可预知性。服务器间通讯往往难以架设调试环境,并很容易把事情搅成⼀团糨糊。⽽且正确⾼效的管理多连接,对来说也是⼀项挑战。
前些年,我也曾写过好⼏篇与之相关的设计。这⼏天在思考⼀个问题:如果我们要做⼀个底层通⽤模块,让后续开发更为⽅便。到底要解决怎样的需求。这个需求应该是单⼀且基础的,每个应⽤都需要的。
正如 TCP 协议解决了互联⽹上稳定可靠的点对点数据流通讯⼀样。游戏世界实际需要的是⼀个稳定可靠的在游戏系统内的点对点通讯需要。
我们可以在⼀条 TCP 连接之上做到这⼀点。⼀旦实现,可以给游戏服务的开发带来极⼤的⽅便。
可以把游戏系统内的各项服务,包括并不限于登陆,拍卖,战⽃场景,数据服务,等等独⽴服务看成⽹络上的若⼲终端。每个玩家也可以是⼀个独⽴终端。它们⼀起构成⼀个⽹络。在这个⽹络之上,终端之间可以进⾏可靠的连接和通讯。
实现可以是这样的:每个虚拟终端都在游戏虚拟⽹络(Game Network)上有⼀个唯⼀地址 (Game Network Address , GNA) 。这个地址可以预先设定,也可以动态分配。每个终端都可以通过游戏⽹络的若⼲接⼊点 ( GNAP ) 通过唯⼀⼀条 TCP 连接接⼊⽹络。接⼊过程需要通过鉴权。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。