Lua 表的差异同步

栏目: Lua · 发布时间: 6年前

内容简介: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) 就可以让接收端清理不用对象。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Four

The Four

Scott Galloway / Portfolio / 2017-10-3 / USD 28.00

NEW YORK TIMES BESTSELLER USA TODAY BESTSELLER Amazon, Apple, Facebook, and Google are the four most influential companies on the planet. Just about everyone thinks they know how they got there.......一起来看看 《The Four》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具