rclone union 后端深度解析:策略驱动的多远程统一视图与 writeback 缓存
2026/9/8 21:33:21 网站建设 项目流程

rclone union 后端深度解析:策略驱动的多远程统一视图与 writeback 缓存

【免费下载链接】rclone"rsync for cloud storage" - Google Drive, S3, Dropbox, Backblaze B2, One Drive, Swift, Hubic, Wasabi, Google Cloud Storage, Azure Blob, Azure Files, Yandex Files项目地址: https://gitcode.com/GitHub_Trending/rc/rclone

union是 rclone 提供的"远程统一"后端(自 v1.44 引入),它把多个远程(远程或本地路径)合并成一个统一视图,让你用一条rclone命令同时操作多个存储端。本文基于官方文档 docs/content/union.md 并对照 backend/union/union.go、backend/union/policy/policy.go 等源码实现,完整覆盖 union 的配置流程、三大行为类别(action/create/search)下的 15 种策略、:ro/:nc/:writeback标签语义以及 writeback 缓存机制,读完后你可以独立完成 union remote 的配置、按配额/路径保留需求选择合适的策略组合,并理解其并行读写与配额缓存的底层实现。

union 是什么:把多个远程合并为一个入口

union后端将若干远程拼接在一起,形成一个统一的视图。在rclone config初始化配置时,你需要以空格分隔的列表指定上游(upstream)远程,上游既可以是本地路径,也可以是其他远程。

三个关键标签可以附加在 upstream 路径末尾:

  • :ro(read only):该远程只读,文件只从这里读取,绝不被写入;
  • :nc(no create):该远程不允许创建新文件或新目录;
  • :writeback:在其他远程中发现的文件会被回写到该远程,详见后文 writeback 小节。

例如remote:directory/subdirectory:roremote:directory/subdirectory:nc

这些标签的解析实现在 backend/union/upstream/upstream.go:upstream.New按后缀顺序剥离:ro:nc:writeback并设置writable/creatable/writeback标志。其中:ro会同时置writable=falsecreatable=false:nc只置creatable=false——这与文档描述一致:read-only 远程既不能写也不能建,no-create 远程可以写已有文件但不能建新对象。

子目录映射与路径透传

upstream 中允许使用子文件夹。假设名为backup的 union remote 的上游是mydrive:private/backup,那么执行rclone mkdir backup:desktop与执行rclone mkdir mydrive:private/backup/desktop完全等价。

union 不会对含..段的路径做特殊处理:rclone mkdir backup:../desktoprclone mkdir mydrive:private/backup/../desktop完全等价,路径段会原样透传到上游远程。

配置 union remote:完整交互流程

下面以把本地文件夹合并为一个名为remote的 union 为例。首先运行:

rclone config

随后进入交互式配置流程:

No remotes found, make a new one? n) New remote s) Set configuration password q) Quit config n/s/q> n name> remote Type of storage to configure. Choose a number from below, or type in your own value [snip] XX / Union merges the contents of several remotes \ "union" [snip] Storage> union List of space separated upstreams. Can be 'upstreama:test/dir upstreamb:', '\"upstreama:test/space:ro dir\" upstreamb:', etc. Enter a string value. Press Enter for the default (""). upstreams> remote1:dir1 remote2:dir2 remote3:dir3 Policy to choose upstream on ACTION class. Enter a string value. Press Enter for the default ("epall"). action_policy> Policy to choose upstream on CREATE class. Enter a string value. Press Enter for the default ("epmfs"). create_policy> Policy to choose upstream on SEARCH class. Enter a string value. Press Enter for the default ("ff"). search_policy> Cache time of usage and free space (in seconds). This option is only useful when a path preserving policy is used. Enter a signed integer. Press Enter for the default ("120"). cache_time> Remote config Configuration complete. Options: - type: union - upstreams: remote1:dir1 remote2:dir2 remote3:dir3 Keep this "remote" remote? y) Yes this is OK e) Edit this remote d) Delete this remote y/e/d> y Current remotes: Name Type ==== ==== remote union e) Edit existing remote n) New remote d) Delete remote r) Rename remote c) Copy remote s) Set configuration password q) Quit config e/n/d/r/c/s/q> q

