美文网首页
skynet中数据增量同步方案

skynet中数据增量同步方案

作者: simon_xlg | 来源:发表于2018-09-19 17:01 被阅读0次

    游戏服务器开发中,有一种常见的场景,就是跨进程多个服务中数据同步的问题。

    譬如 数据中心服 和游戏服之间的数据同步,玩家在游戏服务中发生数据改变时候需要同步到数据中心服。

    比较常见的解决方案有几种:

    1.把用户数据全量发送到目标服务。

    2.把用户数据粒度划分更细,然后写很多的接口诸如:更新用户金币 update_usergold、更新任务数据 update_usertaskinfo。等等

    3.还有一种办法就是增量更新。

    例如云风写过的一个小工具

    https://blog.codingnow.com/2017/05/syncobj.html

    但是这个工具,云大并没有花太多的时间去完善,我在使用的时候发现不是特别好用。

    主要是 如果一个table 的层级比较多的情况下。

    譬如:

    local tab = {
      x = {x1 = 1,x2={x3 = “x3”}}
    }
    

    那么假如改变了 tab.x.x2.x3的值

    整个tab.x 都被改变了。很明显不是我想要的。

    我想要的是改变某个值只记录路径和最终的值

    所以我自己写了一个工具类。
    最新代码(https://github.com/simonxlg/syncobj

    
    -----------------------
    
    -- synctable
    
    -- Author simon_xlg 285909195@qq.com
    
    -----------------------
    
    local pairs = pairs
    
    local setmetatable = setmetatable
    
    local synctable = {}
    
    local new
    
    local make
    
    new = function(root,tab,tag)
    
    local _tab = {}
    
    local _root = root
    
    local ret = make(_root,_tab,tag)
    
    if not _root then
    
    _root = ret
    
    end
    
    for k,v in pairs(tab) do
    
    if type(v) == "table"  then
    
    _tab[k] = new(_root,v,tag.."."..k)
    
    else
    
    _tab[k] = v
    
    end
    
    end
    
    return ret
    
    end
    
    make = function(root,tab,tag)
    
    local proxy = {
    
    __data = tab,
    
    __tag = tag,
    
    __root = root,
    
    }
    
    if not root then
    
    proxy.__root = proxy
    
    proxy.__pairs ={}
    
    end
    
    setmetatable(proxy,{
    
    __newindex = function(s, k, v)
    
    local root = s.__root
    
    local tag = s.__tag
    
    local data = s.__data
    
    if not data[k] and type(v) == "table"  then
    
    data[k] = new(root,v,tag.."."..k)
    
    else
    
    data[k] = v
    
    end
    
    root.__pairs[s.__tag.."."..k] = v or "nil"
    
    end,
    
    __index = function (s, k)
    
    return s.__data[k]
    
    end
    
    })
    
    return proxy
    
    end
    
    function synctable.create(tab)
    
    local _tag = "root"
    
    return new(nil,tab,_tag)
    
    end
    
    function synctable.diff(tab)
    
    local diff = tab.__pairs
    
    tab.__pairs = {}
    
    return diff
    
    end
    
    function synctable.patch(obj,diff)
    
    for k,v in pairs(diff) do
    
    local arr = {}
    
    for w in k:gmatch("([^.]+)") do table.insert(arr,w) end
    
    local curr = obj
    
    local len = #arr
    
    for i=2,len-3 do
    
    curr = obj[arr[i]]
    
    end
    
    curr[arr[len]] = v
    
    end
    
    return obj
    
    end
    
    return synctable
    
    

    下面测试一下

    
    local synctable = require "synctable"
    
    function _dump(data, max_level, prefix)
    
        if type(prefix) ~= "string" then
    
            prefix = ""
    
        end
    
        if type(data) ~= "table" then
    
            print(prefix .. tostring(data))
    
        else
    
            print(data)
    
            if max_level ~= 0 then
    
                local prefix_next = prefix .. "    "
    
                print(prefix .. "{")
    
                for k,v in pairs(data) do
    
                    io.stdout:write(prefix_next .. k .. " = ")
    
                    if type(v) ~= "table" or (type(max_level) == "number" and max_level <= 1) then
    
                        print(v)
    
                    else
    
                        if max_level == nil then
    
                            _dump(v, nil, prefix_next)
    
                        else
    
                            _dump(v, max_level - 1, prefix_next)
    
                        end
    
                    end
    
                end
    
                print(prefix .. "}")
    
            end
    
        end
    
    end
    
    function dump(tab,prefix)
    
    _dump(tab,5,prefix)
    
    end
    
    local tab = {a=1,b=2,c={c_1 = {c_2={c_3="c_3"}}},d={{1},{2},{3}}}
    
    local tab2 = {a=1,b=2,c={c_1 = {c_2={c_3="c_3"}}},d={{1},{2},{3}}}
    
    print('{a=1,b=2,c={c_1 = {c_2={c_3="c_3"}}},d={{1},{2},{3}}}')
    
    tab = synctable.create(tab)
    
    tab.c.c_1.c_2.c_3 = "c_4"
    
    tab.a={1,2,3,5}
    
    tab.a[1]=2
    
    tab.a[2]=7
    
    tab.a = nil
    
    tab.d = {1,2}
    
    tab.k = {x = 1,y=2,z={x=1,y=2}}
    
    tab.k.z.x=199
    
    tab.a = 9
    
    tab.k.z.x=220
    
    dump(tab2,"----")
    
    local diff = synctable.diff(tab)
    
    dump(diff)
    
    dump(synctable.patch(tab2,diff))
    
    local t = os.time()
    
    for i = 1 ,1000000 do
    
        tab.a = i
    
        tab.d = {1,i}
    
        synctable.diff(tab)
    
        synctable.patch(tab2,synctable.diff(tab))
    
    end
    
    dump(tab2)
    
    print("times" , os.time() - t)
    
    

    如果客户端是H5 或者微信小游戏 我这里还有对应的js版本
    https://github.com/simonxlg/syncobj

    相关文章

      网友评论

          本文标题:skynet中数据增量同步方案

          本文链接:https://www.haomeiwen.com/subject/elginftx.html