开发笔记(20) : 交易系统
物品交易和掉落系统不是一期里程碑的内容,手头事情不多,就还是先做设计了。
物品掉落和交易,本质上是一件事情。区别在于玩家之间的物品交换于玩家和系统之间的物品交换。这部分的设计,我在去年初曾经写过一篇 blog 总结过。
这次重新设计实现,做了少量的改动。主要是一些简化。设计原则是,交易服务器独立,简洁,健壮,容易回溯交易历史做数据恢复和分析。
交易服务,我认为是一个后备系统。在数据不出问题时,不大用理会它的存在。它仅仅是用来保证物品不被复制,确定每件物品可以有唯一的所有人。在出现争议的时候,可以作为仲裁机构。
在游戏服务中,玩家或其他实体储存的物品,同样会保存在玩家数据中,利用共享内存读写 。 每件物品记录在对应的包裹格类,直接记录物品名称或指代名称的 id 。即,同样的物品用同样的标识。之外,再额外记录一个(或若干个)物品唯一 id (用 64bit 或 128bit ) 。这样做,避免在访问物品的功能时,额外去查一张表。
交易认证服务,其实只关心一件事情。即,某个物品 id 归属于谁。它不关心物品 id 代表的是什么含义。当然,可以有另一个数据库记录这个关系。在物品的所有者改变时,交易服务来保证其原子性。除了玩家间的转换,还有大量的和系统间的交换。掉落物品其实是从系统改为玩家所有,而玩家销毁物品则是把所有者改为系统所有。
我把交易系统所操作对象分为三类,Entity 表示所有者,Goods 表示物品,Currency 表示货币。货币是唯一不用唯一 ID 来记录的,它只记录数量。游戏中可能有多种不同的货币,所以需要额外记录一个货币的类型。
每笔交易都是由若干交易品构成的,每件交易品是 GoodsID 或 CurrenyType + CurrenyAmount ,为了让系统可以检查出交易品的合法性,我们需要同时绑定物品所有人,或物品所有人名下的货币总量。大体上,每次交易,对于一个交易方需要提供的信息是:
EntityID (所有人标识) Balances (所有人货币账户余额) { GoodsID (物品标识) | Currency (支出货币金额) }
展示我只打算支持两方交易,所以单条交易请求,只需要提供两个交易方的支出就可以完成交换了。
交易系统会校对双方的账户余额是否正确,交易交易品的所有人是否正确。如果有一项不正确,则取消交易,并返回错误的交易品是什么(或是正确的账户余额)。
其它协议大体上没有改变,和以前写的那篇类似。只是我增加了创建 Entity 时可以初始化账号余额的参数,用起来更方便一点。初始化物品也可以设置所有者,而不是默认给系统所有,进行一次交易才能赋予玩家。
系统不会只有一个 ID ,在掉落系统中,每张地图每个副本都有独立的 EntityID 。我们会在副本开始初始化好左右的可掉落物品(对于开放地图,会略微复杂一点,由某种和时间以及玩家数量有关的量来定期初始化)。货币也是定额配给在地图的 Entity 账户里的。和玩家账户不同,系统账户允许为负值,但是当系统账户为负时,会提醒维护人员。这样,我们比较好控制副本的货币产出。
销毁物品会把物品所有者更改为一个回收站名下,而不会从数据库中删除。但在实现上,或做一些特别优化,把这部分冷数据(正常逻辑不再访问的到的数据)移动到分离的数据库中。
这个系统接口简洁,需求单一,需要考虑的是在海量数据时足够稳定高效。所以对热数据(在线玩家的物品)需要做一些 cache 优化。对于每件物品都有一个唯一 ID ,可以预想到整个游戏世界中的对象可以轻易超过 10 亿这个数量级。因为日后还有合并服务器的需求,务必要保证所有服务器间也不可以有重复 id 的物品。这个数量非常之大,在实现时要从多方面考虑性能优化问题。
数据库的选择上,我认为是一个比较次要的问题。交给最终实现的人来选就好了。其实需要维护的数据仅仅是物品ID 到所有人 ID 的映射关系,使用 SQL 数据库也好,NoSQL 数据库也好,都没有特别的必要性。晓靖同学自告奋勇想做这套系统,他决定使用 Redis 来做数据储存,我觉得没有太大问题。
在数据容灾问题上,我们打算把交易请求通过独立服务来逐条记录 log 。保证使用 log 就可以完全恢复出数据库中的数据来。靠加强 Log 系统来保证数据不易损坏。
Comments
Posted by: DylanWang | (31) September 26, 2017 05:24 PM
Posted by: LukeJR | (30) August 28, 2017 09:10 PM
Posted by: Xi_Ao4 | (29) October 31, 2012 04:27 PM
Posted by: 陈鹏 | (28) July 17, 2012 10:53 AM
Posted by: andyshi | (27) July 10, 2012 05:06 PM
Posted by: ladeng | (26) June 20, 2012 10:27 AM
Posted by: Jichong | (25) June 19, 2012 05:53 PM
Posted by: jichong | (24) June 19, 2012 05:14 PM
Posted by: jichong | (23) June 19, 2012 05:08 PM
Posted by: jichong | (22) June 19, 2012 04:25 PM
Posted by: guest | (21) June 19, 2012 11:03 AM
Posted by: jichong | (20) June 19, 2012 02:47 AM
Posted by: jichong | (19) June 19, 2012 02:43 AM
Posted by: jichong | (18) June 19, 2012 02:41 AM
Posted by: jichong | (17) June 19, 2012 02:40 AM
Posted by: 杰拉明 | (16) June 17, 2012 04:10 PM
Posted by: 毛豆 | (15) June 15, 2012 02:52 PM
Posted by: 大笨兔 | (14) June 15, 2012 02:40 PM
Posted by: 小明 | (13) June 14, 2012 11:13 PM
Posted by: 123456 | (12) June 14, 2012 04:08 PM
Posted by: hoddddky | (11) June 14, 2012 12:12 PM
Posted by: 减肥药排行榜 | (10) June 13, 2012 10:15 PM
Posted by: Anonymous | (9) June 13, 2012 08:24 PM
Posted by: lqk | (8) June 13, 2012 01:58 AM
Posted by: dany | (7) June 12, 2012 04:51 PM
Posted by: elaine | (6) June 12, 2012 12:10 PM
Posted by: Anonymous | (5) June 12, 2012 10:44 AM
Posted by: egmkang | (4) June 11, 2012 10:53 PM
Posted by: blueflycn | (3) June 11, 2012 05:52 PM
Posted by: 胖子 | (2) June 11, 2012 04:54 PM
Posted by: hoddddky | (1) June 11, 2012 04:52 PM