游戏服务端架构发展史
手游、页游和端游本质上并无区别,主要差异在于游戏类型。以下将详细介绍不同类型游戏的服务端架构发展历程。
类型 1:卡牌、跑酷等弱交互服务端
卡牌、跑酷类游戏交互性较弱,玩家之间无需实时面对面 PK,只需对对方的离线数据进行操作、计算排行榜以及买卖道具等。因此,这类游戏的服务端实现通常采用简单的 HTTP 服务器。
登录加密机制
登录时采用非对称加密(如 RSA、DH)。服务器根据客户端的 uid、当前时间戳以及服务端私钥,计算哈希得到加密 key 并发送给客户端。之后,双方通过 HTTP 进行通信,并使用该 key 进行 RC4 加密。客户端收到 key 和时间戳后将其保存在内存中,用于后续通信;而服务端无需保存 key,因为每次都可根据客户端上传的 uid、时间戳以及自身私钥重新计算得出。通过模仿 TLS 的行为,可保证多次 HTTP 请求间的客户端身份,同时利用时间戳确保同一人两次登录的密钥不同。
游戏流程与数据存储
每局游戏开始时,客户端向服务器请求关卡数据;游戏结束后,提交游戏结果,服务器验算其合法性并给予相应奖励。数据库可选用单台 MySQL 或 MongoDB,后端的 Redis 可作为缓存(可选)。若要实现通知功能,可让客户端定时轮询服务器,初始轮询时间为 15 秒,若有消息则缩短轮询时间至 10 秒、5 秒;若无消息则逐步延长轮询时间,如 30 秒。即便两人聊天,该机制也能自适应延迟。
优势
此类服务器足以支持三国类策略、卡牌及酷跑等游戏的开发。由于游戏逻辑简单,玩家间交互不强,使用 HTTP 开发可加快开发速度,调试时仅需一个浏览器即可理清逻辑。
类型 2:第一代游戏服务器(1978 年)
1978 年,英国 Essex 大学的学生 Roy Trubshaw 编写了世界上第一个 MUD 程序《MUD1》。1980 年,Essex 大学接入 ARPANET 后,该程序吸引了众多外部玩家,包括国外玩家。《MUD1》的源代码在 ARPANET 上共享后,出现了众多改编版本,MUD 游戏也因此在全球广泛流行。基于不断完善的 MUD1,1991 年开源的 MudOS 诞生,它成为众多网游的鼻祖。
MUDOS 架构特点
- 单线程无阻塞套接字:MUDOS 采用 C 语言开发,由于玩家之间交互较强(如聊天、交易、PK),它使用单线程无阻塞套接字为所有玩家提供服务。所有玩家的请求都由同一个线程处理,主线程每隔 1 秒钟更新一次所有对象,包括网络收发、更新对象状态机、处理超时、刷新地图和 NPC 等。
- 房间式游戏世界:游戏世界以房间为基本单位组织,每个房间有东南西北四个方向可通往其他房间。早期欧美网游多为地牢迷宫形式,因此场景的基本单位被称为“房间”。MUDOS 使用 LPC 脚本语言描述整个游戏世界,包括房间拓扑、配置、NPC 以及各种剧情。高级玩家(巫师)可通过修改脚本为游戏添加房间和剧情。
- 文本交互方式:用户使用 Telnet 等客户端通过 TCP 协议连接到 MUDOS 上,以纯文字进行游戏,每条指令用回车分隔。例如,在 1995 年国内第一款 MUD 游戏《侠客行》中,玩家输入“go east”,游戏会提示当前房间信息;输入“look a mu”,可查看指定角色的信息。玩家可根据这些信息进行操作,如击败角色获取物品,但可能会面临相应后果。
- 用户数据存储:用户数据保存在文件中。用户登录时,从文本文件加载数据到内存;操作在内存中进行,无需立即写回磁盘。用户退出或每隔 5 分钟检查到数据改动时,将数据保存到磁盘。当时,每台服务器承载 4000 人同时游戏并非难事。
第一代图形网络游戏
1997 年,游戏《UO》在 MUDOS 的基础上,为角色增加了 x、y 坐标,为每个房间增加了地图,并为角色添加了动画,形成了第一代图形网络游戏。由于游戏内容可通过 LPC 脚本定制,MUDOS 成为名副其实的第一款服务端引擎。后续国内的《万王之王》等游戏,大多在 MUDOS 上进行二次开发,加入房间地图和角色坐标等要素。该架构一直为国内第一代 MMORPG 提供稳定支持,直到 2003 年仍有游戏基于 MUDOS 开发。然而,随着游戏内容日益复杂,MUDOS 架构逐渐难以承受,各种负载问题逐渐显现,于是催生了第二代游戏服务器。
类型 3:第二代游戏服务器(2003 年)
2000 年后,网游进入全面图形化时代。由于频繁读写小文件导致用户数据负载增大,同时早期 EXT 磁盘分区脆弱,停电易造成大面积数据丢失,因此第一步是将文件存储拆分到数据库中。
架构改进
- 服务端重写与脚本替换:游戏服务端脱离陈旧的 MUDOS 体系,各公司参考 MUDOS 结构,使用 C 语言重新开发游戏服务端。脚本语言也从 LPC 替换为扩展性更好的 Python 或 Lua。
- 游戏世界拆分:由于主逻辑采用单线程模型,随着游戏内容增加,传统单服务器结构成为瓶颈。因此,有人开始拆分游戏世界,将不同功能模块分离。
- 数据库前端代理:游戏服务器压力拆分后,两台游戏服务器同时访问数据库会导致大量重复访问和数据交换,使数据库成为新的瓶颈。为解决这一问题,引入了数据库前端代理(DB Proxy)。游戏服务器通过代理访问数据库,代理提供内存级别的缓存,并将高级数据操作指令转化为具体的数据库操作,一定程度上替代了存储过程(早期 MySQL 4 之前未提供存储过程)。
- 网关服务独立:玩家切换场景时,频繁切换连接易导致状态错乱,且游戏服务器增多后,数据交互变得复杂。为解决这些问题,将网络功能独立出来,形成网关服务(Gate,也称为 Session 或 LinkSvr 等)。用户统一连接到网关服务器,由网关服务器转发数据到后端游戏服务器,游戏服务器之间的数据交换也通过网关进行。这种架构可稳定为玩家提供游戏服务,一台网关服务可支持 1 - 2 万人,后面的游戏服务器每台可服务 5k - 1w 人,具体数量取决于游戏类型和复杂度。
架构扩展与挑战
随着经验积累,人们尝试进一步拆分架构,如拆分网关、基础服务(如聊天交易),并提供 web 接口,拆分数据库等。虽然有成功游戏采用类似架构并发挥了性能优势,但也面临两个挑战:一是每增加一级服务器,状态机复杂度可能翻倍,导致研发和调试成本上升;二是对开发组要求较高,项目时间紧张、开发人员经验不足时,容易导致项目失败。因此,在游戏成功率不高的情况下,选择架构时需考虑投资回报率,根据游戏实际情况选择合适的架构。
由于上述架构本质上是对 MUDOS 的拆分,因此将其归纳为第二代游戏服务器。
类型 4:第三代游戏服务器(2007 年)
自《魔兽世界》推出无缝世界地图后,该功能成为 2005 年以后大型 MMORPG 的标准配置。与以往按地图切割游戏不同,无缝世界中一块地图上的玩家不再仅由一台服务器处理。
架构设计
- 服务器层次结构:每台 Node 服务器管理一块地图区域,由 NodeMaster(NM)进行总体管理,更高层次的 World 提供大陆级别的管理服务。为简化描述,省略了传统数据库前端、登录服务器、日志和监控等细节服务器,统一用 ADMIN 概括。
- 玩家区域管理:玩家在不同区域间移动时,需进行相应处理。例如,玩家 1 完全由节点 A 控制,玩家 3 完全由节点 B 控制;处于两个节点边缘的玩家 2 同时由 A 和 B 提供服务。玩家 2 从 A 移动到 B 的过程中,会同时向 A 请求左边情况,向 B 请求右边情况,但仍由 A 管理,直到彻底离开 AB 边界后,才交由 B 管理。根据此逻辑,将世界地图分割为多个区域,由不同的 Node 服务器管理。一个 Node 管理的区域在地理上无需相连,可根据游戏实时负载情况,在定时维护时更改 NodeMaster 上的配置。
架构优化
- 用户对象切割:随着服务器种类增加和玩家移动频繁,按 UID 查找玩家和 GATE 动态计算与 Node 通信的逻辑变得复杂。为解决这些问题,将“用户对象”从负责连接管理的 GATE 中切割出来,由按照 UID 划分的 OBJ 服务器承担用户逻辑。GATE 按网络接入负载分布,OBJ 按资源编号(UID)分布,与用户通信时可直接根据 UID 计算 OBJ 服务器编号并发送数据。
- OBJ 服务器功能:新独立的 OBJ 服务器提供了更多高层次服务,包括对象移动管理、数据广播、对象消息推送和好友聊天等。
- 动态负载均衡:为解决负载问题,引入了动态负载均衡机制。有两种实现方法:一是由 Node Master 定时动态移动修改各个 Node 的边界,将玩家对象从一台 Node 迁移到另一台 Node;二是将地图均匀切割成静态网格,每个格子由一个 Node 负责,根据负载情况实时迁移到其他 Node 上。迁移过程分为准备、切换、完成三个阶段,由 Node Master 负责维护。
架构特点与局限性
虽然无缝地图引入分布式对象模型后,第三代游戏服务端架构完全脱离了 MUDOS 体系,并通过动态负载均衡提高了服务器性能和游戏体验,可容纳超过上一代服务器数倍的人数上限,但该体系仍受网络带宽和客户端性能的限制,MMORPG 游戏的人数上限无法无限扩充。
类型 5:战网游戏服务器
战网游戏服务器与 RPG 游戏服务器有本质区别。RPG 游戏分区分服,不同区的用户无法互动;而战网游戏全国只有一套服务器,所有玩家可一起游戏,玩家之间采用 P2P 方式连接。
游戏连接与同步
- 游戏组队方式:玩家通过 Match Making 服务器创建、加入、自动匹配或邀请其他玩家组成一局游戏。服务器会选择一个玩家作为 Host,其他玩家通过 P2P 连接到 Host 上。STUN 作为牵引服务器,帮助玩家建立 P2P 连接;若 P2P 连接失败,可通过 Forward 进行转发。
- P2P 模型选择:P2P 有网状模型和星状模型。由于复杂游戏状态在网状模型下难以达成一致,星状 P2P 模型更具优势。支持语音的战网系统会将语音数据发送到 Host 机器上,经过混音、去重和再编码后返回给所有用户。
游戏结果公正保障
战网类游戏以竞技、体育、动作等类型为主,游戏同步策略复杂,很多游戏结果由客户端直接计算得出。为保证游戏结果公正,主要采用投票法。所有客户端独立计算结果并传递给服务器,若结果相同则更新记录;若结果不一致,则通过投票确定最终结果。同时,记录本局游戏的所有输入,在可能的情况下,找其他游戏客户端验算整局游戏结果,并记录有作弊嫌疑的用户供运营人员参考。
类型 6:休闲游戏服务器
休闲游戏服务器采用全区架构,与战网服务器类似,但增加了房间服务器和具体的游戏服务器,游戏主体不再依赖玩家 P2P 连接,而是连接到专门的游戏服务器处理。
用户数据管理
由于全区架构下用户可能同时玩多个游戏,用户数据需区分基本数据和不同的游戏数据,游戏数据又分为积分数据和文档数据。胜平负等积分数据可直接提交增量修改,文档类数据则需提供读写令牌。写令牌只有一个,读令牌有多个。当同一账号在两台电脑上同时玩同一个游戏时,先开始的游戏获得写令牌,可操作任意用户数据;后开始的游戏除提交积分增量外,对用户数据采用只读方式,并提示用户游戏数据锁定。
类型 7:现代动作网游
现代动作网游融合了传统战网动作类游戏和 RPG 游戏的特点,形成了“动作 + 城镇”模式。玩家在城镇中聚集,通过开副本的方式以动作游戏玩法完成各种 RPG 任务。其本质是一套 RPG 服务端加副本服务端的架构,由于每次副本人数可控制在 8 人以内,玩家可获得更实时的游戏体验。
综上所述,游戏服务端架构经历了从简单到复杂、从单机到分布式的发展过程。不同类型的游戏根据自身特点和需求,选择合适的服务端架构。未来,游戏服务端架构将如何发展,开发模式是否会有新的突破,这些问题值得我们进一步关注。敬请期待下节内容。