acm-header
登录

ACM通信

实践

游戏和虚拟世界的规模化


我以前也像你一样。

我曾经是一名系统程序员,负责银行、电信公司和其他工程师使用的基础设施。我研究的是操作系统。我从事分布式中间件的工作。我研究编程语言。我写工具。我做了所有硬核系统程序员做的事情。

我知道规则。我知道吞吐量是对伸缩性的真正考验。我知道必须保持数据的一致性和持久性,关系数据库是确保原子性的方法,而信息的丢失是绝对不可能的。我知道,随着服务器层的增加,客户端变得越来越薄,最好的客户端应该包含最少的状态,并允许重要的计算在计算云中进行。我知道对遗留代码的支持对于任何新技术的采用都是至关重要的,而且大多数遗留代码还没有编写出来。

但两年前,我的世界改变了。我被邀请担任Project Darkstar的技术架构师,这是一个面向大型多人在线游戏和虚拟世界市场的分布式基础设施。起初,这似乎是一个熟悉的系统。目标是通过允许机器的动态增加(或减少)来匹配负载,从而实现灵活的伸缩。有一个持久层和一个通信层。我们还希望使编程模型尽可能简单,同时使系统能够使用Sun(和其他公司)生产的新一代多核芯片的所有功能。这些都是我以前遇到过的问题,那么针对这个特定市场,这些特定版本的问题会有多难呢?我同意花几个月的时间在这个项目上,清理架构,确保它在正确的轨道上,同时思考我可能想要解决的新研究课题。

三个月变成了两年(而且还在增加)。我发现了许多新的研究挑战,但它们都与寻找方法使在线游戏和虚拟世界的环境规模化有关。在这个过程中,我被引入了一个不同的计算世界,有不同的问题、不同的假设和不同的环境。有时我觉得自己像一个发现了新文明的人类学家。我仍在学习游戏文化和实践,这是一个不同的世界。

回到顶部

你所知道的一切都是错的

要了解这个新世界,首先要意识到它是娱乐产业的一部分。正因为如此,游戏或虚拟世界最重要的目标就是要有趣。其他一切都是次要的。趣味性并不是一个客观的衡量标准,但其目标是提供一种沉浸式的、全身心投入的体验,奖励玩家玩得好,容易学习但很难掌握,并让玩家不断回到游戏中。

大多数网络游戏都以故事和世界为中心,故事和世界的丰富程度与游戏的成功有很大关系。游戏设计的核心是故事和玩法。用于执行游戏的代码设计要晚一些(通常被认为不那么有趣)。制作人负责团队创造游戏或世界。团队成员包括作家、艺术家、音乐家以及程序员。对游戏影响最小的群体是程序员;他们的工作是把别人的愿景变成现实。

在线游戏或虚拟世界的计算环境与高科技产业服务的大多数市场几乎完全相反。客户们一点也不瘦;游戏玩家将使用他们所能获得的最高端的计算平台,或者专门为这些游戏的计算严格性而设计的游戏机。这些客户端机器将拥有尽可能多的内存,最新最快的CPU,以及一个具有超级计算能力的图形子系统。这些客户端还具有相当大的持久存储能力,因为这些游戏的基本方法之一是将尽可能多的信息放在客户端上。

在某种程度上,对重量级客户端的需求是这些游戏发展的结果。在线游戏是从独立产品发展而来的,在这些产品中,一切都是在本地机器上完成的。然而,在这个行业中,这不仅仅是熵;在客户端上尽可能多地保留可以最小化与服务器的通信,包括对服务器的调用数量和在这些调用中传递的信息量。这种最小化交流是满足乐趣的首要指令所必需的,因为这是在这些游戏中最小化延迟的方法之一。

延迟是乐趣的敌人,因此也是在线游戏和虚拟世界的敌人。这在在线游戏的情况下尤其有趣,其中客户端和服务器之间的连接延迟无法控制。因此,通信协议需要尽可能地简单,并且从客户端传输到服务器的信息必须尽可能地装入单个数据包。此外,服务器的设计必须确保它所做的事情非常少,确保它所做的事情能够非常快速地完成,从而将响应发送回玩家。一些有趣的技巧被开发来掩盖玩家不可避免的延迟。这些技术包括在任务加载过程中显示预先录制的片段,或在操作结果中立即显示“最佳猜测”,然后在服务器响应时修复猜测与实际结果之间的任何差异。

