游戏服务器的思考之二:游戏系统的封闭性

前一篇文章讲过,游戏服务器的设计哲学是在一个封闭的环境内,针对各个环节优化以达到最大的性能。如何处置数据是达到高性能的关键问题,通常成熟的游戏公司,其实不多面临数据处理方面的压力(如今开始流行的全球同服游戏多是个挑战),这是因为他们都有一套很成熟的技术方案了。
 
咱们这个团队因为一开始是作web系统的,在这个基础问题上非常挣扎了一番。下面,就咱们的经验大致讲述一下咱们对游戏数据的分类及处置方案。
一、静态配置数据
静态配置数据就是指那些在运行过程当中基本不会发生变化的数据,好比角色的技能、道具属性等,静态配置数据推荐使用静态文件来存储,咱们的作法是由策划将这些数据编写成excel文件,技术人员经过工具脚本导出两份,一份给客户端使用,一份给服务器使用。具体的导出格式并不重要:咱们的项目中,前端导出的是lua脚本,后端导出的是json文件。
 
这种存储方式的优势:
1)读取效率高,技术实现简单:
就是一段读取本地文件的代码而已,简单意味着不容易出错;
2)策划、前端、后端对数据模型达成高度的一致性:
这点对一个复杂的游戏来讲是很重要的,游戏试图刻画一个虚拟的世界,再简单的游戏,它内部创造的概念名词以及这些概念之间的关系,也比其余互联网应用多得多。一组配置文件对这个世界创建了一个静态模型,若是你们对这个模型认识、表达不一致,结果是灾难性的。相比长篇大论的需求文档,一组配置文件要精确太多了;
3)维护修改简单:
游戏通常包含大量的静态配置数据,这个数据是由策划人员维护的,在产品的生命周期内,策划更愿意编辑静态文件而不是一堆数据库表;
4)方便灰度发布
静态文件伴随代码一块儿部署,线上环境和灰度环境互不影响。
 
缺点:不支持在线修改
咱们经过技术手段实际上作到了能够在线修改:方式是经过推送修改后的文件到服务器,再通知服务器从新加载这个文件;这个过程须要技术来执行,显然不是一个常规操做。但静态数据之所是静态数据,是因为他的本质特性决定的,试想一下角色技能应该被常常修改吗?用户玩游戏的过程当中忽然多出一种从未见过技能是什么感觉?在游戏这个业务里是说不通的,会破坏游戏世界的一致性和完整性。实际的状况下,静态数据须要在线调整的缘由是:发现某个数值配置错误而进行微调,这不是一种常规的运营手段,因此“不那么方便”是能够接受的。
 
二、动态配置数据
配置数据整体上来讲是不多发生变化的,可是咱们仍然指望某些数据在须要时能够方便地修改(不须要技术人员的干预)。因为这种数据能够从外部修改,因此就必需要放在数据库里面了,可是因为他不多变化,所每次都从数据库或者缓存里面去拉取就显得效率过低。咱们的系统采起的是一种3级存储的方案:数据库+redis+服务器内存。原始数据存储在数据库表里面,运营人员能够经过GM工具对数据库表里面的数据进行修改,而后经过一个指令来告诉主服务器”数据发生了变化“,主服务器把数据库表的数据加载到redis里面,再发出一个广播通知,全部的游戏服务器接受到这个通知,从新从redis里面拉取数据到内存里。
 
动态配置数据和静态配置数据最大的区别是:对它的修改是一种常规的运营需求,好比一个充值活动的起止时间,一个抽奖系统的几率干涉等等;二者之间有时并无明显的界限,决策依据取决于对需求的理解,以及开发和运营之间的共识。仍是拿抽奖系统来举例,策划准备了两套几率配置,但愿运营依据运行的具体状况进行调整;那么这两套几率都是静态配置,那个切换的”开关“是动态配置。
 
这类数据按理不会太多,不然说明策划的想法有问题。
 
三、全局状态数据
有些数据是全局共享,而且变化也比较频繁,表明游戏运行某种全局状态,好比博彩游戏的总奖池状态或者棋牌游戏的房间列表,这些数据必须放到redis缓存系统,并进行实时的同步访问,幸亏这样的数据通常很少。这些数据通常不须要持久化,在服务器重启的时候适当地初始化就好。
 
四、用户数据
用户数据包括基本属性(昵称、头像)、财富数据(金币、道具)、角色数据、任务状态数据等,能够说游戏里面用户相关的数据远远多于web系统。
这些数据又多又读写频繁,若是每次操做都访问数据库或缓存系统确定是妨碍性能的,所以通常采起的策略是将数据加载到服务器内存,在须要的时候才同步到缓存中心或数据库。
 
