V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zyxk
V2EX  ›  程序员

程序想要支持离线使用?应该怎么实现云端实时同步?

  •  
  •   zyxk · 2023-09-11 10:17:24 +08:00 · 3012 次点击
    这是一个创建于 444 天前的主题,其中的信息可能已经有所发展或是发生改变。
    程序想要支持离线使用?应该怎么实现相关技术?

    比如一个最简单的单人记账软件,想要实现云端实时同步,客户端离线时时也可以使用全功能,

    我是这样想的,软件使用本地数据库 Sqlite 实现全部功能,每个表都要增加一个时间检验,

    因为网页端可能修改数据,客户端离线时也可能修改了数据,

    所以每次客户端启动时逐行判断检验字段实现同步数据,(数据量少时可以,数据量大的软件怎么实现呢)

    之后客户端正常在线,WebSocket 连接服务器,添加或更新数据后,ws 通知服务端更新?

    但是感觉这样实现后不太严谨?请问这种需要应该怎么实现?请教各位
    第 1 条附言  ·  2023-09-11 11:43:33 +08:00
    通常做法是自行实现数据对比或增量同步吗?

    使用的 Golang , 有没有一种库可以实现本地数据和云端数据的同步?
    26 条回复    2023-09-14 18:32:13 +08:00
    dode
        1
    dode  
       2023-09-11 10:28:26 +08:00
    需要多个客户端数据合并吗
    zyxk
        2
    zyxk  
    OP
       2023-09-11 10:31:49 +08:00
    @dode 应该是不需要的,客户端只登录一个。
    cnoder
        3
    cnoder  
       2023-09-11 10:34:44 +08:00
    版本控制要重新设计,有网了再同步主要就是处理多端的版本冲突,另外最好增量校验
    Mithril
        4
    Mithril  
       2023-09-11 10:34:58 +08:00
    同步不是问题,如何解决冲突才是问题。没有什么办法可以完美的自动解决冲突。比如你说的办法,如果本地时间不准就可能丢数据。
    所以分布式代码管理使用分支,和并请求等等措施,让你手动解决冲突。
    OneNote 等笔记也会在有冲突的时候通知你。

    最简单的办法,压根就不提供这样的功能。而是在客户端允许用户手动把数据上传更新到服务器,或者手动将数据同步回客户端本地。你不更新就一直用本地数据。
    然后在同步的时候提醒用户数据可能有冲突,让他自己选用哪个。只要你在服务器保留每个版本的完整快照,不会让客户丢数据就可以了。

    另外记账软件和笔记等等还是不一样的。你可以把它当成一个 Log 收集系统。每条记录都相对独立,而且一旦生成就很少修改,因而也很少产生冲突。你可以将每一次修改都视为创建一条不可变记录,只不过修改时将旧的记录标记为不可用,删除也是如此。
    这样就算同步彻底乱套了,你也就只会多数据,而不会丢。
    dode
        5
    dode  
       2023-09-11 10:38:15 +08:00
    联网后直接覆盖云端啊,要啥字段版本控制,做好表的设计,哪些数据要同步,感觉增量备份比较好,
    大型表,不要修改历史数据
    timethinker
        6
    timethinker  
       2023-09-11 10:40:09 +08:00
    记录一下最后同步时间,注意这里的时间最好是一个逻辑序号,每同步一次在服务端就自增一次。

    客户端拿到这个序号以后,在本地的任何操作,具体表现在存储上都关联上这个序号,这样当你下次同步的时候,就可以查询出所有跟这个序号相关联的数据变动,然后把这些数据+序号提交到服务器。

    当不同的终端/客户端开始进行同步时,服务端就能够取出这个序号,比较一下当前最后同步序号,这样就能知道不同客户端在同步上的先后顺序。

    在技术上有很多种方法来做,上面的序号是一种,还有一种就是写日志,通过快照+重放来实现同步。当然技术只是一方面,如何实现同步的逻辑流程取决于具体的场景,更重要的是你如何处理复杂的边界情况。
    zyxk
        7
    zyxk  
    OP
       2023-09-11 11:18:29 +08:00
    @Mithril @timethinker 感谢各位 非笔记类软件, 更类似于记账软件,这样应该不太存在冲突问题,只要保留最新的就可以了

    @cnoder @dode 感谢,麻烦问下,增量检验或增量备份应该要怎么实现?我的理解是:假如离线,本地修改了后,本地更新数据库,同时标记或记录一下修改的数据 id ,在联网时只同步这些标记的数据吗?
    iosyyy
        8
    iosyyy  
       2023-09-11 11:19:38 +08:00
    可以考虑 Myers 算法
    当数据量大的时候直接让他选择其中一个版本不同意合并
    deeridea
        9
    deeridea  
       2023-09-11 11:51:13 +08:00
    @zyxk 其实 本地录入数据和 线上录入数据 使用不同表进行记录也是个方法,然后接口呈现时进行数据合并,本地端联网时 和云端互换数据 云端下行更新 cloud 表 本地上行更新 local 表
    iOCZ
        10
    iOCZ  
       2023-09-11 12:02:26 +08:00
    记录一下同步时间,每条记录增加 update 时间和同步标志。同步的时候先拉取上次同步后的新修改数据。如果记录更新时间比现在新就覆盖,否则就丢弃并标记为未同步。筛选未同步的记录,然后上传到服务器,replace into 到表里。
    tyzandhr
        11
    tyzandhr  
       2023-09-11 12:07:51 +08:00 via Android
    直接用 firebase realtime database
    bxb100
        12
    bxb100  
       2023-09-11 13:39:09 +08:00
    CRDT
    totoro52
        13
    totoro52  
       2023-09-11 13:52:28 +08:00
    @dode #5 那么问题来了,假设我在 A 电脑上修改了记录,并且增加了很多数据, 然后上传云端,此时我在 B 电脑也写入了很多数据, 然后这个时候联网了,开始同步,会发生什么事
    codehz
        14
    codehz  
       2023-09-11 15:03:37 +08:00   ❤️ 1
    这不直接 CRDT 吗(
    不过如果模型简单的话,可以直接记录修改然后重放
    dode
        15
    dode  
       2023-09-11 15:10:43 +08:00
    @totoro52 楼主说不涉及多个客户端数据合并吧
    mayne95
        16
    mayne95  
       2023-09-11 15:17:49 +08:00
    有没有可能记账软件并不需要服务端,p2p 多端 CRDT 同步就行了。https://github.com/vlcn-io/cr-sqlite
    omerg
        17
    omerg  
       2023-09-11 16:09:35 +08:00
    @zyxk #7 离线修改之后,将修改的记录标记为 dirty ,在线时将 dirty 记录上传。
    zeusho871
        18
    zeusho871  
       2023-09-11 16:11:10 +08:00 via Android
    git......(#误
    horizon
        19
    horizon  
       2023-09-11 19:14:12 +08:00
    sqlite 支持 wasm ,直接强行同步 sqlite ?
    NUT
        20
    NUT  
       2023-09-11 19:18:12 +08:00
    CRDT 不合适, 记账软件,你不能给他把冲突的给干掉。 还是实现一套类似 binlog 的模式,做日志同步。 不过服务器的节点为主节点, 以服务器的变更为准。
    butanediol2d
        21
    butanediol2d  
       2023-09-11 19:54:06 +08:00
    @NUT #20 CRDT 不就是没有冲突吗?
    XiLingHost
        22
    XiLingHost  
       2023-09-11 23:57:13 +08:00
    直接用文本存储+git 版本控制得了
    AItsuki
        23
    AItsuki  
       2023-09-12 02:27:46 +08:00
    这种应用实现难度在前端而不是后端,前端要设计复刻一套后端的业务逻辑,然后进行同步表。
    同步的逻辑基本都是前端处理,后端只做数据版本校验(类似乐观锁的那种版本),符合规则的就入库。如果多设备同步出现冲突,简单的方案是谁先同步谁胜出。总的来说还是比较复杂的,所以我更推荐的是实时数据库。

    例如 realm ,couchdb 等。或者使用云服务,例如 google 的 firebase 的实时数据库,aws 和 azure 我记得也有,忘了叫啥。
    shenyuzhi
        24
    shenyuzhi  
       2023-09-12 12:04:43 +08:00
    最大的坑在于冲突了怎么办。
    如果需要解决冲突,这个问题会非常复杂。
    如果不需要解决冲突,那就简单了,根本不需要自己写服务器端程序,直接对接各种云存储就行了。本地用 sqlite ,每隔一段时间备份到云存储。
    SenLief
        25
    SenLief  
       2023-09-12 17:29:26 +08:00 via iPhone
    同步的解决要远大于记账类软件的开发的。最难得问题就是冲突如何处理?多端同步如何识别相同的内容?
    NUT
        26
    NUT  
       2023-09-14 18:32:13 +08:00
    @butanediol2d CRDT 是用最大可能进行处理冲突。 而不是没有冲突。 可以查一下。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1042 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 20:50 · PVG 04:50 · LAX 12:50 · JFK 15:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.