服务器的角色是双重的。最明显的是允许玩家在游戏环境中相互交流。随着这些游戏和世界变得越来越精致,这个角色也变得越来越重要和复杂。服务器最初的作用是让玩家在游戏中相互竞争。现在,游戏和世界正在发展自己的社会,玩家可以竞争,也可以合作,或者只是以各种方式互动。虚拟世界允许用户尝试新的个性。游戏让玩家合作完成他们无法单独完成的任务。在这两种游戏中,玩家都发现这项技术的一大吸引力在于利用它与他人建立联系。

服务器的第二个角色是充当客户端之间真相的仲裁者。无论客户端是运行在主机上还是个人电脑上,控制权都掌握在玩家手中。这意味着玩家可以访问客户端程序,游戏的竞争性让玩家有动力按照自己的意愿改变客户端。即使是在只有社交竞争的虚拟世界中,玩家也普遍希望增加个体玩家的机会(通常称为“作弊”)。这就要求服务器(游戏邦注:不受玩家控制的组件)成为游戏真实状态的仲裁者。游戏服务器既用于阻止作弊(通过使作弊变得更加困难),也用于检测作弊(通过查看客户端报告的游戏状态和服务器持有的游戏状态之间的差异模式)。点对点技术似乎很适合游戏服务器的第一个角色,但第二个角色意味着很少有游戏或世界能够充分信任它们的同伴来避免服务器组件。

回到顶部

当前的扩张策略

单数术语的使用服务器在前面的部分中,系统结构的概念幻象只能由游戏或世界的客户端来维护。事实上,任何在线游戏或虚拟世界都会涉及大量服务器(或者失败到没有人能够或想要记住游戏或虚拟世界)。使用多个服务器是将游戏的服务器组件扩展到当今在线世界的基本机制。据报道,《魔兽世界》的用户已经超过500万,任何时候都有数十万活跃用户。《第二人生》的使用量与《魔兽世界》差不多,有证据表明Webkinz或Club Penguin等网站更受欢迎。单个服务器无法处理这样的负载,无论表示多么有效。即使单个服务器可以处理这种负载,这种服务器对于在低需求时期(或在需求下降的产品生命周期的部分时期)遇到的较小负载(有时是相同的游戏或世界)来说也太昂贵了。

拥有多个服务器意味着构建游戏的一部分便是决定如何在这些服务器上划分负载。在网络游戏和虚拟世界中,有两种技术被普遍使用。有时只使用两种技术中的一种,有时两者都使用,这取决于游戏或世界的性质。

第一种技术是利用游戏或世界的地理位置,将游戏分解成不同的区域,每个区域都可以映射到主机服务器上。例如,“第二人生”中的岛屿对应于运行共享现实世界代码的物理服务器。类似地,《魔兽世界》世界的不同区域托管在不同的物理机器上。该地区的任何人都可以连接到同一台服务器,该服务器上的玩家之间的互动可以被本地化(和优化)。在世界其他地方发生的操作不太可能影响到世界这一部分的操作,因此服务器之间的通信流量可以保持较小。

第二种技巧被称为分片。碎片是游戏或虚拟世界的一部分的副本。不同的碎片驻留在不同的服务器上,分配到一个碎片的玩家可以与世界和碎片中的其他玩家互动,但不会看到(或能够与)其他碎片中的玩家或物体互动。碎片不仅可以让更多的玩家在世界中得到支持,还可以让不同的玩家组独立地探索世界。因此,当一个新的任务或任务被添加到游戏中时,它通常会被多个碎片复制,这样不止一个玩家(或一组玩家)可以在原始状态下体验任务或任务。


可能除了最高端的科学计算之外,没有任何一种软件像游戏或虚拟世界程序那样积极地利用摩尔定律的进步。


