SQLite 数据库远程复制工具

1. 概述

下面的命令会让 REPLICA 成为 ORIGIN 的副本:

$ sqlite3_rsync ORIGIN REPLICA ?OPTIONS?

使用 --help 或 -? 参数可查看完整选项列表。选项可以放在 ORIGIN 和 REPLICA 参数之前、之后,或两者之间。

加入 -v 选项可获得更多输出,格式类似 rsync。

2. 功能

  1. ORIGIN 或 REPLICA 中的任意一端可以采用 USER@HOST:PATH 格式;另一端则是普通 PATH。该工具会让 REPLICA 成为 ORIGIN 的副本。

    1. 如果 REPLICA 尚不存在,就创建它。

    2. 通信使用 ssh,因此 USER@HOST 可以是 SSH 别名。

    3. 并不要求 ORIGIN 或 REPLICA 必须有一端位于远程机器。两端都在本地时,sqlite3_rsync 也能正常工作。

  2. 该工具运行时,两个数据库都可以处于“在线使用”状态。其他程序可以继续连接任意一端的数据库,也可以写入 ORIGIN、读取 REPLICA。

    REPLICA 得到的是 sqlite3_rsync 命令开始时 ORIGIN 的快照。命令执行期间,如果其他进程修改了 ORIGIN,这些变更仍会应用到 ORIGIN,但不会传输到 REPLICA。因此,REPLICA 最终是 ORIGIN 在某个时间点的完全一致的快照。

  3. 同步采用节省带宽的协议,类似 rsync,工具名称也由此而来。

3. 限制

  1. 两个数据库文件都必须采用 WAL 模式,并且页大小相同。 ← 这两项限制已在 3.50.0 版本(2025-05-29)中取消。

  2. sqlite3_rsync 运行期间,REPLICA 为只读。仍可查询 REPLICA,但不能执行写事务。

  3. 每次调用只能同步一个数据库。目前还不能像标准 rsync 那样,通过通配符同步多个不同数据库。

  4. ORIGIN 和 REPLICA 至少有一个必须位于本机,不能两端都是其他机器上的数据库。

  5. 远程系统必须把该工具安装到 SSH 默认 $PATH 中的某个目录。/usr/local/bin 通常是不错的选择。也可以用 --exe
    NAME
    参数指定远程可执行文件的位置,例如 --exe /opt/bin/sqlite3_rsync。

  6. 副本与源数据库非常接近,但并非完全相同。副本中所有表和索引内容都逐字节一致,不过 数据库头 可能有少量变化。具体来说,副本与源库可能存在以下差异:

    1. 数据库头第24至27字节中的 变更计数器 可能在副本中递增。

    2. 数据库头第96至99字节中的 SQLite 写入库版本号,将使用生成副本的 sqlite3_rsync 程序所对应的 SQLite 版本号,而不是最后一次写入源数据库的程序版本号。

  7. 在 Windows 上,如果 HOST 只有一个字母,且前面没有 USER@,它会被解释为 Windows 盘符,而不是主机名。

4. 安装方法

把 sqlite3_rsync 可执行文件放在 $PATH 中的某个目录,即可安装。如果与远程系统同步,本机和远程机器都必须安装 sqlite3_rsync。远端安装时,确认 SSH 使用的 $PATH 能找到它;/usr/local/bin 通常是合适的位置。

不过,macOS 上 ssh 的默认 PATH 是 /usr/bin:/bin:/usr/sbin:/sbin,而且 macOS 不允许向这些目录添加新程序。作为变通办法,sqlite3_rsync 会尝试按下面的方式扩展 PATH:

PATH=$HOME/bin:/usr/local/bin:/opt/homebrew/bin:$PATH

因此,与远程 Mac 同步时,把 sqlite3_rsync 二进制文件安装在以下三个新增 PATH 目录中的任意一个,通常就足够了:

  • $HOME/bin

  • /usr/local/bin

  • /opt/homebrew/bin

如果必须把 sqlite3_rsync 安装到远程机器上的其他非标准位置,直接用命令行的 --exe 选项指定精确位置即可。例如:

sqlite3_rsync sample.db mac:sample.db --exe /some/weird/place/sqlite3_rsync

本文原作者一直未能成功让 SSHD 在 Windows 上运行。也许未来的版本中,他能解决这个问题,并提供与远程 Windows 机器同步数据库的说明。

4.1. 向后兼容问题

sqlite3_rsync 会在启动时协商源端与副本端的同步算法细节,并选择双方都支持的最先进算法。不过,协商逻辑存在一个缺少 fflush() 调用的缺陷:当本地使用 3.50.0 或更新版本、远程使用 3.49.1 或更早版本时,应用可能挂起。最好的解决办法是在两端安装最新版本的 sqlite3_rsync。如果做不到,可以在命令行加入 --protocol 1 绕过问题。

5. 网络带宽

协议的核心思路是:副本端向源端发送页或页组的密码学哈希。源端返回有差异的页内容;如果多页哈希不匹配,则要求更细粒度的哈希。如果同步前源端与副本端差异很大,交换哈希的开销可能使总网络流量超过整个数据库的大小,但额外带宽并不多,最多只有几个百分点。另一方面,如果两端一开始就非常相似——这也是常见情况——总带宽往往小于数据库大小的0.01%。原文测试中,500MB 数据库通常只需要约20KB 网络流量就能同步。

在3.50.0版本(2025-05-29)之前,协议只发送单独页的哈希,不发送页组哈希。这意味着即使两端一开始完全相同,所需带宽通常也至少约为数据库大小的0.5%。在源端和副本端差异很少时,3.50.0及之后版本更节省带宽。不过,两端都必须安装3.50.0或更新版本,否则协议会退回旧的、带宽效率较低的算法。

6. 为什么不能直接使用普通 rsync?

普通 rsync 不理解 SQLite 事务。它会把 ORIGIN 复制到 REPLICA,但这个副本可能不一致:一部分来自某个事务,另一部分来自不同事务,最终数据库副本可能损坏。

如果 rsync 运行的整个过程中没有其他进程连接数据库,并且数据库不存在 热日志,rsync 就能生成一致的副本。但如果无法保证同时满足这两个条件,rsync 就可能生成损坏的副本。相比之下,sqlite3_rsync 始终生成一致的副本。

本页最后更新时间:2025-11-13 07:12:58Z

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容