lmk123 / blog

个人技术博客,博文写在 Issues 里。
https://github.com/lmk123/blog/issues
623 stars 35 forks source link

客户端 / 服务器数据同步机制的一点思考 #82

Open lmk123 opened 3 years ago

lmk123 commented 3 years ago

最近要做一个数据同步的功能,先介绍一下类似的场景:

假设我有一个待办事项 APP,同时支持网页端、移动端和桌面端,功能就是待办事项清单,用户可以在任意端新增、修改、删除待办事项,其他端都要同步到数据。

第一个想法:完全从数据库读取数据

这应该是最常见的做法了:无论从哪个端打开待办事项,都从服务器加载数据;对待办事项的新增、修改、删除操作都在服务器的数据库进行,本地不保存任何数据。

但这种模式有一个缺点:APP 没办法离线使用了。对于一个待办事项 APP 而言,用户应该是无需登录就可以使用的。

第二个想法:判断操作是在哪个端进行的,然后下载新增的数据

先给用户登录过的每个端都生成一个唯一的设备 id 进行区分。然后,当用户在其中一个端 A 新增待办事项之后,先在本地数据库新增,然后将这次新增的数据提交到服务器,且标识是由端 A 新增的;当用户从别的端 B 打开 APP 时,就从服务器查询数据库,找到不是由端 B 新增的数据,然后保存到端 B 的本地数据库。

但是……这个办法只能找到新增的数据,对修改和删除操作无效。

第三个想法:记录用户的操作

这个做法有以下几个要点:

  1. 用户登录时,从服务器将所有数据都下载到本地数据库;
  2. 之后,用户对本地数据库的所有操作都记录下来发送给服务器;
  3. 当用户切换到另一个端时,根据上次同步数据的时间查询用户的操作日志,将这些操作应用到本地数据库即可。

举例来说,用户登录了端 A 和端 B,登录成功后,需要先把服务器中已有的数据全部下载到本地数据,并记录下下载的时间;然后,当用户在端 B 对数据进行了新增、修改和删除后,这些操作记录都发送到服务器保存下来,比如“下午 4 点用户删除了一项 id 为 xxx 的待办事项”、“晚上 7 点用户新增了一条待办事项,id 是 xxx”;最后,当用户又切换回端 A 时,根据上次同步数据的时间去查询服务器,服务器把上次同步过后、用户进行的操作日志返回给端 A,端 A 再根据这些操作对本地数据库进行同样的操作就可以了。

目前看下来,第三个想法是比较完善的,这种做法有点类似于 Git 的形式。

另外,这种离线数据同步似乎没有现成的解决方案,基于 WebSocket 的数据同步倒是有 ShareDB。不知道有没有路过的大佬能有更好的离线数据同步方式或现成的解决方案。

whalecold commented 3 years ago

redis 的 AOF 机制也是用的第三种方法,这种方式用的还蛮多的,好像需要重写去压缩下数据,数据会随着操作的变多量越来越大。