三个策略项(action_policy默认epallcreate_policy默认epmfssearch_policy默认ff)直接对应 backend/union/union.go 中fs.RegInfo声明的选项及其Default值,也对应 backend/union/common/options.go 的Options结构体(另含upstreamscache_time、已弃用的remotesmin_free_space)。

基本用法:对 union remote 执行常规命令

配置完成后即可像操作普通远程一样使用:

列出remote1:dir1remote2:dir2remote3:dir3顶层目录:

rclone lsd remote:

列出这三个远程中的全部文件:

rclone ls remote:

把另一个本地目录复制进 union 中名为source的目录(按默认create_policy=epmfs,会被放到remote3:dir3,即路径存在且剩余空间最多的那个上游):

rclone copy C:\source remote:source

从源码看,List的实现(backend/union/union.go)会对所有上游并发调用u.List(ctx, dir),再用mergeDirEntries按条目名(Remote())归并候选项——同名文件/目录来自不同上游时会被包装为携带全部候选的 unionObject/Directory,之后再由 search 策略从中挑选一个作为实际返回值;只有当所有上游都报"目录不存在"时才返回ErrorDirNotFound。这解释了为什么ls remote:能看到所有上游的合并视图。

行为类别与策略:action、create、search

union 后端的行为设计借鉴了 mergerfs 的思路:所有功能被划分为三个类别——action(修改已存在的文件/目录)、create(创建不存在的文件/目录)、search(读取与列举)。每个功能或类别都可以被赋予一个策略(policy),策略决定了执行该行为时选择哪个文件/目录(即选择哪个上游)。任意策略都可以分配给任意类别,尽管某些组合在实践中并不实用。例如rand(随机)用于文件创建尚可,但如果用于delete且同一文件存在多份副本时,行为会非常怪异。

功能类别划分

类别说明包含功能
action写入已存在的文件move、rmdir、rmdirs、delete、purge,以及 copy、sync(作为目标且文件已存在时)
create创建不存在的文件copy、sync(作为目标且文件不存在时)
search读取与列举文件ls、lsd、lsl、cat、md5sum、sha1sum,以及 copy、sync(作为源)
N/A不适用size、about

路径保留(Path Preservation)

策略分为两种基本类型:path preserving(路径保留)与non-path preserving(非路径保留)。

所有以ep开头的策略(epffeplfseplusepmfseprandepall)都是路径保留型,ep即 existing path。路径保留策略只考虑"被访问的相对路径已经存在"的上游;使用非路径保留策略时,路径会在目标上游中按需创建(对应源码中mkdir会递归创建父目录,见 backend/union/union.go)。

依赖配额信息的策略

部分策略依赖配额(usage)信息。只有当上游支持相应配额字段时才应使用这些策略:

策略所需字段
lfs、eplfsFree(剩余空间)
mfs、epmfsFree(剩余空间)
lus、eplusUsed(已用空间)
lno、eplnoObjects(对象数量)

要检查上游是否支持某字段,可运行rclone about remote: [flags]查看所需字段是否存在。源码侧对应 backend/union/upstream/upstream.go 中的About/GetFreeSpace/GetUsedSpace/GetNumObjects:这些值带有cache_time(默认 120 秒)的本地缓存,缓存过期后通过上游的About接口(15 秒超时)刷新;字段不支持时返回ErrUsageFieldNotSupported,策略会把该上游视为"无限空间"处理(见 backend/union/policy/epmfs.go 中的 Notice 日志)。

过滤规则(Filters)

策略的职责是搜索上游远程并为功能构造待操作的列表,负责过滤与排序。排序方式由策略类型决定,而过滤逻辑大体统一:

  • 所有search策略不做过滤;
  • 所有action策略会过滤掉标记为read-only:ro)的远程;
  • 所有create策略会过滤掉标记为read-onlyno-create:nc)的远程。

若所有远程都被过滤掉,则返回错误。这与 backend/union/policy/policy.go 中的filterRO/filterNC一致:各策略的Action入口先调用filterROCreate入口先调用filterNC,过滤后为空则返回fs.ErrorPermissionDenied

全部策略说明

策略命名同样借鉴 mergerfs,但并不完全相同——由于远程文件系统的延迟远大于本地,部分策略语义有所调整。完整策略表如下:

