“和学霸一起学”栏目每周推送游戏相关的专业课程内容,通过相对专业、体系的知识内容,帮助大家提升对游戏的认识水平和理解力。本篇内容源于由清华大学美术学院与腾讯游戏学院联合制作“游戏程序设计”系列课程,课程名称为《游戏服务器概述》(讲师:孙峻,高璐)。文末还设有学习互动环节,欢迎参与赢取奖励!
游戏程序开发有两个大方向,包括前端和后端。其中,前端是指客户端方面,包括PC、手机和平板上面的可视化图形技术。后端则偏向于服务器,即用户不可见的部分。
本文将通过游戏服务器的起源、功能特点、分类和发展历史,以及系统架构、开发核心技术和难点、设计原理等方面来介绍后端的服务器技术。
#01
游戏服务器概述
概念及起源
游戏服务器,是服务器硬件和软件的结合。其中,硬件负责承载游戏服务,软件则提供游戏服务。
游戏服务器的出现,是因为玩家对游戏有三个方面的需求。
第一,是游戏性的需求。
最早的游戏机,更讲究单局游戏的体验和过程,不可以存储进度。这种单局过关的游戏性,来自于用户体验的提升,来自于玩家对技能、关卡熟悉程度。随着用户体验时间的增长,这类游戏对玩家来说会变得容易,游戏性就会被消耗掉。
随后出现了一些可存档的游戏。比如,红白机上有了最早的可存盘游戏——《三国志:霸王大陆》。网络刚开始兴起的时代,PC端的游戏也是可以存储一些进度的。但当时的网吧基于安全需求,在玩家使用电脑后重置机器,游戏内容就会被清空。从游戏性的需求来看,玩家希望换电脑也能够继续游戏进度。为了解决这个问题,设计者就需要把玩家的数据和剧情放到网络服务上。
第二,是多人联机的需求。
单机游戏有它的乐趣,但更多时候,玩家与玩家之间的互动可以产生更多变化。比如,斗地主这个传统游戏,一共只有52张牌,三个人玩却可以有无数种玩法。为了实现这个需求,一般可以用中转的电脑来转发用户的数据和状态操作。这个操作不局限于用服务器来实现,在局域网上,一些互相转发的方式也同样可以实现。
第三,是保证游戏公平性的需求。
通常,游戏防止玩家作弊的方式就是引入第三方电脑裁判。
上述三个需求驱动了游戏服务器的诞生,它们同样也是游戏服务器的主要功能。此外,游戏服务器还有一个重要功能——充值。
功能
游戏服务器的功能,主要有四个。
(1)包括终端网络连接的建立和会话维护在内的网络服务。
有了终端和前端间的网络连接,才能实现前端后端的交互。而会话维护,主要指用户的登录和登出,同时也是该用户在服务器上的一个生命周期。会话维护还包括断线重连,这一问题在PC端不太容易出现,但在手游端会经常发生网络的切换(WIFI和WIFI、4G基站之间),这些都会导致玩家网络掉线。会话维护使得网络掉线后,玩家在服务器上的生命周期也不会消失。
(2)用户数据的存取
数据读取,一般会发生在以下两个场景:一是登录。玩家登入服务器后,服务器会从存储读取。二是切换。比如,从大厅服务器切换到战斗服务器,也有可能从DB(database,或者文件系统)读取用户数据。
而一般的服务器技术采用三种存储方式:
① 用户下线存取。用户下线时,服务器会对数据进行回写。
② 定时回写。比如,每隔半分钟、每隔五分钟,把数据回写一次。
③ 重要数据立即回写。比如游戏里,玩家打了一个特别贵重、极其稀有的装备,或者涉及金钱交易的数据,都是会及时回写。这种方式是为了解决前两种存储方式可能导致的问题:如果异常掉电,那么服务器会出现异常,导致用户数据丢失。
(3)游戏的逻辑计算。
采用服务器技术后,一些以前单机上实现的前端计算,被放到了后端。这也是为了防止作弊,以及解决以前存在的一些问题。比如,在FPS(第一人称射击游戏)中,玩家是否命中的判断是在前端,但命中后产生的伤害,包括护甲、免伤等数据,都要通过逻辑计算。以前的逻辑计算都是在客户端进行,不可避免地会有作弊的可能。如今,逻辑计算都在服务器进行,减少了作弊的可能性。
(4)是用户行为或状态变化的同步。
在网络游戏中,玩家在用户端的视野范围内,可以看到其他玩家或怪物、NPC(非玩家角色)的动作行为。这种真实世界的模拟,就需要各角色行为和状态的同步变化,这就是后端服务器的功能之一。
特点
游戏服务器虽然是互联网服务的一种,但相对互联网服务有一些自己的特点:
第一是,延迟敏感。延迟指玩家操作动作、发出指令,和动作在画面上呈现图像反馈到视觉,之间有一定的时间差。
第二是,实时的高强度交互。单次请求会产生很多服务器的逻辑,还有一些广播和同步。服务器承受的最大压力的逻辑是移动同步。比如,假设玩家在一个20人左右的场景里,每移动一步,客户端1s之内大概会发出5个移动包(假设),表示玩家方向或移动目标点的改变。对于其他用户来说,服务器也要实时同步,相当于消息量会放大20倍。这对服务器来说,是很高强度的交互。
第三是,业务逻辑复杂,内部耦合度高。由于游戏服务器具有延迟敏感和交互高强度的特点,这决定了服务器的状态维护是一个必然的过程,也导致了逻辑的复杂性。举例来讲,玩家击杀一个怪物,在服务器端,逻辑不仅仅是击杀一个怪物,也可能会触发一个任务,比如玩家今天要击杀15个怪物,这样类似的逻辑。
第四是,变更频度高、幅度大。手游时代,游戏的更新频率非常快,内容非常多。因此,服务器的更新和灰度部署要求会更高。
#02
游戏服务器的发展
网络游戏发展史
上世纪七十年代末,网络游戏最早是文字MUD和UNIX网络同步出现。
之后,八十年代末到九十年代初,局域网连接的游戏出现,最早是《沙丘》,其次是《红警》、《魔兽2》和《DOOM》。
到九十年代末,出现了Diablo(《暗黑破坏神》)战网。
1997年,金山发布了一款比较有名的RPG类(角色扮演)游戏《剑侠情缘》。当时,《剑侠情缘》还是单机版的。后来在2003、2005和2009年,分别发布了网络版的1代、2代和3代。
1998年,主打休闲游戏的联众游戏成立。
2000年左右,MMOG(大型多人在线游戏)《传奇》登陆中国。
2004年,《魔兽世界》(WOW)出现。
2006-2010年,手游兴起。莉莉丝游戏做出了一个比较成功的手游产品——《刀塔传奇》。
2010至今,就是休闲类的《纪念碑谷》、网易次元文化的《阴阳师》,再到如今大热的MOBA类(多人在线战术竞技游戏)的对战手游《王者荣耀》。
游戏服务器的发展
第一代游戏服务器,是比较简单的单进程、单线程模型,无阻塞。服务器在接收到玩家的消息后,把消息按照队列进行异步的序列化。
这种单线程的服务器模型,最早的是类似于78年的MUD游戏。使用终端模拟程序telnet等,就可以直接登录。进入场景之后主要采用文字叙述的方式,即服务器告诉玩家在什么场景、有什么数据,然后玩家输入指令。早期的服务器,虽然没有很强的逻辑,但因为整体构架比较简单,所以承载能力较低。
第二代游戏服务器,为了增加并发,在服务器端也发展了多线程和多进程的模型。在服务器本身的逻辑上,开始增加了分区分服的结构。
比较典型的游戏是上图中,EA(美国艺电公司)旗下公司在1997年发布的《Ultima Online》,即《创世纪》。它是世界上第一款图形界面的大型多人在线角色扮演游戏。
此外,还有联众在2000年推出的休闲棋牌游戏。当时,联众跟地方的运营商(电信、联通等)合作,搭建游戏服务器。所以在游戏中,会有南方电信1、北方联通1等分区。这体现了第二代游戏服务器架构典型的分区分服特点。
第三代游戏服务器,相对更百花齐放一些,主要有四种类型。
第一种类型,是在第二代的基础上发展而来,实现三层架构的游戏服务器。
首先,Gate server作为所有玩家的游戏连接,主要负责处理网络的IO部分。然后,通过内部的网络即IDC(互联网数据中心)专网,与游戏逻辑服务器相交互。最后,通过mysql或其他数据库,把用户数据存储到DB server。它的主要特点是,把网络和存储IO进行逻辑分离,可以对每一层进行扩展。一般负载的瓶颈大都在GameServer层,这层可以做更多的扩展,从而支持单区单服增加承载的能力。
2003年的QQGame,是比较典型的三层架构服务器代表。它当时是腾讯首款自研的游戏产品,最高达到过PC端八百多万人在线的成绩。QQGame很快就超越了联众,即使在现在的休闲棋牌市场上,也处于绝对领先的地位。
第二种类型,是服务器集群,上图是比较简单的示意图。
首先,也有与玩家连接的接入类服务器,这里命名为GATE,它负责处理专网连接,在游戏WORLD处理游戏逻辑。然后它会把通用逻辑和功能抽取分离开来,比如管理、聊天、交易以及一些组队和工会,放到独立的地方,再通过Cluster服务器集群的方式提供服务。采用这种分组以后,以前同步的逻辑直接本地调用一个函数,来处理组队和工会,会变到另外一个服务器上,中间就多了一些异步交互。异步交互存在状态维护的困难,所以这种结构开发难度会更高。
MMO和RPG大都是这种结构。其中,比较有代表性的是最早期的《传奇》。它是一个经典的MMO,是盛大引进代理的韩国游戏。
《QQ幻想》和《QQ华夏》,也采用了这种结构。《QQ幻想》是腾讯在2005年,自研的一款Q版卡通类RPG,最高的时候有六十万左右玩家在线。《QQ华夏》则是07年深圳网域公司开发的RPG游戏,当时腾讯做代理运营。
第三种类型,是无缝地图。它的特点主要有三:
① 一个场景服务器只负责一部分场景;
② 玩家进入游戏后,没有加载地图的过程;
③ 在场景边缘处,数据可能同时存在于多个场景服务器中。此时会由world级的服务器进行管理,决定哪个服务器做决策。在边界切换时,不同场景服务器共同持有玩家的数据,玩家就不会感觉到明显的切换。最典型的,就是《魔兽世界》对无缝地图技术的应用。
第四种,是房间型服务器。
图中间的部分是大厅接入群,类似于上文中的gate和游戏服务器。这部分主要负责用户的接入、主要的逻辑处理以及其他一些大厅服务,比如《王者荣耀》和《英雄联盟》的5v5匹配。当很多玩家同时申请进入游戏时,房间型服务器会根据规则挑选出等级接近的玩家,分别组成队伍。之后单局的过程,叫做战斗接入群或房间服务。战斗接入群会做一个分布,比如,根据北方的联通和南方的电信,对用户做就近的接入。再如PUBG mobile,它的大厅集群放在北美,同时在北美、亚洲和欧洲都有战斗接入群,方便各地用户接入。
房间型服务器的游戏比较多,包括《英雄联盟》、《王者荣耀》和《刺激战场》(《和平精英》)等。
#03
核心问题、技术和实现难点
核心问题
游戏服务器要解决的核心问题,是满足海量游戏用户稳定和高质量的服务需求。
首先,“海量”指的是,十万到千万级的PCU(Peak Concurrent User,即最高同时在线用户)。此外,还有个名词DAU(Daily Active User,日活跃用户),是游戏运营的数据指标,而PCU主要考量服务器的性能数据。
其次,“稳定”代表着:
①服务器不能宕机,一旦服务器出现问题,用户的直观感受就是掉线了。
②要容忍弱网络的问题。比如,用户网络不稳定,连接断掉之后,服务器可以允许用户在短时间内进行WiFi和4G的切换,允许用户重新连接,保证服务可以继续。
最后,“高质量”主要是指处理网络的延迟和一些逻辑问题。
核心技术和实现难点
游戏服务器的核心技术和实现难点主要有四个:
① 单服处理能力
对于不同类型的游戏,单服即一个服务器,支撑的在线玩家数量是不同的。休闲类如棋牌游戏,可以支撑两万到三万的玩家;MMO可支撑的玩家数在五千到八千;而射击类等高强度交互的游戏,只能支撑两千到三千的玩家。
② 逻辑耦合度高
服务器有很多集群的设计,所以在单服处理能力方面,会有算法的优化。比如,排序方面有排序查找、hash(哈希,“散列”算法)和二叉树;还有用空间换时间的方法,把经常用的数据放到内存里,减少CPU的经常读取。
服务器设计比较难的地方在于逻辑设计。很多逻辑是一个整体,要想将它分离开,就要找联系相对薄弱的地方。举例来说,组队和游戏逻辑的相关性比较小,就可以抽离出来。有些服务器单独将组队剥离,那么组队的消息接口和逻辑,就容易抽离成另外一个独立的服务器。但即使逻辑之间可以分解,这也是有限度的。分解的越细,异步协作和状态维护的内容就会越复杂,游戏开发的难度就越大。
③ 延迟敏感
在防止延迟上,前端和后端需要一定配合。比如,前端会提前按帧缓存,当出现网络延迟和卡顿时,游戏其实还可以继续进行一段时间,这样玩家对延迟就没那么敏感。但是,提前缓存会存在玩家手感差异的问题,而且也不能缓存太多,否则玩家感受到的延迟就会比较明显。
④ 版本更新
现在,手游时代很少会停机更新,即使有也大都在凌晨。更流行的方式是不停机更新,这就要求逻辑、资源一定要做程序设计上的分离,保证在更新资源时,程序可以重新读取并加载,且不中断。
上图是游戏服务器的一个系统结构示例,它偏向于房间型结构。首先,前端采用TCP或其他协议进行接入;之后,大厅接入群,主要包括接入服务器和游戏逻辑服务器,通过Proxy或者哈希算法的方式,把DB(database,数据库)做分布式存储。因为一台DB存储不了千万上亿级的用户数据。最右侧,是一些内部的接口。举例来讲,如果运营商要发布活动如经验加倍、金币加倍等,就会通过管理端向游戏逻辑服务器做接口服务。图中的战斗接入群,主要处理单局的游戏内容。
此外,在公共平台还有支付、关系链和排行榜等功能。支付与游戏逻辑的相关性不大,可以独立出来。支付的大致方式有两种:一是将人民币转换为游戏内代币,二是代币旳消耗。关系链一般是第三方平台的关系链服务,包括QQ关系链、微信关系链和Facebook关系链等等,有些服务通过第三方的API或接口进行同步。排行榜也可以做成一个独立公有的服务器。
游戏服务器的网络协议主要有Tcp、Udp、R-udp和http四种。
Tcp是面向一个流的模型,本身有滑动窗口重传的机制。协议没有边界,但有流量控制,丢包会影响它的传输速度。
Udp是点对点的,没有可靠性的控制,不能保证消息包一定被收到,丢包会影响传输的成功率。
R-udp是在Udp的基础上,吸收了Tcp的特点,保证了可靠重传的机制。