« skynet 模块命名空间调整 | 返回首页 | 支持部分共享的树结构 »

sharedata 的替代品:datasheet

skynet 中有一个用来在多个服务间共享数据表的模块,叫做 sharedata

它的设计动机是:当我们有很多服务时,如果需要共享一份只读的数据表,把数据表分别在每个服务类加载会很浪费内存。而且,一旦数据表有热更新的需求,分散在多个服务中的数据更新起来会比较麻烦。

我试过很多方案来达成这个需求,一直都不是特别满意。目前的 sharedata 模块是用的最久、使用项目最多的一个。虽然它基本可用,但使用它的同学也提出了一些问题,我对这些问题做了一些思考。

首先、它其实并不能完全共享一块内存。我们很难做到像 C 数据结构一样,一份只读的数据结构让多个读取者持有指针,完全共享同一块内存。因为对于树结构的数据,如果期望让 lua 用原生的语法来访问,就需要把子结构的指针用 lua userdata 封装起来,这个结构本身是属于 lua vm 的,每个 vm 必须独立,不能共享。它是需要额外占用内存的。

如果把这个结构用 lightuserdata 封装,一是元表的问题很难解决的很好(不同的 lightuserdata 必须共享元表),二是 lightuserdata 无法做热更新:你很难(并非完全不行)通过遍历 lua vm 更新它。

而从节约内存的角度看这个模块的用途,它更多的是做到部分加载:策划会把很多数据打包到一个数据表里,但是一个服务在一段时间只会用到很少的一部分。把整个数据表加载到服务的 lua vm 内是很浪费内存的。

访问速度也是可能成为问题:lua 访问纯 table 的内容还是很快的,如果是 userdata 或带 metatable 的 table 的话,由于要至少多出一次函数调用,性能就大打折扣。sharedata 做了一定的 cache ,我们有一个项目在使用的时候更是自己额外多做了一层 cache ,为了配合 cache 工作,我还特定添加了 deepcopy 方法,把 sharedata 的子树复制成普通的 lua 表。这也可以看出,完全共享内存而减少内存消耗的需求并不那么强烈。


sharedata 在实现的时候,把数据热更新、副本引用管理的部分写在 C 层次,给实现也带来了不必要的复杂度。理论上热更新时,时间效率是很次要的,我们只需要保证正确即可,多长时间可以更新好并不太重要。

我在综合以上重新考虑后,最近重新实现了一个替代模块,暂命名为 datasheet 。它能做的是:把一个复杂的有一定限制的 lua 表,转换为一块 C 内存,由多个 lua 服务共享读取。

这里的一定限制指:表项的 key 只能是字符串,或是正的连续整数(数组)。加上这个限制可以简化实现。

它和 sharedata 的实现有所不同:它仅在第一次访问一个子表时,利用元方法触发,将子表的第一层完全复制到当前的 lua vm 中;如果这一层下还有子表,则只创建一个空表,附上元方法,惰性展开。展开后,它就变成了 lua 中一个普通 table ,原表也已去掉,访问操作完全没有效率损失。

从 lua 表转换为 C 内存块的过程交给独立的子模块 datasheet.builder 来完成,并由调用这个模块的服务来保持 C 内存块的生命期。这个 C 内存块将以 lua string 的形式存在于调用 datasheet.builder 的 lua 服务的 vm 中,只是把字符串指针共享给其它服务。

而任何服务一旦引用一张表,都可以把生命期保持到该服务退出。这些数据表采用引用数据管理,管理部分全部由 lua 实现。


数据热更新是这样实现的:

任何转换为 C 内存的数据表,每个子表都有一个唯一数字 id 。对应在 lua vm 中是一个包含有这个数字 id 的 userdata 。而在需要热更新数据表的时候,需要把老版本的数据表和新版本的数据表做一次差异比较,根据表项的 key 找到新老对应项,尽量保持相同的 id 生成新版本的数据块。

这样,在做热更新的时候,只要通知持有旧表的服务,更新 C 数据块指针,并把 vm 中的 cache 清空,下次访问任何一个子表时,重新从 C 数据块展开数据即可。


目前 datasheet 已经提交到 skynet 的 master 主干,以一个独立模块存在,接口方面和 sharedata 大致相同。有兴趣尝试的同学可以帮忙测试一下。它以后很有可能作为 skynet 1.1 的默认模块提供。

Comments

@mayao11 用一个动态库实现所有数据的操作接口,是比较直接简单
云风,你好,我想修改datasheet的功能,实现能够操作非正的连续整数key的table,请问是要修改C语言层的代码,还是dump.lua中的dump和undump呢?求抽空回复一下这个问题,谢谢
其实就是把数据在C那层共享出来。其实C语言写一个查表的话,连在lua里建table都不需要了。 表格这种游戏固有的需求,直接返璞归真,最Low的办法反而是最合适的,哈哈。
诚信学编程,需要资金买myeclipse软件,寻找投资伙伴
做项目缺人手,有意者私聊,免费提供冷饮,非诚勿扰,本人很忙
@sog 手机可以用 rss 订阅。
是否可以顺应潮流,博客支持手机阅读,我也明白,大家都很忙,
很好很强大

Post a comment

非这个主题相关的留言请到:留言本