数据同步
juicefs sync
是强大的数据同步工具,可以在所有支持的存储之间并发同步或迁移数据,包括对象存储、JuiceFS、本地文件系统,你可以在这三者之间以任意方向和搭配进行数据同步。除此之外,还支持同步通过 SSH 访问远程目录、HDFS、WebDAV 等,同时提供增量同步、模式匹配(类似 rsync)、分布式同步等高级功能。
juicefs sync
功能的代码在社区版和企业版之间共享代码,因此即便交叉混用不同版本的 JuiceFS 客户端,sync
命令也能正常工作——除 了一个特例,就是使用 jfs://
协议头的情况。社区版和企业版客户端有着不同的元数据引擎实现,因此如果用到了 jfs://
协议头,则不能混用不同版本的客户端。
juicefs sync
用法以及常见示范如下:
juicefs sync [command options] SRC DST
# 从 OSS 同步到 S3
juicefs sync oss://mybucket.oss-cn-shanghai.aliyuncs.com s3://mybucket.s3.us-east-2.amazonaws.com
# 拷贝所有以 .gz 结 尾的文件
juicefs sync --match-full-path --include='**.gz' --exclude='*' s3://xxx s3://xxx
# 拷贝不以 .gz 结尾的所有文件
juicefs sync --match-full-path --exclude='**.gz' s3://xxx/ s3://xxx
# 拷贝所有文件,但忽略名为 tmpdir 的子目录
juicefs sync --match-full-path --exclude='**/tmpdir/**' s3://xxx/ s3://xxx
快速上手视频
模式匹配
你可以通过 --exclude
和 --include
来包含或排除要同步的文件路径。如果不提供任何规则,默认会同步所有扫描到的文件(默认就是 --include='*'
)。但如果需要使用 --include
实现只包含特定命 名模式的文件,则必须同时使用 --exclude
来排除其他文件,具体请参考上方的示范命令。
当提供多个匹配模式时,取决于你具体使用的「过滤模式」,对于判断是否要同步某个文件可能会变得很困难。此时建议加上 --dry --debug
选项提前查看要同步的具体文件是否符合预期,如果不符合预期则需要调整匹配模式。
匹配规则
匹配规则指的是给定一个路径与一个模式,然后确定该路径能否匹配上该模式。模式可以包含一些特殊字符(类似 shell 通配符):
- 单个
*
匹配任意字符,但在遇到/
时终止匹配; **
匹配任意字符,包括/
;?
匹配任意非/
的单个字符;[...]
匹配一组字符,例如[a-z]
匹配任意小写字母;[^...]
不匹配一组字符,例如[^abc]
匹配除a
、b
、c
外的任意字符。
此外,还有一些匹配规则需要注意:
- 如果匹配模式中不包含特殊字符,将会完整匹配路径中的文件名。比如
foo
可以匹配foo
和xx/foo
,但不匹配foo1
(无法前缀匹配)、2foo
(无法后缀匹配)和foo/xx
(foo
不是目录); - 如果匹配模式以
/
结尾,将只匹配目录,而不匹配普通文件; - 如果匹配模式以
/
开头,则表示匹配完整路径(路径不需要以/
开头),因此/foo
匹配的是传输中根目录的foo
文件。
以下是一些匹配模式的例子:
--exclude '*.o'
将排除所有文件名能匹配*.o
的文件;--exclude '/foo/*/bar'
将排除根目录中名为foo
的目录向下「两层」的目录中名为bar
的文件;--exclude '/foo/**/bar'
将排除根目录中名为foo
的目录向下「任意层级」的目录中名为bar
的文件。
sync
命令支持「完整路径过滤」和「逐层过滤」两种模式,这两种模式都支持使用 --include
和 --exclude
来过滤文件,但是解析的行为并不一样:默认情况下,sync
命令使用逐层过滤模式,这种模式的过滤行为无论是理解还是使用都较为复杂,但是基本兼容 rsync 的 --include/--exclude
选项,所以只推荐已经习惯了 rsync 过滤行为的用户使用。对于大多数 JuiceFS 用户,推荐通过 --match-full-path
选项来使用完整路径过滤模式,他的工作流程更容易理解。
完整路径过滤模式(推荐) 新增自 v1.2.0
从 v1.2.0 开始,sync 命令支持 --match-full-path
选项。完整路径过滤模式是指对于待匹配的对象,直接将其「全路径」与多个模式依次进行匹配,一旦某个匹配模式匹配成功将会直接返回结果(「同步」或者「排除」),忽略后续的匹配模式。
下面是完整路径过滤模式的工作流程图:
例如有一个路径为 a1/b1/c1.txt
的文件,以及 3 个匹配模式 --include 'a*.txt' --inlude 'c1.txt' --exclude 'c*.txt'
。在完整路径过滤模式下,会直接将 a1/b1/c1.txt
这个字符串与匹配模式依次进行匹配。具体步骤为:
- 尝试将
a1/b1/c1.txt
与--include 'a*.txt'
匹配,结果是不匹配。因为*
不能匹配/
字符,参见「匹配规则」; - 尝试将
a1/b1/c1.txt
与--inlude 'c1.txt'
匹配,此时根据匹配规则将会匹配成功。后续的--exclude 'c*.txt'
虽然根据匹配规则也能匹配上,但是根据完整路径过滤模式的逻辑,一旦匹配上某个模式,后续的模式将不再尝试匹配。所以最终的匹配结果是「同步」。
以下是更多示例:
--exclude '/foo**'
将排除所有根 目录名为foo
的文件或目录;--exclude '**foo/**'
将排除所有以foo
结尾的目录;--include '*/' --include '*.c' --exclude '*'
将只包含所有目录和后缀名为.c
的文件,除此之外的所有文件和目录都会被排除;--include 'foo/bar.c' --exclude '*'
将只包含foo
目录和foo/bar.c
文件。
逐层过滤模式
逐层过滤模式的核心是先将完整路径按照目录层级拆分,并逐层组合成多个字符串序列。比如完整路径为 a1/b1/c1.txt
,组成的序列就是 a1
、a1/b1
、a1/b1/c1.txt
。然后将这个序列中的每个元素都当成完整路径过滤模式中的路径,依次执行「完整路径过滤」。
如果某个元素匹配上了某个模式,则会有两种处理逻辑:
- 如果该模式是 exclude 模式,则直接返回「排除」行为,作为最终的匹配结果;
- 如果该模式是 include 模式,则跳过本层级的后续待匹配的模式,直接进入下一层级。
如果某层的所有模式都未匹配,则进入下一层级。如果所有层级匹配完毕后都没有返回「排除」,则返回默认的行为——即「同步」。
下面是逐层过滤模式的工作流程图:
例如有一个路径为 a1/b1/c1.txt
的文件,以及 3 个匹配模式 --include 'a*.txt' --inlude 'c1.txt' --exclude 'c*.txt'
。在逐层过滤模式中,组成的序列就是 a1
、a1/b1
、a1/b1/c1.txt
。具体匹配步骤为:
- 第一层级的路径为
a1
,根据匹配模式,结果是全部未匹配。进入下一层级; - 第二层级的路径为
a1/b1
,根据匹配模式,结果是全部未匹配。进入下一层级; - 第三层级的路径为
a1/b1/c1.txt
,根据匹配模式,将会匹配上--inlude 'c1.txt'
模式。该模式的行为是「同步」,进入下一层级; - 由于没有下一层级了,所以最终返回的行为是「同步」。
上面的例子是到最后一层才匹配成功,除此之外可能还有两种情况:
- 在最后一层之前匹配成功,且匹配模式是 exclude 模式,则直接返回「排除」行为作为最终结果,跳过后续的所有层级;
- 所有层级都已经匹配完毕,但都未匹配上,此时也将会返回「同步」行为。
如果你已经熟悉上一小节的“完整路径过滤模式”,那么逐层过滤其实就是按路径层级由高到低依次执行完整路径过滤,每层过滤只有两种结果:要么直接得到「排除」作为最终结果,要么进入下一层级。得到「同步」结果的唯一方式就是执行完所有过滤层级。
以下是更多示例:
-
--exclude /foo
将排除所有根目录名为foo
的文件或目录; -
--exclude foo/
将排除所有名为foo
的目录; -
对于
dir_name/.../.../...
这种多级目录来说,将按照目录层级匹配dir_name
下的所有路径。如 果某个文件的父目录被「排除」了,那即使加上了这个文件的 include 规则,也不会同步这个文件。如果想要同步这个文件就必须保证它的「所有父目录」都不要被排除。例如,下面的例子中/some/path/this-file-will-not-be-synced
文件将不会被同步,因为它的父目录some
已经被规则--exclude '*'
所排除:--include '/some/path/this-file-will-not-be-synced' \
--exclude '*'一种解决方式是包含目录层级中的所有目录,也就是使用
--include '*/'
规则(需放在--exclude '*'
规则的前面);另一种解决方式是为所有父目录增加 include 规则,例如:--include '/some/' \
--include '/some/path/' \
--include '/some/path/this-file-will-be-synced' \
--exclude '*'
存储协议
凡是 JuiceFS 支持的存储系统,都可以使用 sync 命令来同步数据。特别一提,如果其中一端是 JuiceFS 文件系统,那么建议优先使用无挂载点同步方式。
无挂载点同步 新增自 v1.1
在两个存储系统之间同步数据,如果其中一方是 JuiceFS,推荐直接使用 jfs://
协议头,而不是先挂载 JuiceFS,再访问本地目录。这样便能跳过挂载点,直接读取或写入数据,在大规模场景下,绕过 FUSE 挂载点将能节约资源开销以及提升数据同步性能。
myfs=redis://10.10.0.8:6379/1 juicefs sync s3://ABCDEFG:[email protected]/movies/ jfs://myfs/movies/
对象存储与 JuiceFS 之间同步
将对象存储的 movies
目录同步到 JuiceFS 文件系统:
# 挂载 JuiceFS
juicefs mount -d redis://10.10.0.8:6379/1 /mnt/jfs
# 执行同步
juicefs sync s3://ABCDEFG:[email protected]/movies/ /mnt/jfs/movies/
将 JuiceFS 文件系统的 images
目录同步到对象存储:
# 挂载 JuiceFS
juicefs mount -d redis://10.10.0.8:6379/1 /mnt/jfs
# 执行同步
juicefs sync /mnt/jfs/images/ s3://ABCDEFG:[email protected]/images/
对象存储与对象存储之间同步
将对象存储的全部数据同步到另一个对象存储桶:
juicefs sync s3://ABCDEFG:[email protected] oss://ABCDEFG:[email protected]
本地及服务器之间同步
对于本地计算机上的目录之间拷贝文件,直接指定数据源与目标端的路径即可,比如将 /media/
目录同步到 /backup/
目录:
juicefs sync /media/ /backup/