方便网页游戏合服的数据库设计思路

合服应该算是游戏生命周期中的一环,很多游戏开发者都会经历这个过程,而根据我自己的经验,网页游戏合服更为普遍和频繁。我经历过合服的痛 苦历程,甚至听说过有些游戏由于最初的设计原因导致无法合服。当然真正的无法合服应该是不存在的,我想大概是因为这个痛苦超过了常人的忍受能力,或者是这 个过程成本过高。 所以说,我们最好在早期开发过程中就预先考虑好这个问题。

环境说明

以下的内容直接使用 MySQL 的术语和语句,不过就算你使用其他数据库,也应该很容易理解这些概念。

主键冲突

合服时遇到的最普遍情况当属主键冲突。

玩家角色、道具等等都是在游戏运行过程中添加进去的数据,我们用数据库的 AUTO_INCREMENT 特性来创建这些数据的主键,来保证他们在游戏中的唯一性。 比如我们定义了玩家的ID字段为 `uid` int(11) NOT NULL AUTO_INCREMENT ,那么玩家的道具表中势必也会有一个字段 `uid` int(11) NOT NULL ,用来表明这个道具是哪个玩家的,类似的,玩家的装备等等也会用类似方法表明归属。

当合服时问题就来了,AUTO_INCREMENT 只能保证数据在这个服务器中唯一,最终导致服务器 A 中有个玩家的 uid 是 1 ,服务器 B 中也有个玩家的 uid 是 1 ,在解决这个冲突前是不能合服的。

我们常常采用的方法就是把服务器 B 中的所有 uid 都加上一个数,以保证服务器 B 中最小的 uid 也比服务器 A 中的大,这样就把冲突解决了,当然还要做一些其他工作,因为玩家表中 uid 改了,所以道具表中的 uid 也要做相应的修改,以保证合服后道具还属于原来那个玩家,然后还有装备表等等要如法炮制。如果你使用了外键,还得加上删除和重做外键的步骤。

同时,道具表和装备表等又有自己的主键冲突要解决,表越多,表之间的关系越复杂,修改一个表的主键牵涉到的相关表也就越多。虽然解决问题的规则和方法很简单,但实际操作起来,这样一层层套在一起简直让人疯狂。

主键冲突的避免

通过上面的描述,主键冲突产生的原因和解决主键冲突的方法都已经很明了了。那么与其每次这么手动去处理,不如把这个解决的方法提前到数据库产生数据前。

首先,我们给每个服务器一个编号,我想这很容易,服务器本来就是一服二服这么下来的。 然后预估每个表最多会有多少数据:比如我预计我们一个服务器不会达到1亿个玩家,那么用服务器编号乘上这个预估的数,比如 1 服,就是 1 x 100000000 = 100000000 ,2 服就是 2 x 100000000 = 200000000。在开服前我们用 ALTER TABLE x AUTO_INCREMENT = y 把 AUTO_INCREMENT 的字段设定从这里开始计数。这么一来,合服时就不会出现主键冲突了。

事实上,我很懒,懒得去给每张表估计最多会有多少数据;也很胆小,不想承担数据量超过我预估的值的风险。 所以我干脆预估所有表都是 100 亿,事实上这已经超过了 int(11) 的最大值,就没什么好担心的了。 我们要做的就是把原来使用的 int(11) 改成 bigint(20)。

别怕太大,硬盘很便宜,AUTO_INCREMENT 也不用你去数。 牺牲那么点存储空间,换得我们开发人员的安枕无忧,我觉得太划算了。

本问转自:

http://bnlt.org/?p=254