我有一个文件一直保持打开状态并被另一个进程不断修改。这个过程不断地寻找文件的不同部分并写入新的块。我希望能够制作该文件的副本,但作为该文件在单个时间实例的快照。
我不想发生的是,我复制第一个字节块,文件发生更改,然后复制包括新修改的字节的第二个块。
Linux 可以帮我吗?
答案1
在复制之前您需要暂停写入过程。
在大多数情况下,写入进程将具有一定的备份能力。仔细查看更新文件的过程的文档。
为了获得更详细的帮助,我们需要知道哪个进程正在写入文件。有人可能知道该应用程序并且知道如何以正确的方式进行备份。
kill
如果没有内置备份功能,您可以尝试使用SIGSTOP/SIGCONT 信号来暂停写入进程。如果每个逻辑更新都是单个操作,那么很好。但是,如果您的编写器进程可以像逻辑更新一样执行两次写入(例如更新数据和更新文件的索引部分),那么您将面临在此类写入之间暂停进程的风险。
答案2
Linux 可以帮我吗?
是的。但不是以您可能希望的方式。
因此,Linux 上的文件系统通常遵循以下语义:对所读取的文件(无论以何种方式)进行的更改应尽可能立即反映在该文件的所有读取器中。请注意这与您想要的有多么不一致。
你可以很好地告诉你的文件系统或块设备层制作快照,这里的语义是不同的,即要求快照时的一致性。
所以,你需要有
- 支持快照的文件系统,或者
- 支持快照的块设备子层。
一致性
正如多纳尔非常正确地指出的那样:如果拍摄快照,这些都没有帮助你尽管单个“一致性单元”(即,导致另一个一致文件状态的搜索和写入,可能您从应用程序视图中认为是“数据更改”)正在进行中。
下面的事情都假设您在当前没有写入的瞬间拍摄快照。他们避免的副本与文件不完全相同在开始复制的那一刻。如果您在写入 8 kB 数据的过程中创建快照,则您的快照将在您要覆盖的 8 kB 数据块中包含 4 kB 新数据和 4 kB 旧数据。这就是我所说的“数据不一致”。
这实际上意味着没有任何帮助:如果您没有确保文件一致性的逻辑方法,则操作系统无法使文件进入一致状态。
如果您需要这样做,您将必须研究“正确的”数据库系统如何确保当存储设备突然从系统中删除时数据库不会处于不可恢复的损坏状态。
你的文件无法做到这一点。如果您不限制快照时间点仅在没有未完成的写入时发生,您自己永远无法保证一致性!为了实现这一点,在任何存储介质或操作系统上,您都必须更改文件架构。
最常见的方法是实现严格有序的机制: 1. 将更改(包括要对主文件执行的位置、长度和数据)写入到文件(或另一个文件)末尾的日志中,并使用尾随校验和可让您检查是否完全发生。并且,只有在完全完成之后,才将更改写入主文件。 3.偶尔,您需要返回并清理已成功提交的日志条目。
现在,当您在写入主数据文件时进行快照时,日志中的数据与主数据中的数据不一致。您可以重播日志中的写入内容,并返回到一致的状态。如果您在写入日志时进行快照,您可以在读取锁时注意到日志条目的校验和不正确,因此该日志条目无法完整,因此主要数据尚未受到什么影响日志条目描述。您从快照日志中删除损坏的日志条目。
文件系统快照
据我所知,在Linux下,只有btrfs和openZFS文件系统支持快照。 Btrfs 是 Linux 内核的一部分,因此它可能是最容易使用的。
在 btrfs 中,您的文件系统(例如,安装在 /srv/data 上的文件系统)可以具有子卷。您可以将它们作为子目录访问或单独安装它们。
一个btrfs快照只是一个与当前卷相同的子卷。这对于 btrfs 来说很“容易”实现,因为这是一个写时复制文件系统:通常,每当您修改文件时,都会创建受影响的存储块的副本,其中包含修改后的数据。然后,文件元数据被更新:文件的内容只是块列表中的数据,如果您更改了 4. 块中的某些内容,则该列表中的第四个条目将替换为对“的引用”新复制和修改的”块。无论如何,这带来的开销非常低,因为存储设备以块的形式工作——你永远无法读取单个字节,你读取一个块,并且写入一个字节和一个块需要相同的时间。因此,读取、修改、写入不同的位置与就地修改一样昂贵。
现在,当创建快照时,发生的只是快照后对文件元数据的任何修改都将进入单独的数据结构。因此,基本上,快照和文件系统当前“活动”的工作视图 100% 共享所有未更改的数据,但已更改的内容存在两次:一次在修改版本中,一次按原样在快照时。
因此,将文件放在 btrfs 子卷上,制作快照,挂载该快照:您的文件及时“冻结”了。
块设备映射器快照
这些基本上适用于任何现代 Linux 文件系统。在这些很常见的世界中,XFS 是一种流行的文件系统选择(但任何文件系统都应该这样做)。
LVM 是 Linux 卷管理器。这基本上意味着它是内核的一部分,您可以提供一个或多个块设备(“物理卷”),告诉它将这些设备组装成一个“卷组”,然后从累积的存储池中创建“逻辑卷”。
其中的一个特殊情况是“精简卷”,这基本上意味着您说“好吧,我的卷组中有 512 GB 的存储空间。我想创建一个可以使用文件系统格式化的逻辑卷。我想要那个也许最终会成为 TB(例如,如果我的客户实际上使用这些),但现在,我什至没有那么多空间(新的 SSD 尚未订购,但您也不需要所有这些 1 TB 尚未)”。然后 LVM 将创建一个卷看起来