2 台机器正在安装同一个 NFS 文件夹(位于第 3 台机器上)。
文件通常以块的形式从任一客户端服务器上传到此挂载点。服务器 A 可能处理一个块,然后服务器 B 处理下一个,所有这些都定义了起点和终点,因此最终一切都会累积起来。
不过,还是有一些情况,如果你md5sum
从服务器 A 运行,你得到的结果与服务器 B 不同。
但实际上,据我所知,该文件位于 NFS 服务器上,并且应该只有一个版本推送到所有客户端。
而且它不会随着时间的推移而自行修复。
我目前假设这是一种竞争条件,与未按顺序添加的块和 NFS 缓存有关,您可能会让其中一个服务器认为文件的长度达到一定长度,但事实并非如此,从而导致0000 0000
添加大量填充。
那么,这是怎么发生的?我需要使用挂载设置来防止这种情况发生吗?有没有办法告诉 NFS 服务器将文件重新同步到所有客户端?
一般而言,应该如何处理这个问题?
编辑:客户端上的安装选项:
machine1:~$ nfsstat -m
/mnt/dirA from <SERVER_IP>:/dirA
Flags: rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,namlen=255,acregmin=1,acregmax=1,acdirmin=1,acdirmax=1,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=<LOCALHOST_IP>,local_lock=none,addr=<SERVER_IP>
/mnt/dirB from <SERVER_IP>:/dirB
Flags: rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,namlen=255,acregmin=1,acregmax=1,acdirmin=1,acdirmax=1,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=<LOCALHOST_IP>,local_lock=none,addr=<SERVER_IP>
machine1:~$ cat /proc/mounts | grep <SERVER_IP>
<SERVER_IP>:/dirA /mnt/dirA nfs4 rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,namlen=255,acregmin=1,acregmax=1,acdirmin=1,acdirmax=1,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=<LOCALHOST_IP>,local_lock=none,addr=<SERVER_IP> 0 0
<SERVER_IP>:/dirB /mnt/dirB nfs4 rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,namlen=255,acregmin=1,acregmax=1,acdirmin=1,acdirmax=1,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=<LOCALHOST_IP>,local_lock=none,addr=<SERVER_IP> 0 0
machine2:~$ nfsstat -m
/mnt/dirA from <SERVER_IP>:/dirA
Flags: rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,namlen=255,acregmin=1,acregmax=1,acdirmin=1,acdirmax=1,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=<LOCALHOST_IP>,local_lock=none,addr=<SERVER_IP>
/mnt/dirB from <SERVER_IP>:/dirB
Flags: rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,namlen=255,acregmin=1,acregmax=1,acdirmin=1,acdirmax=1,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=<LOCALHOST_IP>,local_lock=none,addr=<SERVER_IP>
<SERVER_IP>:/dirA /mnt/dirA nfs4 rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,namlen=255,acregmin=1,acregmax=1,acdirmin=1,acdirmax=1,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=<LOCALHOST_IP>,local_lock=none,addr=<SERVER_IP> 0 0
<SERVER_IP>:/dirB /mnt/dirB nfs4 rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,namlen=255,acregmin=1,acregmax=1,acdirmin=1,acdirmax=1,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=<LOCALHOST_IP>,local_lock=none,addr=<SERVER_IP> 0 0
EDIT2:两台机器都是 Ubuntu 18.04,全新安装,两台机器上的 md5sum 工具都是 8.28 版本。
编辑3:
我找到了我保存在文件上的这个注释。我执行了一项操作xxd
,从两台机器的挂载到机器的本地文件系统,获取十六进制转储。为了确保它是从各个机器的角度捕获的。如您所见,根据 machine01,文件中有空填充,但根据 machine02,文件中没有。
结果如下:
root@machine01:/home/kdguser# grep -C 5 '2ddd5000' output01
2ddd4fb0: 0a78 95ff c53e e2c4 f79a db05 0a59 d7d1 .x...>.......Y..
2ddd4fc0: 85a8 1192 26a6 a25a d741 db3c a61f e72e ....&..Z.A.<....
2ddd4fd0: 4d0b 97b6 93cc 7845 6ef4 0cca f9aa 9390 M.....xEn.......
2ddd4fe0: 9f00 bacd 707f 2398 f419 e49e 8073 67fb ....p.#......sg.
2ddd4ff0: 89f5 9450 99f5 808f 4b21 3154 f97f 1271 ...P....K!1T...q
2ddd5000: 0000 0000 0000 0000 0000 0000 0000 0000 ................
2ddd5010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
2ddd5020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
2ddd5030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
2ddd5040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
2ddd5050: ba34 fb76 5af3 69d2 9af0 4711 8a0c eae8 .4.vZ.i...G.....
root@machine02:/home/kdguser# grep -C 5 '2ddd5000' output02
2ddd4fb0: 0a78 95ff c53e e2c4 f79a db05 0a59 d7d1 .x...>.......Y..
2ddd4fc0: 85a8 1192 26a6 a25a d741 db3c a61f e72e ....&..Z.A.<....
2ddd4fd0: 4d0b 97b6 93cc 7845 6ef4 0cca f9aa 9390 M.....xEn.......
2ddd4fe0: 9f00 bacd 707f 2398 f419 e49e 8073 67fb ....p.#......sg.
2ddd4ff0: 89f5 9450 99f5 808f 4b21 3154 f97f 1271 ...P....K!1T...q
2ddd5000: c969 a259 431e 2a17 12b4 8365 07cb 5e56 .i.YC.*....e..^V
2ddd5010: fa61 327f eb63 1b13 bc30 eb4b c8f0 af14 .a2..c...0.K....
2ddd5020: 6ebe 3f79 9012 7ece 1662 e104 be19 b249 n.?y..~..b.....I
2ddd5030: 9b9c f61d 180b e92a b93b 9980 aba4 ba41 .......*.;.....A
2ddd5040: 0929 fece fc8a 5309 3883 2562 fe2a 459a .)....S.8.%b.*E.
2ddd5050: ba34 fb76 5af3 69d2 9af0 4711 8a0c eae8 .4.vZ.i...G.....
虽然实际文件是从 machine02 看到的,但 machine01 显示的却是其他内容。
EDIT4:需要明确的是,文件的长度是相同的,每个客户端的 md5 是不同的。
答案1
我建议阅读“数据和元数据一致性”部分nfs 手册页。
NFS 版本 3 协议引入了“弱缓存一致性”(也称为 WCC),它提供了一种在单个请求之前和之后有效检查文件属性的方法。这允许客户端帮助识别其他客户端可能做出的更改。
特别是,您需要使用noac
:
当 noac 生效时,客户端的文件属性缓存将被禁用,因此每个需要检查文件属性的操作都会被强制返回到服务器。这样客户端就可以非常快速地查看文件的更改,但需要进行许多额外的网络操作。
唉,
noac 挂载选项可防止客户端缓存文件元数据,但仍存在可能导致客户端和服务器之间的数据缓存不一致的竞争。
O_DIRECT
因此,如果noac
它不能为您解决问题,您可能需要用标志打开文件。
NFS 协议并非设计为在没有某种类型的应用程序序列化的情况下支持真正的集群文件系统缓存一致性。如果需要客户端之间的绝对缓存一致性,应用程序应使用文件锁定。或者,应用程序也可以使用 O_DIRECT 标志打开其文件以完全禁用数据缓存。
答案2
免责声明:首先,我不使用 Ubuntu。其次,我是“老派”。第三,文档可能不同意我的观点(请参阅第二条免责声明)。
布拉夫:这可能是时间、缓存或缓冲问题。
解释:在里面过去,程序实际上不会立即写入磁盘。操作系统实际上会将文件数据发送到缓冲区。当缓冲区(几乎)已满时,缓冲区将冲洗写入磁盘。即缓冲区的内容随后将被物理写入磁盘本身。
对于磁盘阵列,有时磁盘控制器也会有一个缓存。数据到达控制器的速度可能比磁盘写入的速度快,因此它将被缓存在控制器中,直到磁盘能够赶上。
对于网络流量,数据通常以数据包的形式传输。TCP/IP 无法保证数据包会按照发送的顺序到达。因此,有一个缓冲区可以保存数据包并按正确的顺序重新组装它们。
今天,缓冲区应该立即缓存。在过去,我们会运行命令sync
来强制刷新缓冲区。
我在这里看到的问题是:
每个服务器都有一个“下一个块号”,当轮到它时,它应该开始写入。服务器 A 和服务器 B 之间的这个值可能不同步。
缓存或缓冲区可能写入速度不够快。例如,服务器 A 必须将其数据发送到服务器 C。服务器 C 必须将其物理写入磁盘。服务器 B 必须从磁盘重新读取文件,然后才能“看到”它。
这意味着服务器 B 的数据中可能存在服务器 A 之前刷新的漏洞。反之亦然。
服务器 C(NFS 服务器)可能因读/写请求而超载。服务器 C(NFS 服务器)是否还有不同的校验和?
服务器 A 和服务器 B 可能重读速度不够快。
希望这可以让您了解在哪里寻找答案。
可能的故障排除步骤:
是否可以关闭网络,sync
在每台服务器上运行几个命令,然后查看是否匹配?
文件最终会赶上吗?您提到了数据中的漏洞。
如您所见,根据machine01,文件中有空填充,但根据machine02没有。
一段时间后(TBD),填充是否会填充缺失的数据?如果是这样,则存在缓冲或计时问题。如果没有,则整个系统设计存在更大的问题。
您可以重新考虑 2 个服务器的问题吗?您可以只让 1 个服务器接管所有写入,并在必要时将故障转移到另一台服务器吗?
您的配置中是否有可以调整的缓存参数或计时值?