尽管分片和地理分解允许使用多个服务器来处理单个游戏或世界的负载,但它们确实给开发者带来了重大挑战。通过创建世界部分的非交互副本,碎片将不同碎片中的玩家彼此隔离。这意味着想要分享游戏世界或游戏经验的玩家需要了解所提供的不同碎片,并安排将其放置在同一个碎片中。随着想要进入同一个碎片的玩家数量的增加(游戏邦注:有些公会,或者是在一款游戏中合作玩一段时间的玩家群体,拥有数百名成员),协调放置碎片的难度也会增加,并干扰游戏世界的体验。虽然碎片允许规模,但它们是以玩家互动为代价的。

地理分解并不会限制玩家互动,但确实要求游戏设计师能够预测地理区域的大小,这将是正确的分解单位。如果一个地理区域变得非常流行,那么该区域的游戏速度就会变慢,因为与该区域相关的服务器过载了。如果一个地理区域的受欢迎程度低于最初的预期,那么电脑硬件(和资金)就会浪费在这个区域上,因为那里没有足够的玩家。因为地理分解是硬连接到游戏或世界的代码中,所以根据观察到的用户行为改变分解需要重写部分游戏或世界本身。这需要时间,可能会引入错误,而且成本非常高。在此过程中,游戏玩法可能会受到不利影响。在极端情况下,这可能会产生重大的财务影响。当《魔兽世界》问世时,市场对这款游戏的需求远远超过了游戏内置的容量,以至于在重新编写分发游戏的代码期间,订阅服务不得不关闭数月之久。

回到顶部

改变芯片架构

在一组机器上扩展是一个分布式计算问题,而游戏和虚拟世界编程文化对这类问题几乎没有经验。这并不是唯一需要游戏程序员学习新技能的地方。芯片设计趋势的变化也意味着这些程序员必须学习他们以前从未练习过的技能。

可能除了最高端的科学计算之外,没有任何一种软件像游戏或虚拟世界程序那样积极地利用摩尔定律的进步。随着芯片的速度越来越快,游戏和虚拟世界也变得越来越逼真、越来越复杂、越来越有沉浸感。认真的游戏玩家会投资于他们所能获得的最好的设备,然后使用超频等技术来提高这些系统的性能。

然而,现在芯片设计者们决定以一种不同的方式利用摩尔定律。他们不是提高芯片的速度,而是在以相同(有时更慢)时钟速度运行的芯片上增加多个内核。这有很多很好的理由,从简化设计到降低功耗和产热,但这意味着当您在新芯片上运行程序时,单个程序的性能不会自动提高。一组程序的总体性能可能会提高(因为它们都可以并行运行),但单个程序不会提高(除非它可以被分解成多个协作线程)。然而,游戏是由单线程程序编写的。

事实上,游戏和虚拟世界(特别是这些程序的服务器端)应该是展示多核芯片和协作服务器组可能带来的性能提升的完美工具。游戏和虚拟世界是令人尴尬的平行关系,因为其中发生的大多数事情都独立于正在发生的其他事情。在《魔兽世界》的数十万活跃玩家中,只有极少数会与特定玩家互动。在《第二人生》和几乎所有大型游戏或世界中也是如此。


通过以持久的方式备份数据,而不是将其保存在主存中,我们获得了一些内在的可靠性,这是过去的游戏或世界所没有表现出来的。


问题在于,围绕游戏和虚拟世界成长起来的文化并不理解或过于熟悉开发这些系统中固有的并行性所需的编程技术。这些人是在一台(PC)机器上长大的,运行一个线程。要求他们掌握并发编程或分布式系统的复杂性会让他们无法专注于游戏或世界体验本身。即使他们有这样的愿望,他们也没有时间或经验去开发这些新技术。

回到顶部

暗黑之星项目

