V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MySQL 5.5 Community Server
MySQL 5.6 Community Server
Percona Configuration Wizard
XtraBackup 搭建主从复制
Great Sites on MySQL
Percona
MySQL Performance Blog
Severalnines
推荐管理工具
Sequel Pro
phpMyAdmin
推荐书目
MySQL Cookbook
MySQL 相关项目
MariaDB
Drizzle
参考文档
http://mysql-python.sourceforge.net/MySQLdb.html
Suomea
V2EX  ›  MySQL

客户端 SQLite 和服务端 MySQL 数据同步的问题

  •  
  •   Suomea · 2021-06-10 11:43:40 +08:00 · 4103 次点击
    这是一个创建于 1248 天前的主题,其中的信息可能已经有所发展或是发生改变。
    场景:用户在客户端创建一条数据,数据肯定会保存在本地的 SQLite 数据库中,如果网络连接正常的话还会调用接口保存在服务端的 MySQL 上。

    问题:1. 进行数据同步该如何处理? 如果新的客户端首次登录肯定会同步服务端的全部历史数据保存到 SQLite,但是后续使用过程中的同步是不是也要全部历史数据同步过来,即使本地已经有了数据。
    2. 这种同步场景有什么好的处理方案吗?
    13 条回复    2021-06-11 11:31:35 +08:00
    supermoonie
        1
    supermoonie  
       2021-06-10 11:54:09 +08:00 via iPhone
    有点类似企业微信的消息同步
    no1xsyzy
        2
    no1xsyzy  
       2021-06-10 12:02:45 +08:00
    1. 可以增量,具体增量可能是有一个绝对单增 ID 的类 Journal 方式,或者远端从不修改已写入数据的话可以单纯地进行末端附加。
    2. 如果你建立了 model 层,任何处理方式甚至改变处理方式应当不会有任何难点。

    但是单纯地 SQLite - MySQL sync 的现成方案也是有的,但我觉得你可能还会涉及不同用户间的可见性的问题
    一些 NoSQL 似乎天然提供了多数据库同步,但也可能涉及用户间可见性问题。
    3dwelcome
        3
    3dwelcome  
       2021-06-10 12:19:43 +08:00
    不知道别人是怎么做的,我简单暴力,直接发把本地每条 SQLite 的最后修改时间打包成 json 数组,给服务器确认,那一些记录是需要同步的。

    如果 json 数据量很大,还可以切片做分段 hash,来减少初始化数据量。
    3dwelcome
        4
    3dwelcome  
       2021-06-10 12:22:42 +08:00
    然后服务器记录一下最后同步时间,下次再次同步时,这个时间点以前的记录,客户端自然就不需要发送了。
    timethinker
        5
    timethinker  
       2021-06-10 12:35:40 +08:00   ❤️ 1
    1:如果是多终端,修改来源不止一处,比较好的方式就是使用订阅机制,相当于多个生产者和多个消费者,同步只需要同步本地不存在的数据,使用一种递增的序列标识来表示数据的前后顺序。

    2:使用日志式的存储比较容易实现,即数据只是简单的追加,不涉及到修改,如果有修改或者删除的需求,也仅仅只是追加一条数据(墓碑记录),当然了,数据无止境的累加也是不现实的,因此可以异步定期的去压缩数据(合并同一条记录的修改、移除已被删除的数据),这其实就是许多数据库背后的原理,用在应用层上也是同样的道理,其目的在于减少复杂的 IO 操作(在本例中是为了减少对数据库的复杂操作),提升整体的处理效率。

    不太清楚你们的应用场景具体是怎么样的,简单的说一下思路:已经发生的事情是客观存在的,就像一个个事件,我们不能改变过去,但是可以补偿过去,其结果就是如果严格按照先后顺序处理这些事件,其结果最终都是一致的。定期压缩数据也只是建立了一个快照点,这样其他客户端就可以直接从这个快照点获取整个数据,然后在基于这个快照点的版本 ID,去同步之后的事件。

    最后说一下问题,多个生产者产生数据可能会遇到冲突问题,需要共识算法来达成一致,这就是典型的分布式问题(比如上面的全局序列 ID/版本号),如果要做到这一步就需要结合业务场景做取舍,取决于你的业务复杂程度。

    举个例子,我们都对 git 比较熟悉吧,如果两个人基于同一个版本提交,那么当他们试图同步彼此的时候,必定有一个人需要 merge 或者 rebase,如果对同一个文件修改了,可能还需要处理冲突。为什么说它是分布式的呢?因为可以脱离服务器,在自己本地独立的进行操作,以后同步的时候只需要大家对提交记录达成共识即可。

    最后,以上这些都是基于你有多个终端修改源,并且需要同步到多个终端上的假设作为前提,如果只有一个生产者,那么这些问题都不存在了。
    xuanbg
        6
    xuanbg  
       2021-06-10 12:54:34 +08:00
    客户端把 SQLite 当作本地缓存用,遵循缓存数据的管理规范就行了。
    Suomea
        7
    Suomea  
    OP
       2021-06-10 13:32:49 +08:00
    可能会有多个客户端 Android/iOS,客户端离线是能进行操作(增删改查)。
    Suomea
        8
    Suomea  
    OP
       2021-06-10 13:34:15 +08:00
    @3dwelcome 支持多端,多端离线也能进行各种操作。
    Suomea
        9
    Suomea  
    OP
       2021-06-10 13:54:27 +08:00
    @xuanbg 问题是每次同步我都要全量检查数据是否已经失效,然后进行更新
    james2013
        10
    james2013  
       2021-06-10 16:15:22 +08:00   ❤️ 1
    做过 1 个类似的项目,比如保存文章
    1.不论是在线环境还是离线环境,客户端的文章增删改操作首先修改本地 sqlite 的文章表,然后将此条操作记录存放到操作记录表中
    2.客户端搞 1 个定时器,定期从本地的操作记录表待上传状态的数据按时间先后顺序放到内存中的队列中
    3.从队列中获取一条记录,调用操作记录对应的接口,接口调用成功,则将操作记录表的此条记录状态设置为已成功;如果网络问题,则进行重试操作
    4.当本地操作记录表没有待上传的数据后,将服务器的数据更新到本地
    增量同步参考:
    1)服务器提供文章列表简略接口:只有文章 id,更新时间
    2)客户端调用上一步的接口,发现本地文章的更新时间与服务器不一致时,将该文章的 id 存入到列表中
    3)调用文章详情列表,传入上一步需要更新的文章 id 列表,再更新到本地
    Kinnice
        11
    Kinnice  
       2021-06-10 17:15:41 +08:00
    每个操作记录一条,每次同步这些操作语句
    joesonw
        12
    joesonw  
       2021-06-11 11:30:34 +08:00
    couchbase 就是干你这种事的. 服务器和客户端数据库保持一致, 中间可以写 js 的脚本做数据过滤(每个客户仅可访问自己的数据)
    joesonw
        13
    joesonw  
       2021-06-11 11:31:35 +08:00
    @joesonw 订正: CouchDB
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1618 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 16:56 · PVG 00:56 · LAX 08:56 · JFK 11:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.