策略说明
allSearch 类别:同epall。Action 类别:同epall。Create 类别:作用于所有上游。
epall (existing path, all)Search:按配置顺序,操作第一个相对路径存在者。Action:作用于所有找到的上游。Create:作用于所有相对路径存在的上游。
epff (existing path, first found)按上游响应时间,操作第一个相对路径存在者。
eplfs (existing path, least free space)在相对路径存在的所有上游中,选剩余空间最少者。
eplus (existing path, least used space)在相对路径存在的所有上游中,选已用空间最少者。
eplno (existing path, least number of objects)在相对路径存在的所有上游中,选对象数量最少者。
epmfs (existing path, most free space)在相对路径存在的所有上游中,选剩余空间最多者。
eprand (existing path, random)调用epall后随机化,只返回一个上游。
ff (first found)Search:同epff。Action:同epff。Create:按上游响应时间操作第一个找到的上游。
lfs (least free space)Search:同eplfs。Action:同eplfs。Create:选可用剩余空间最少的上游。
lus (least used space)Search:同eplus。Action:同eplus。Create:选已用空间最少的上游。
lno (least number of objects)Search:同eplno。Action:同eplno。Create:选对象数量最少的上游。
mfs (most free space)Search:同epmfs。Action:同epmfs。Create:选可用剩余空间最多的上游。
newest选 mtime 最大(最新)的文件/目录。
rand (random)调用all后随机化,只返回一个上游。

每个策略都是 backend/union/policy/ 目录下的独立文件(epall.goepff.goeplfs.goepmfs.gorand.gonewest.go等共 16 个),通过init()中的registerPolicy注册进全局策略表,policy.Get按名称(不区分大小写)取出,见 backend/union/policy/policy.go。

writeback:用:writeback搭一个简易读缓存

upstream 上的:writeback标签可以搭出一个简单的缓存系统:

[union] type = union action_policy = all create_policy = all search_policy = ff upstreams = /local:writeback remote:dir

工作机制:

  • 读路径:文件被打开读取时,如果文件在remote:dir而不在/local,rclone 会先把文件完整复制到/local,再返回指向/local中副本的句柄。复制等价于rclone copy,因此若配置了--multi-thread-streams会被使用;所有回拷都会以 INFO 级别记录日志。
  • 写路径:写入文件时会同时写入remote:dir/local两端。

upstreams中可以加入任意数量的远程,但:writeback标签只能有一个。rclone 除回写文件外不会以任何方式管理:writeback远程——过期文件清理、缓存容量控制等都需要自行处理。

源码印证了两处关键行为:

  1. 唯一性约束在 backend/union/upstream/upstream.go 的Prepare中强制:发现 0 个 writeback 直接放行,超过 1 个则报错can only have 1 :writeback not %d,并为其余上游设置writebackFs指针;
  2. 回读逻辑在 backend/union/entry.go 的Object.Open:加锁后调用o.Object.Writeback(ctx),后者(backend/union/upstream/upstream.go)在存在writebackFs时通过operations.Copy把当前对象复制到 writeback 上游并返回新对象,随后Open打开的就是这个本地副本。

标准选项与高级选项

以下是 union 后端专属选项(摘自 docs/content/union.md 的自动生成选项段):

--union-upstreams

空格分隔的上游列表。可以写成'upstreama:test/dir upstreamb:''"upstreama:test/space:ro dir" upstreamb:'等形式(含空格的路径需加引号)。

  • Config:upstreams
  • Env Var:RCLONE_UNION_UPSTREAMS
  • Type: string
  • Required: true

--union-action-policy

ACTION 类别选择上游的策略。

  • Config:action_policy
  • Env Var:RCLONE_UNION_ACTION_POLICY
  • Type: string
  • Default:epall

--union-create-policy

CREATE 类别选择上游的策略。

  • Config:create_policy
  • Env Var:RCLONE_UNION_CREATE_POLICY
  • Type: string
  • Default:epmfs

--union-search-policy

SEARCH 类别选择上游的策略。

  • Config:search_policy
  • Env Var:RCLONE_UNION_SEARCH_POLICY
  • Type: string
  • Default:ff

--union-cache-time

已用与剩余空间的缓存时间(秒)。仅在使用路径保留(ep*)策略时有意义。

  • Config:cache_time
  • Env Var:RCLONE_UNION_CACHE_TIME
  • Type: int
  • Default: 120