这种延时同步的策略必然存在一致性风险:
1)不一样服务器之间数据不一样步:用户进入不一样游戏场景会被分配到不一样的服务器实例,系统要确保各服务器之间的用户数据是同步的。用户数据在某个时间段会驻留在特定的服务器实例上,要保证在切换服务器以前数据作了同步。
2)服务器内存与数据库的不一样步:数据库存储的数据状态老是滞后的,这种滞后性并非特别大的问题(参见“游戏系统的封闭性”),为了减小这种滞后性对运营形成的困扰,能够加上定时同步(周期不要太长)的机制。
3)服务器宕机致使数据丢失:定时同步能减小这种风险,在某些特定时机(好比用户得到特别大额的金币)进行当即同步也能减小风险。此外就只能依靠服务器本地日志了,经过将数据变化同步地写入日志文件,能够在宕机时用于恢复数据。实际上,在宕机时发生小量的数据丢失,给用户一个统一的小额补偿每每就够了,说到底游戏数据不是金融数据。
 
有不少游戏系统将用户相关的数据分红几块,每块打包成json或二进制数据块,做为一个字段放在数据表里面。这种彻底不一样于web系统的数据存储方案是有道理的:
1)游戏里面数据更新虽然频繁,但并不会实时入库;须要入库时,写入效率更佳;
2)游戏里面涉及的数据结构特别复杂,若是采用分散字段的方式来存储,形成表结构复杂,后期的表结构调整也是个麻烦事
3)数据库里面的数据能够直接抛给客户端;
5)数据备份更容易。
这样的数据字段无法在外部经过sql进行读写和统计,你得提供一套完整的运营工具来作这些事情。有些游戏系统会作一个折中方案,某些重要的字段独立存储(好比用户ID,帐号、金币),其余的打包存储(咱们的游戏系统也在往这个方向发展)。
 
因为历史缘由,目前咱们的用户数据存储方案设计有点偏web系统,数据库表比较多,大概可分红3类
A、用户属性数据和财产数据:诸如昵称、金币、道具等数据
这些数据是最重要的数据,须要按期作数据库备份,一旦出现重大漏洞和运营事故,要作数据回档。
B、有时效的数据:好比任务、签到等
这一类数据通常在一个固定的期限内只有一条有效记录,能够按时间戳来生成新的记录,老的记录由dba按期删除就好(好比保留最近7天),这样程序逻辑会比较简单,也能保留必定的历史记录。
C、日志数据:好比各类战斗记录,金币流水等
这一类数据写入量比较大,通常单独一个数据库来存放,而后作按期的删除(好比保留最近20天)。此类数据能够用来辅助客服工做,以及在出现小的bug和运营事故时做为补偿用户的依据。
 
五、流失用户数据备份:
游戏运行久了,就有不少的流失用户,这些用户的信息停留在系统里面,会慢慢影响数据库的性能,对不分服的棋牌游戏来讲,这个问题必需要处理。对于分服的游戏来讲,为了提升硬件的利用效率,在一组服务器用户流失多了之后,也会考虑合并多组服务器的活跃用户数据以节省硬件资源。
 
咱们作的是棋牌游戏,因此是不分服的,解决垃圾用户数据问题的方案是:按期将不活跃的用户(好比半年没有登陆)数据,放到一个静默用户数据表里面,当用户登陆的时候先去活跃表里面查找,若是找不到,就去静默表查找;若是在静默表里面找到用户数据,就将他恢复到在线表里面来。按照上面的分类定义,只有A类数据须要转移,因此须要转移的数据实际上并不太多。
 
这样,对活跃用户来讲,他的登陆时间是比较快的;对于新用户来讲,第一次登录会额外增长一次在静默表查找用户的时间;对于流失又回来的用户,会增长一个恢复数据的时间。为了防止静默表愈来愈大,能够设定一个规则,若是用户数据在静默表又待了1年,那么能够考虑将它的数据直接删除,另外对于身上没有什么财富的流失玩家,其实能够更早一点将他删除,好比半年甚至更短。
 
只有上面所述的A类数据是须要备份的,全部有时效的数据,咱们都不备份(咱们倾向于相信,一个静默用户的这类数据早就失效了)。因为用户的数据被存储到多个数据表,对全部这些数据库表分别作备份,很是繁琐,并且一旦数据库表调整,对应备份表的也要做调整,很是麻烦。为了解决这个问题,咱们在备份流失用户的数据时,将用户全部须要备份的数据打包成一个json,存到备份表的一个字段(上面说了,有不少游戏的用户数据原本就是这么存储的,备份就很easy了)。在恢复备份数据时候,就解析这个数据块并分别写入不一样的数据库表。 
相关文章
相关标签/搜索