正是出于这些原因,我们启动了Project Darkstar (http://www.projectdarkstar.com),这是一项研究工作,试图构建一个服务器端基础设施,该基础设施将利用正在生产的多线程、多核芯片,并在大型机器上进行扩展,同时给程序员一种他或她正在单线程、单机环境中开发的错觉。在一般情况下,隐藏线程和分布可能不是一个好主意(完整的参数请参阅http://research.sun.com/techrep/1994/abstract-29.html)。游戏和世界服务器倾向于遵循一个非常受限的编程模型,然而,我们相信在这个模型中,我们可以同时隐藏并发性和分布性。

该模型是一个简单的基于事件的模型,服务器接收来自客户端的输入,然后启动一个任务来响应该事件。这些任务可以改变游戏世界的状态(通过移动玩家,改变物体的状态等等)并引发交流。通信可以是与单个客户端通信,也可以是与订阅了同一通信通道的一组客户端通信。

我们选择这个模型很大程度上是因为这是大多数游戏和虚拟世界服务器的结构方式。当时的挑战是保持这种模型,并允许以这种风格编写的服务器在多核(运行多线程)和多服务器上扩展。我们并没有试图获取现有的代码并允许它在我们的系统中运行。这将使任务变得更加困难,并且不符合游戏和虚拟世界文化的现实。游戏和世界服务器是为每个游戏或世界从头开始编写的,可能会重用一些库,但很少会在运行后重新托管到不同的环境中。将不同平台引入游戏的努力仅限于客户端,新主机带来的新玩家可能值得付出努力。

Darkstar提供了一个运行服务器的容器。容器为一组服务提供接口,允许游戏服务器保持持久状态,与客户端建立连接,并使用客户端集合构建发布/订阅通道。游戏服务器代码的多个副本可以在Darkstar容器的多个实例中运行。每个副本都可以写成唯一激活的副本(事实上,它可能是小型游戏或世界中唯一激活的副本)。每个服务器都被构造成一个事件循环——主循环监听与客户端的会话,会话是在客户端登录时建立的。当传递消息时,将调用事件循环。然后循环可以解码消息,并确定游戏或世界行动是适当的响应。然后在容器内分派任务。

这些任务中的每一个都可以通过Darkstar数据服务读取或更改世界中的数据,与客户端通信,或通过通道向其他游戏或世界参与者发送消息。在幕后,任务被包装在事务中。该事务用于确保不会发生冲突的对世界数据的并发访问。如果某个任务试图更改正在由其他并发任务更改的数据,则数据服务将检测到该冲突。在这种情况下,其中一个冲突的任务将被中止并重新安排;另一个任务应该运行到完成。因此,当重试中止的任务时,冲突应该已经消失,任务应该运行到完成。

这种并发控制机制确实要求所有任务通过Darkstar数据服务访问它们的所有数据。这与通常的游戏或世界服务器编程方式不同,后者将数据保存在内存中以减少延迟。通过使用过去20年数据库研究的结果,我们相信可以通过智能的方式缓存数据,使通过数据服务访问的代价保持在较小的水平。我们还相信,通过使用这些游戏中固有的并行性,我们可以随着玩家数量的增加而提高游戏的整体性能,即使对个人数据访问有很小的惩罚。我们的数据存储不是基于标准SQL数据库,因为我们不需要这种数据库提供的全部功能。我们需要的是能够让我们快速访问持久存储的对象的东西,这些对象可以用简单的方式进行标识。我们目前的实现使用Berkeley数据库来实现这一点,尽管我们已经抽象了对它的访问,以便在需要时提供使用其他持久性层的机会。

并发控制并不是要求通过数据存储访问所有数据的唯一原因。通过以持久的方式备份数据,而不是将其保存在主存中,我们获得了一些内在的可靠性,这是过去的游戏或世界所没有表现出来的。将所有数据存储在内存中意味着服务器崩溃可能导致游戏或世界自上次系统检查点以来的任何变化的丢失。这有时可能是几个小时的游戏,这可能会在客户中引起相当大的恐慌,并给服务热线打昂贵的电话。通过持久地保存所有数据,我们相信我们可以确保在服务器崩溃的情况下,不超过几秒钟的游戏或世界互动将会丢失。在最好的情况下,这样的崩溃甚至不会被玩家注意到,因为服务器上的任务将以一种对玩家透明的方式转移到另一个服务器上。

要求所有数据都保存在数据存储中的最大收益是,它有助于让游戏中的事件响应生成的任务具有可移植性。由于数据存储可以被运行Darkstar堆栈和游戏逻辑的任何一台机器集群访问,因此没有数据不能从一台机器移动到另一台机器。我们对通信机制也做了同样的处理,确保连接游戏和某些客户端的会话或通道通过Darkstar堆栈抽象出来。这允许我们将使用会话或通道的任务移动到另一台机器,而不会影响通过会话或通道进行会话的任务的语义。

这种任务可移植性意味着我们可以在运行游戏或虚拟世界的一组机器上动态平衡负载。在编译时,虚拟世界或基于Darkstar堆栈的游戏可以在运行时在服务器机器网络中移动负载,而不是将游戏划分为区域或碎片。虽然参与者在移动过程中可能会看到延迟的短暂增加,但在移动之后,整体延迟将会降低。通过移动任务,我们不仅可以平衡相关机器上的负载,还可以尝试配置访问相同数据集或彼此通信的任务。所有这些机制都允许我们在游戏进行时决定哪些任务(以及哪些用户)应该放在同一个服务器上。

该项目处于开发和部署的早期阶段。它基于开源授权模式和社区,所以我们依靠我们的用户来教育我们社区的需求,他们将在基础设施上构建游戏和世界。这项研究部分是计算机科学,部分是人类学,但每种文化都有机会从对方身上学到很多东西。

即使在这个早期阶段,很明显,这将是一项复杂的冒险。虽然早期的代码经验表明,编程模型确实可以让游戏或世界服务器程序员摆脱对线程和锁定的思考,但它也表明,在某些地方,他们必须了解系统的底层并发性。其中最明显的是数据结构的设计。我们代码的早期用户之一从系统中得到了糟糕的性能。当我们查看代码时,我们发现每个任务都有一个单独的对象,更新游戏状态的全局部分。通过以这种方式设计服务器,该用户有效地序列化了系统中运行的所有任务,使得服务器无法从游戏中固有的并行性中获得任何优势。一些小的重新设计,将单个对象分解为许多(更小的)对象,消除了这个特定的瓶颈,从而提高了整体性能。这一经验还告诉我们,我们需要教育系统用户如何设计可以并行访问的独立数据结构。

我们自己的实现也令人兴奋。当我们从运行在单机上的多线程服务器转移到运行在多台机器上的实现时,我们预计单机系统的性能会有所下降。我们很高兴地发现单节点系统的性能下降并没有我们想象的那么大,但是我们发现增加的机器降低了整个系统的容量。当看到这些测量结果时,理解多台机器上争用的可能性比一台机器上的更大并不奇怪,并且发现和从这种争用中恢复需要更长的时间。我们正在努力消除阻塞点,这样增加设备实际上可以增加产能。

由于对目标服务器的需求缺乏明确的概念,因此度量系统的性能特别具有挑战性。游戏开发者的秘密是出了名的,游戏或虚拟世界的特征负载的概念并没有很好的记录。我们有一些由团队或我们在游戏世界中认识的人写的例子,但我们不能确定这些是行业所写内容的准确反映。我们希望围绕这个项目开始形成的开源社区将有助于产生有用的性能和压力测试。

从更广泛的角度来看,该项目已经并将继续是为多线程、分布式系统世界构建抽象级别的有趣实验。我们正在解决的问题并不新鲜。大型web服务农场在需求高度可变的情况下也存在许多相同的问题。科学网格也有在多台机器上扩展的类似问题。搜索网格在处理大规模环境时也有类似的问题,解决令人尴尬但不完全平行的问题。

与其他领域相比,在线游戏和虚拟世界的不同之处在于它们所提出的要求非常不同。交互式、低延迟环境与网格、Web服务或搜索非常不同。娱乐产业的发展也使得工程学科与其他学科截然不同。在这种新环境中解决这些问题是具有挑战性的,并且增加了我们如何为新兴的多线程、多核、分布式系统编写软件的一般知识。

最重要的是,它很有趣。

回到顶部

作者

吉姆·沃尔多他是马萨诸塞州伯灵顿太阳微系统实验室的杰出工程师,在那里他进行大规模分布式系统的研究。

回到顶部

脚注

DOI: http://doi.acm.org/10.1145/1378704.1378716


©2008 acm 0001-0782/08/0800 $5.00

允许制作本作品的全部或部分数字或硬拷贝供个人或课堂使用,但不得为盈利或商业利益而制作或分发副本,并且副本在第一页上带有本通知和完整的引用。以其他方式复制,重新发布,在服务器上发布或重新分发到列表,需要事先明确的许可和/或费用。

数字图书馆是由计算机协会出版的。版权所有©2008 ACM, Inc.

Baidu
map