内容简介:Lua 表的差异同步
最近同事碰到的一个需求:需要频繁把一组数据在 skynet 中跨网络传递,而这组数据实际变化并不频繁,所以做了大量重复的序列化和传输工作。
更具体一点说,他在 skynet 中设计了一个网关节点,这个网关服务可以负责把一条消息广播给一组客户端,每个客户端由内部的一个 uuid 串识别,而每条消息都附带有客户端 uuid 列表。而实际上这些 uuid 列表组有大量的重复。每条广播消息都重复打包了列表组,且列表组有大量重复信息。
一开始我想的方法是专门针对这个需求设计一组协议,给发送过的数据组编上 id ,然后在发送方和接收方都根据 id 压缩通讯数据。即,第一次发送时,发送全量信息,之后再根据数据变化发送差异;如果完全没有变化,则只需要发送 id 。
之后我想,能不能设计一种较为通用的差异同步方法,可以在跨节点传递数据组的时候,避免将相同的数据重复传输,而采用差异同步的方法同步对象。
晚饭后,我试着实现了一个这样一个简单的模块。
https://github.com/cloudwu/syncobj
我们可以先在通讯的两端建立对等的通道,构造数据的一端用 syncobj.source() 创建一个发送通道;而同步数据的另一端用 syncobj.clone() 创建一个接收通道。
当我们在发送端需要构造一组数据的时候,利用 obj = source:new() 创建出一个依附在这个通道上的对象 obj;为了简化实现,这个对象是一个单层的 lua 表。
我们可以在发送端像一个普通表一样访问这个对象,当我们需要同步到另一端时,可以用 diff = source:diff(obj) 生成一个和上个版本之间的差异数据;然后可以把 patch 作为普通的对象序列化发送。
而接收端用 cobj = clone:patch(diff) 就可以还原这个对象。由于 diff 中只是每次对象变化的差异数据,所以数据量会比直接全量传输 obj 要小。
如果通讯过程出了问题,我们还可以用 diff = source:reset(obj) 生成一个全量数据,而接收端则可以无视差异包和全量包的差别,都可以用 clone:patch(diff) 还原数据。
在内部协议中,实际上是给每组数据附加了一个单调递增的 id 号的,这个 id 号包含在 diff 数据中,所以 clone:patch 可以正确识别出如何还原数据。source:reset 生成全量包的过程,其实是赋予了对象一个全新的 id 。
当然,这个同步方案长期工作的话,就会存在一些对象已经在 source 端废弃,lua 的 gc 虽然会回收那些不再使用的对象内存,但 clone 端并不知晓;另外 source:reset 也会在 clone 端制造垃圾(老的版本已经废弃)。
所以,还提供了 removeset = source:collect() 返回一个不再使用的 id 列表;只要定期调用,把返回值传递给 clone:collect(removeset) 就可以让接收端清理不用对象。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Lua 表的差异同步
- 迁移学习领域自适应:具有类间差异的联合概率最大平均差异
- for与foreach的差异
- 在2019使用差异化服务
- 【译】框架与库的差异
- import 与 require 的两个差异
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
颠覆式创新:移动互联网时代的生存法则
李善友 / 机械工业出版社 / 2014-12-1 / 69
为什么把每件事情都做对了,仍有可能错失城池?为什么无人可敌的领先企业,却在一夜之间虎落平阳? 短短三年间诺基亚陨落,摩托罗拉区区29亿美元出售给联想,芯片业霸主英特尔在移动芯片领域份额几乎为零,风光无限的巨头转眼成为被颠覆的恐龙,默默无闻的小公司一战成名迅速崛起,令人瞠目结舌的现象几乎都被“颠覆式创新”法则所解释。颠覆式创新教你在新的商业竞争中“换操作系统”而不是“打补丁”,小公司用破坏性思......一起来看看 《颠覆式创新:移动互联网时代的生存法则》 这本书的介绍吧!