高级选项 --union-min-free-space

lfs/eplfs 策略可用的最低剩余空间。某远程剩余空间低于该值时,lfs/eplfs 策略不会考虑它。

  • Config:min_free_space
  • Env Var:RCLONE_UNION_MIN_FREE_SPACE
  • Type: SizeSuffix
  • Default: 1Gi

默认值 1Gi 与 backend/union/union.go 中Default: fs.Gibi一致。

--union-description

远程的描述。

  • Config:description
  • Env Var:RCLONE_UNION_DESCRIPTION
  • Type: string
  • Required: false

Metadata

底层远程支持的任意元数据都可读写(backend/union/union.go 中MetadataInfo亦如此声明;特性列表中ReadMetadata/WriteMetadata/UserMetadata均为开启)。

源码视角:union 的关键实现细节

配置校验与特性屏蔽

NewFs(backend/union/union.go)在构造阶段做了几条硬校验,排错时可直接对照报错:

  • upstreams为空 →union can't point to an empty upstream
  • 只配置了 1 个上游 →union can't point to a single upstream(union 至少需要 2 个上游);
  • 上游指向自己(strings.HasPrefix(u, name+":"))→can't point union remote at itself

此外保留了旧配置兼容:若旧版remotes设置存在而upstreams为空,除最后一个外的所有远程自动追加:ro后再作为upstreams使用。

union 的功能特性由所有上游"取交集"得出:features.Mask(ctx, f)对每个上游逐一屏蔽,只有全部上游都支持的能力(如 server-side move)才会暴露给 union;Hashes()返回各上游哈希集合的交集(Overlap,backend/union/union.go),意味着只要有一个上游不支持某哈希算法,union 层面就不报告该算法可用。

多上游并行写入:multiReader 扇出

当 create 策略(如all)选中多个上游时,put需要把同一份数据同时写入多个远程。backend/union/union.go 中的multiReaderio.Pipe+bufio.Writer把输入流"分叉"成 n 个只读流,io.MultiWriter汇聚写出,任何一条流的错误都会传播给其他流;随后put(backend/union/union.go)用 goroutine 池(multithread,backend/union/union.go)并行调用各上游的Put/PutStream,某一路失败时会排空其输入缓冲以不阻塞其他上传。同样的扇出/扇入模式也用于Object.Update(backend/union/entry.go):action_policy=epall更新一个在多个上游都存在的同名文件时,会并行更新所有候选。

合并列举与候选选择

  • List/ListR并发列举所有上游后按名字归并(mergeDirEntries,backend/union/union.go),特性CaseInsensitive置为 true,归并键会转小写以兼容不区分大小写的上游;
  • union 目录的ModTime取所有候选的最大值、Size取所有候选之和(backend/union/entry.go);
  • About会把各上游的 usage 逐字段累加,任何字段有一个上游缺失则整体置为未知(backend/union/union.go);
  • epff的"first found"并非按配置顺序串行探测,而是并发向所有上游发起findEntry,按响应先后取第一个命中的上游(backend/union/policy/epff.go)——这与"first found by the time upstreams reply"的文档措辞严格对应。

实践建议

  • 只读归档合并:把冷数据远程标:ro(或:nc),写入自然落到可写上游;action/create 策略默认值(epall/epmfs)即可满足多数场景。
  • 写入均衡:需要把新文件按容量调度到空间最多的上游时,保持默认create_policy=epmfs,并用rclone about <upstream>预先确认该上游支持 Free 字段。
  • 同名冲突:多个上游存在同名文件时,读端由search_policy决定选中者;想让"最新修改者胜出"可考虑newest策略。
  • 缓存型用法:本地目录 + 云端的"离线缓存"场景直接用:writeback配置;注意 rclone 不负责清理本地缓存目录,需要自行控制其容量与过期。
  • 行为验证可在 backend/union/union_test.go 与 backend/union/union_internal_test.go 中找到针对策略选择与并发操作的测试用例,作为策略行为的参照。

【免费下载链接】rclone"rsync for cloud storage" - Google Drive, S3, Dropbox, Backblaze B2, One Drive, Swift, Hubic, Wasabi, Google Cloud Storage, Azure Blob, Azure Files, Yandex Files项目地址: https://gitcode.com/GitHub_Trending/rc/rclone

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询