存储 VPS 配对主 VPS:NFS、SSHFS 与 WireGuard
了解如何让小型高速 VPS 运行应用,并将 TB 级数据放在低成本存储 VPS 上。通过 WireGuard 连接 NFS、SSHFS 或 rclone,同时避免把数据库、缓存和临时文件放到远端挂载。
为什么要将存储 VPS 与主 VPS 配对
将存储 VPS 与主 VPS 配对,可以让每台服务器承担与其定价相符的工作。小型高速服务器运行应用、数据库和缓存。大型低成本服务器存储 TB 级数据并提供数据传输。两台服务器通过专用 WireGuard 隧道连接,应用会将远端磁盘视为 /mnt 下的普通目录。
拆分部署的原因是降低每 GB 成本。存储 VPS 以 CPU 和 IOPS 换取原始容量,因此不必为每 TB 存储空间同时支付高速计算资源后,相同的月度预算就能购买更多容量。如果您还没有确定存储产品,请先了解存储 VPS 与块存储卷和对象存储的比较,因为下面的连接方式取决于您购买的产品类型。
拆分部署的代价是每次文件操作前都增加一次网络往返。本地 stat() 是一次内存查找。远程挂载上的相同 stat() 则需要发送请求、等待响应,再接收结果。任何挂载选项都无法消除这次网络往返。您只能减少应用发起网络往返的次数。
有两个决定会直接影响这对服务器能否正常工作。两台服务器必须位于同一区域。数据库、缓存和转码临时文件必须保存在本地磁盘上。任一项出错,后续步骤都无法补救。
为什么两台服务器必须位于同一区域
往返时间决定了全部延迟预算。在同一个数据中心内,两台 VPS 实例之间的往返时间只有不到 1 毫秒。在两个大洲之间,这个时间通常超过前者的 100 倍,而且这个倍数会叠加到每一次操作上,而不仅是慢操作。
以媒体扫描器为例。它先读取目录,然后对每个条目调用 stat(),再打开其中一些文件读取嵌入的元数据。因此,一个包含 10000 个文件的媒体库,在任何视频数据开始传输之前,至少就需要 10000 次往返。这里的问题不是批量吞吐量。通过长距离链路传输一个大文件通常没有问题,因为读取操作较大且按顺序进行,内核还会预读。问题在于遍历目录树,因为每个小操作都必须等待前一个操作的响应。
因此,应选择同一云服务商、同一区域,最好是同一个数据中心。在迁移任何内容之前先验证这一点。租用两台服务器一个月,建立隧道,然后使用 ping -c 100 10.9.0.2 测量。如果平均值不是远低于 1 毫秒,就不要采用这组服务器。应将应用部署在数据附近,或者改用对象存储,让访问模式变为每次发起一个大型请求。
不得放在远端的内容
以下四类文件必须存放在应用服务器的本地磁盘上。
- 数据库文件。SQLite、PostgreSQL 和 MariaDB 需要
fsync()保持其定义的语义,也需要跨进程文件锁正常工作。使用远程挂载时,这两者都依赖远端和网络正常运行。链路出现阻塞时,数据库不会正常暂停。它可能挂起,也可能损坏。 - 缓存、索引和缩略图。这些文件体积小、读取频繁,而且可以低成本重新生成。将它们放在需要往返通信的位置后面,是最差的取舍。图库中的每个页面都会产生大量细小的远程读取请求。
- 转码临时文件。转码器会以很高的速率、按小块写入并删除文件。将临时目录指向本地磁盘,并确认设置确实已修改。
- 锁文件和 Unix 套接字。位于共享目录中的
.pid文件或套接字,在两台机器之间没有实际意义,而且某些远程文件系统对它们的处理并不可靠。
远端应存放批量文件,即一次写入、整体读取的文件:视频、照片原件、归档文件和备份存储库。
对于媒体服务器,这种划分很明确。在 VPS 上运行的 Jellyfin 将配置和元数据保存在本地磁盘的 /var/lib/jellyfin 下,并从挂载点读取视频。将 /var/lib/jellyfin 移到存储服务器后,Web 界面中的每次点击都要等待远端响应。照片也应采用相同的划分:对于 Immich,上传图库和 Postgres 数据库是两个独立部分,图库可以存放在挂载点上,数据库则不能。
使用 WireGuard 连接两台主机
不要将文件系统导出到公网 IP 地址。NFS 默认不提供传输加密,其身份验证主要是“信任客户端发送的数字用户 ID”。应将 NFS 放入隧道中。
完整配置请参阅在 VPS 上自行托管 WireGuard 的指南。下面是双节点版本。先在每台主机上生成密钥对:
sudo apt update && sudo apt install -y wireguard
sudo install -d -m 700 /etc/wireguard
sudo sh -c 'umask 077; wg genkey > /etc/wireguard/priv.key'
sudo sh -c 'wg pubkey < /etc/wireguard/priv.key > /etc/wireguard/pub.key'在应用主机上,/etc/wireguard/wg0.conf:
[Interface]
Address = 10.9.0.1/24
ListenPort = 51820
PrivateKey = <application box private key>
[Peer]
PublicKey = <storage box public key>
AllowedIPs = 10.9.0.2/32
Endpoint = <storage box public IP>:51820
PersistentKeepalive = 25存储主机的配置与之对应:Address = 10.9.0.2/24、对端的 AllowedIPs = 10.9.0.1/32,并将 endpoint 设置为应用主机的公网地址。两个文件都必须使用 600 权限。然后在两台主机上启动隧道:
sudo chmod 600 /etc/wireguard/wg0.conf
sudo systemctl enable --now wg-quick@wg0
sudo wg show
ping -c 3 10.9.0.2wg show 应列出该对端,并显示最近的 latest handshake 行;此时 ping 应能收到响应。对端没有握手行,表示数据包未到达。检查两台主机的防火墙是否允许 UDP 51820,还要检查服务提供商单独的网络防火墙。大多数控制面板将其作为不同的控制项。
此设计后续会遇到两个隧道问题,现在就应了解。大块顺序读取出现停顿,但 ping 仍可用,说明存在路径 MTU 问题。解决方法是通过二分查找确定实际路径 MTU,而不是猜测整百或整千的数值。如果使用主机名而不是隧道地址引用存储主机,通过隧道进行 DNS 解析就会成为启动时可能失败的另一个环节。在每个挂载定义中直接使用字面量 10.9.0.2 地址,即可避免此问题。
选项 1:通过隧道使用 NFS
对于同一区域内的文件系统,NFS 是最稳妥的选项,因为内核客户端会缓存属性,而且其故障行为可以调节,而不是固定不变。
在存储服务器上:
sudo apt update && sudo apt install -y nfs-kernel-server
sudo install -d -m 755 /srv/media
sudo chown 1000:1000 /srv/media在 /etc/exports 中添加一行,并指定应用服务器的隧道地址:
/srv/media 10.9.0.1(rw,sync,no_subtree_check,root_squash)应用并检查:
sudo exportfs -ra
sudo exportfs -vexportfs -v 会输出内核实际应用的选项。该输出不一定与输入内容完全相同,因为系统会在选项列表周围补充默认值。
导出配置限制了允许挂载的客户端地址,但 NFS 服务器仍会在每个接口的 TCP 2049 端口上监听。扫描公网地址时仍能发现该端口。导出列表不是防火墙,因此还需添加防火墙规则:
sudo ss -lnt | grep 2049
sudo ufw status verbose
sudo ufw allow in on wg0 to any port 2049 proto tcpss 显示监听器绑定到了所有地址,这正是需要确认的结果。ufw status verbose 应输出 Default: deny (incoming)。设置此默认策略后,单条隧道规则就足够了:2049 端口只在 wg0 上响应,其他位置均不响应。如果默认策略是 allow,请先修复它再继续。
不使用 Kerberos 的 NFSv4 会通过数字用户 ID 映射所有权。如果应用在一台服务器上以 uid 1000 运行,而文件在另一台服务器上也归 uid 1000 所有,则可以正常工作。如果两边的数字不同,文件会显示为归 nobody 所有,或者写入会因 Permission denied 失败;再多的 chmod 也无法解决问题。请在两台服务器上统一用户 ID,或者在导出配置中添加 all_squash,anonuid=1000,anongid=1000,让所有客户端访问都映射到同一个所有者。
在应用服务器上挂载:
sudo apt install -y nfs-common
sudo install -d -m 755 /mnt/media
sudo mount -t nfs4 -o vers=4.2,nconnect=4 10.9.0.2:/srv/media /mnt/media
findmnt /mnt/mediafindmnt 会输出当前生效的源、类型和选项。然后在 /etc/fstab 中配置永久挂载,并启用自动挂载,避免隧道未建立时启动过程被挂起:
10.9.0.2:/srv/media /mnt/media nfs4 _netdev,x-systemd.automount,x-systemd.mount-timeout=30,x-systemd.idle-timeout=600,vers=4.2,nconnect=4,hard,timeo=100,retrans=3,acdirmin=60,acdirmax=600 0 0sudo systemctl daemon-reload
sudo systemctl start mnt-media.automount
systemctl status mnt-media.automount单元名称由路径生成:/mnt/media 会变为 mnt-media.automount。使用 x-systemd.automount 时,systemd 只会在启动时安装触发器。实际挂载会在首次访问时执行,因此存储服务器启动缓慢不会延迟应用服务器启动。
下面 3 个选项值得理解,不要直接照抄。nconnect=4 会与同一服务器建立多个 TCP 连接,最多达到文档规定的 16 个连接。当链路存在实际延迟、单个连接的窗口限制了吞吐量时,这可以提高性能。acdirmin 和 acdirmax 设置客户端在再次请求前信任已缓存目录属性的时长。将它们从较短的默认值调高,是元数据密集型扫描中最有效的单项调整。代价是,存储服务器上的其他进程创建的文件会延迟显示。如果文件始终只通过应用服务器写入,这项代价可以忽略,因为客户端写入时会更新自己的缓存。而且,无论你复制该配置的博客文章怎么说,noatime 在这里都不起作用:nfs 手册页明确说明,atime 和 noatime 选项对 NFS 挂载没有效果。
选项 2:SSHFS
除了 SSH 账户外,SSHFS 不需要存储服务器提供其他配置。它通过 FUSE 在用户空间运行,缓存无法处理的每个文件操作都会在 SSH 连接中发起一个 SFTP 请求。
请明确采用它意味着什么。截至 October 2026,上游 README 声明该项目“没有任何活跃的定期贡献者,并且存在一些已知问题”,但维护者仍会处理 pull request 并发布版本。所有主要发行版都提供该软件包,而且它可以正常工作。应将其视为稳定项目,而不是持续改进中的项目。
sudo apt install -y sshfs
sudo install -d -m 755 /mnt/media
sshfs -o reconnect,ServerAliveInterval=15,ServerAliveCountMax=3,uid=1000,gid=1000,allow_other,default_permissions storage@10.9.0.2:/srv/media /mnt/media
ls /mnt/media使用 fusermount -u /mnt/media 卸载,不要使用 umount。uid 和 gid 选项会将远程所有权映射为本地 id,从而避开 NFS 的 id 匹配问题。reconnect 加上两个 keepalive 设置,才能让挂载在隧道短暂中断后继续工作。没有这些设置,连接一旦断开,挂载就会永久失效;每次访问都会返回 Transport endpoint is not connected,直到卸载后重新挂载。
fstab 配置需要使用一个没有 passphrase 且 root 可读取的密钥:
storage@10.9.0.2:/srv/media /mnt/media fuse.sshfs _netdev,x-systemd.automount,IdentityFile=/root/.ssh/id_ed25519,reconnect,ServerAliveInterval=15,ServerAliveCountMax=3,uid=1000,gid=1000,allow_other,default_permissions 0 0问题在于:元数据缓存的有效期很短。SSHFS 会维护自己的目录缓存,其中包含名称、属性和符号链接目标。该缓存默认启用,超时时间为 20 秒(dcache_timeout);此外,FUSE 还会增加一个 1 秒的内核属性缓存。在这段时间内,重复查找都在本地完成。超过该时间后,每次查找都必须再次往返,默认通过单个 SSH 连接完成(max_conns 可打开更多连接)。NFS 客户端可以在 acdirmax 允许的时间内持续从缓存响应长时间扫描,而 SSHFS 会每隔 20 秒通过网络重新执行这些操作,除非提高 dcache_timeout,但这样会导致较晚看到远端的更改。你还会进行两次加密:一次用于 SSH,一次用于 WireGuard。对于小型设备而言,这些 CPU 开销没有实际收益。一个合理的替代方案是去掉隧道,直接使用存储服务器的公网地址运行 SSHFS,因为 SSH 可以安全地暴露,而 NFS 不行。请选择一种设计。不要同时运行两种设计。
选项 3:使用 rclone 挂载
rclone 同样通过 FUSE 挂载,其远端可以是存储服务器上的 SFTP,也可以是其他位置的对象存储桶。远端是对象存储时,应使用这种方案。远端是可以正常挂载的文件系统时,不应使用这种方案。
sudo apt install -y rclone
rclone config
rclone lsd storage:rclone lsd列出目录,可以在尝试挂载之前确认远端已正确配置。在 Linux 上,挂载点必须是已存在的空目录;rclone 文档对此有明确说明。
rclone mount storage:media /mnt/media --vfs-cache-mode full --vfs-cache-max-size 20G --dir-cache-time 72h --allow-other --daemon--vfs-cache-mode full使普通应用能够使用该挂载点,并会写入本地缓存。缓存会占用您原本不想填满的小容量高速磁盘,因此 --vfs-cache-max-size不是可选项。--dir-cache-time 72h会将目录列表保存在内存中 3 天,这使大型媒体库能够正常浏览,但也意味着远端由其他进程添加的文件可能要到 3 天后才会显示。对于 systemd 单元,文档指出,Type=notify会使服务只有在挂载点设置完成后才进入 started 状态,其他单元应以此状态作为启动顺序依据。
问题在于:底层没有 POSIX 语义。在对象存储后端中,重命名实际是先复制再删除;对大型现有文件执行局部写入时,则会重写整个对象。假设底层是实际文件系统的应用(包括所有媒体服务器)可能会出现文档无法替您预测的行为。rclone 适合读取大型文件,也适合将远端服务器作为异地备份目标运行。但它不适合作为通用磁盘。
链路中断时应用的行为
请在构建前决定这一点,因为默认行为通常不是大多数人预期的方式。
使用 NFS hard(默认设置)时,链路中断会使所有访问该挂载点的进程进入睡眠,直到服务器响应。ps 会显示状态 D,而 df 会挂起。如果监控程序运行在 df,监控也会挂起。此类 D 并非无法终止:从 kernel 2.6.25 开始,NFS 客户端会进入可终止的睡眠状态,因此 kill -9 可以终止卡住的进程,也是清理无法继续等待的进程的方法。该进程尚未写入的内容会随进程一起丢失。内核会记录 nfs: server 10.9.0.2 not responding, still trying。链路恢复后,您会看到 nfs: server 10.9.0.2 OK,而所有未处理的进程都会从中断处继续运行,不会丢失已写入的内容。对于任何会写入数据的应用,这是正确的取舍。
使用 NFS soft 时,在 timeo 和 retrans 耗尽后,请求会失败并返回 I/O 错误,应用会看到 EIO,而不是继续等待。手册页中的警告值得原样引用,因为它比大多数人的理解更严重:软超时“在某些情况下可能导致无提示的数据损坏”,因此应“仅在客户端响应能力比数据完整性更重要时”使用。只读媒体挂载属于这种情况。写入路径不属于这种情况。也不要使用 intr 来降低硬挂载的阻塞性。手册页说明,从 kernel 2.6.25 开始该选项会被忽略;在该版本中,上述可终止睡眠取代了它。因此,它在 fstab 中只是注释,不会产生其他作用。
softreval 介于两者之间。客户端在重新验证尝试超时后,仍可从缓存提供路径和属性,因此即使底层数据无法访问,目录树仍可浏览。
SSHFS 配合 reconnect 会自动重试 SSH 连接。rclone mount 配合 --vfs-cache-mode full 时,会继续提供缓存中已有的文件,并将写入排队,稍后再上传;读取缓存未命中的文件时则会失败。
无论选择哪种方式,都要书面回答一个问题:存储服务器因 kernel 更新而重启时,应用能否自动恢复,还是必须由人工登录处理?在这组系统承载重要数据之前,先主动重启存储服务器进行测试。
首先会遇到的故障:向空挂载点写入数据
这类问题会导致真实数据丢失,而且与您选择哪种协议无关。
/mnt/media 是一个目录。挂载处于活动状态时,它显示存储服务器中的文件。挂载未处于活动状态时,它只是本地小容量磁盘上的空目录。应用无法区分这两种情况。应用向 /mnt/media 写入数据,写入操作成功,数据却落在应用服务器的根文件系统中。直到根磁盘被写满、服务开始停止,您才会发现问题。恢复时情况会更糟:再次挂载后,挂载点下方错放的文件会被隐藏,因此磁盘仍然处于满状态,而 du /mnt/media 中看不到任何可删除的文件。
让这个空目录拒绝写入。先卸载它,然后设置 immutable 属性:
sudo umount /mnt/media
sudo chattr +i /mnt/media
lsattr -d /mnt/medialsattr -d 会显示标志;在该路径上没有挂载内容时,i 会出现。此后,向未挂载路径写入会因 Operation not permitted 而失败,应用会记录错误,而不是静默写满磁盘。挂载操作仍然有效,因为挂载不会修改底层目录。如果需要,稍后可使用 chattr -i 删除该属性。ext4 和 XFS 都支持此方法,普通 VPS 镜像的根文件系统通常使用这两种文件系统之一。
接下来,让服务依赖该挂载点。添加一个 systemd drop-in:
sudo systemctl edit jellyfin[Unit]
RequiresMountsFor=/mnt/media需要明确这能解决什么问题。RequiresMountsFor= 会让服务在该路径对应的挂载单元之后启动,并将该挂载单元一并拉起。使用 x-systemd.automount 时,systemd 只需安装触发关系,因此即使存储服务器无法访问,服务仍可能启动。该依赖关系会让故障显示在 systemctl status 中。真正阻止数据损坏的是 immutable 目录。
Docker 还有一个特殊陷阱:daemon 会自动为您创建缺失的 bind 源路径。在 Compose 中关闭此行为:
services:
jellyfin:
volumes:
- type: bind
source: /mnt/media
target: /media
read_only: true
bind:
create_host_path: falseCompose 文档将 create_host_path 描述为:如果主机上的源路径不存在,则在该路径创建目录;其默认值为 true。将其设置为 false 后,Compose 不会自动创建该路径。但当路径已经存在且为空时,这不会产生帮助,而这正是此处的常见情况。因此仍应保留 immutable 目录。
最后,为每个向挂载点写入数据的脚本添加保护:
mountpoint -q /mnt/media || { echo "/mnt/media is not mounted" >&2; exit 1; }哪个盒子是真实来源?
请按数据集书面确认这一点,并在首次同步任务运行前完成。
通常的安排是让每个盒子承担不同的角色。应用盒负责少量可变状态:数据库、配置和密钥。存储盒负责大量数据:媒体文件、原始文件和归档。两个盒子都不是所有数据的真实来源,因此备份会双向运行,而将其中一个方向反过来运行也很容易。
危险的方向是从应用盒向存储盒执行 rsync --delete 推送。如果挂载已断开,源目录会显示为空,--delete 就会照常删除目标目录。rsync 遍历文件列表所需的时间,就足以让数 TB 数据消失。
两种习惯可以避免此问题。每次同步前都使用上面的 mountpoint -q 检查。并且优先使用拉取而不是推送:在保存副本的盒子上运行任务,由它主动连接并获取数据。即使应用盒已被入侵,拉取任务仍然更安全,因为能够删除备份的凭据不在攻击者最先控制的机器上。
请选择能够保存快照而不是只创建镜像的工具。restic 和 borg 会保留历史记录,因此源端被删除或加密的文件仍可从较早的快照中恢复,而 rsync 镜像会准确复制删除操作。如果存储盒保存的是副本而非原始数据,请将其配置为真正的异地备份目标并启用仅追加访问权限,使源端可以添加快照,但不能删除快照。
还有一个容易被忽略的方向。如果存储盒保存的是照片库的唯一副本,存储盒本身也需要备份。恢复时必须同时覆盖这两部分,并且两份备份的时间要足够接近,以确保彼此一致。将星期二的数据库快照与星期四的照片库结合恢复,会得到一个无法正常运行的安装,因为数据库记录指向的文件当时还不存在。
自行测量这对方案
不要相信此设计的已发布吞吐量或延迟数据,包括你在其他地方看到的数据。结果取决于你的服务商、所在区域以及你选择的两项套餐。请测量你自己的方案组合。下面的每条命令都需要你自行运行;除非另有说明,否则应在应用服务器上运行。
隧道上的往返时间会放大每次元数据操作的开销:
ping -c 100 10.9.0.2原始链路吞吐量,不涉及任何文件系统。请在存储服务器上运行服务端部分:
iperf3 -siperf3 -c 10.9.0.2 -t 30如果该数值远低于套餐标称值,问题出在网络或隧道,任何挂载选项都无法修复。先检查 MTU,再判断是否是 NFS 的问题。
通过挂载执行大块顺序读取,并与上述数值比较:
fio --name=seqread --rw=read --bs=1M --size=2G --numjobs=1 --direct=1 --filename=/mnt/media/fio-test --end_fsync=1
rm -f /mnt/media/fio-test在 FUSE 挂载上,如果 fio 报告不支持该标志,请删除 --direct=1,因为不同驱动对 O_DIRECT 的处理方式不同。如果该数值与 iperf3 数值之间差距很大,问题更可能出在挂载,而不是链路。
元数据开销才是实际决定方案的指标:
time find /mnt/media -type f | wc -l运行两次。第一次是冷缓存,第二次显示属性缓存带来的收益。然后在存储服务器本地运行相同的 find 并进行比较。这两次耗时的比值,就是此架构向应用收取的开销;该结果基于你的硬件测得,而不是凭假设得出。
如果选择了 NFS,请直接查看每个操作的延迟:
nfsiostat 5 3
nfsstat -cnfsiostat 随 nfs-common 一起提供,并针对每个挂载报告每秒操作数以及每次操作的平均往返时间。nfsstat -c 会按操作类型细分客户端调用。如果 getattr 调用占据大多数,说明你的工作负载受元数据限制:提高 acdirmin 和 acdirmax,重新挂载,然后再次运行相同的 find。
然后执行人们经常跳过的测试。应用仍在提供流量时,重启存储服务器,并观察实际情况。只有这样才能知道故障行为究竟是按你的配置发生,还是按你的假设发生。
FAQ
我可以将数据库放在存储 VPS 的挂载点上吗?
不可以。数据库引擎依赖 fsync() 访问真实存储,并依赖跨进程文件锁正常工作;而 NFS、SSHFS 或 rclone 挂载无法可靠提供这些条件。连接停滞时,数据库不会正常暂停:进程可能挂起,文件也可能损坏。SQLite、PostgreSQL 或 MariaDB 的数据目录应保留在应用服务器的本地磁盘上。挂载点应存放一次写入、整文件读取的大批量文件。
NFS、SSHFS 还是 rclone:我应该使用哪一个?
如果远端是同一区域内的文件系统,请通过 WireGuard 隧道使用 NFS,因为内核客户端会缓存属性,而且 hard、soft 和 softreval 可用于选择故障处理方式。如果不希望在服务器端进行配置,并且可以接受较短的元数据缓存(默认 20 秒),以及缓存失效后每次查找都需要一次往返通信,请使用 SSHFS。如果远端是对象存储而不是文件系统,请使用 rclone;此时其 VFS 缓存和较长的 --dir-cache-time 能够发挥实际作用。
存储 VPS 离线后,我的应用会发生什么?
使用默认的 hard NFS 挂载时,访问该挂载点的进程会处于 D 状态并等待,内核会记录 nfs: server 10.9.0.2 not responding, still trying。这些进程并非无法终止:从 kernel 2.6.25 开始,kill -9 可以结束卡住的进程,但尚未写入的数据会丢失。如果不进行处理,连接恢复后进程会继续运行,尚未丢失的写入也会保留。使用 soft 时,调用会改为返回 I/O 错误,但写入操作可能发生静默数据损坏。SSHFS 配置 reconnect 后会自动重试,rclone 挂载则会继续提供其 VFS 缓存中已有的内容。
挂载点不可用时,为什么 root 磁盘会被写满?
因为未挂载的挂载点仍是本地磁盘上的可写空目录,应用会将数据写入其中,数据实际落在 root 文件系统上。重新挂载后,挂载点下的这些文件会被挂载内容隐藏,因此磁盘空间仍然被占用,但路径看起来是空的。卸载挂载点,删除其下的内容,然后在空目录上运行 sudo chattr +i /mnt/media,这样后续写入会因 Operation not permitted 而失败,而不会错误地写入本地磁盘。
两台服务器确实需要位于同一区域吗?
是的,对于这种设计来说需要。每次元数据操作至少需要一次往返通信,而扫描目录时每个文件都需要一次通信,因此跨区域往返会将工作负载中最慢的部分放大一百倍甚至更多。迁移数据前,先通过隧道使用 ping -c 100 进行测量。如果平均延迟不是几分之一毫秒这样的小数值,就应让应用与数据保持在同一位置。