同步神器Graft:告别全量同步

"部分复制"听起来很简单——不就是同步你APP需要的数据吗?但选方法可让人头疼:逻辑复制能精确追踪每次改动(但保证强一致性很麻烦),物理复制虽然简单却要同步所有改动(包括没用的)。要是能结合两者的优点该多好?这就是我今天开源的Graft存储引擎的核心思路——专为"懒人式部分复制"设计,既保证强一致性,又能横向扩展,数据还能永久保存。

Graft主要解决这些问题:
1. 离线优先的APP:把同步存储的活甩给Graft,开发更简单
2. 跨设备同步:手机/电脑/网页随时同步数据,不受平台限制
3. 随处部署:能在服务器、小程序甚至U盘里运行
4. 啥数据都能同步:数据库/文件/自定义格式都行,且数据绝对一致

做SQLSync项目时我发现需要这个工具。SQLSync是把SQLite数据库搬到浏览器里的技术(原理类似Git),但它像物理复制那样把所有改动都同步给每个客户端——这在服务器还行,但在浏览器里就太笨重了。

于是我开始寻找更适合边缘计算(比如手机APP)的同步方案,需要满足:
✓ 让客户端自己决定同步时间
✓ 只同步需要的数据
✓ 随时随地能同步(包括离线状态)
✓ 能同步任意类型数据
✓ 还要保证强一致性

结果发现根本没有现成方案,那就自己造一个吧!

#与众不同的同步方案
现有方案基本分两类:
① 全量同步:把整个数据库拷给每个客户端——太占内存
② 逻辑同步(比如CDC/CRDT):只同步字段级改动,但必须深度改造APP

Graft走了第三条路:
• 像全量同步那样不挑数据类型(只管传输二进制)
• 像逻辑同步那样只传变更摘要

核心概念叫"Volume"——由固定大小的"Page"组成的存储单元。客户端通过"快照"来读写数据,Graft则智能地只同步必要的部分。

#懒人同步:想什么时候同步都行
现实中的手机APP经常断网、内存有限。Graft允许客户端随时"快进"到最新状态,同步时只需问服务器:"上次同步后改了啥?"

服务器返回的"graft"(名字来源于植物嫁接)就像变更清单,告诉客户端哪些页面需要更新。关键是——这时只传变更清单,不传实际数据!要不要下载新数据完全由客户端决定。

#精准同步:只下载需要的部分
在浏览器/小程序里不可能下载整个数据库。客户端拿到变更清单后,可以像拼拼图那样只下载缺失的部分。

Graft提供三种预加载策略:
1. 智能预测:用Leap算法猜你可能需要哪些数据
2. 人工指导:比如你知道用户总要查看个人资料页,就提前加载
3. 全量回退:必要时也能退化成全量同步(适合服务器端)

#边缘友好:数据就在你身边

Graft通过两种方式优化:
① 数据缓存在全球边缘节点,访问速度飞快
② 客户端极其轻量,能塞进任何环境(甚至冰箱上的显示屏)

#强一致性:冲突也不怕
采用"可序列化快照隔离"技术:
• 读操作互不干扰
• 写操作严格按顺序执行
当离线修改和服务器冲突时,Graft会拒绝提交,客户端可以选择:
- 重试:拉取最新数据重新提交
- 合并:类似Git的冲突处理
- 分叉:直接另存为新版本

#Graft能用来做什么?
• 离线应用:便签/待办清单,断网也能用
• 全平台同步:手机/电脑数据自动同步
• 快速启动:新设备秒获最新数据
• 万物皆可同步:AI模型/地理数据/猫照片...

#Graft SQLite扩展(libgraft)
今天,libgraft这是开始使用 Graft 的最简单方法。它是原生 SQLite 扩展,可以在任何 SQLite 上运行。它使用 Graft 复制客户端实际使用的数据库部分,从而可以在资源受限的环境中运行 SQLite。
libgraft实现SQLite 虚拟文件系统 (VFS),允许它拦截对数据库的所有读写操作。它提供与 SQLite 在WAL 模式下运行时相同的事务和并发语义。使用libgraft可为您的应用程序带来以下好处:

  • 与对象存储进行异步复制
  • 实现懒人式部分复制:边缘和设备中的惰性部分副本
  • 保证强一致性:可序列化快照隔离
  • 支持数据回滚:时间点恢复
如果您有兴趣使用libgraft,可以在这里找到文档