获取巨大gzip文件的最后一行

8
在数据库备份过程中,我会生成一个文本转储文件。由于数据库非常庞大,因此转储文件也很大,因此我使用gzip进行压缩。压缩是在生成转储时内联完成的(感谢Unix管道!)。
在进程结束时,我通过观察最后一行并检查“Dump completed”字符串是否存在来检查转储文件的有效性。在我的脚本中,我通过将最后一行提取到变量中来完成这个过程:
str=`zcat ${PATHSAVE}/dumpFull.sql.gz | tail -n1`

由于数据库转储文件非常大(目前超过200GB),因此这个结束进程检查需要花费很长时间才能运行(目前超过180分钟)。
我正在寻找一种更快地提取.gz文件中最后一行的方法...有什么建议吗?
注1:为了解释上下文,我们可以说数据库是MySql community,备份工具是mysqldump,生成的转储文件是一个完整的文本文件。操作系统是CentOs。备份脚本是Bash shell脚本。
注2:我知道Percona xtraBackup,但在我的情况下,我想使用mysqldump进行此特定的备份工作。恢复所需的时间不是问题。

1
你能改变gzip文件的创建方式吗?gzip格式的子集被称为“rsyncable gzip”,它会定期重置压缩表;对于这些文件,可以从中途开始阅读(仅丢弃到下一个重置点的信息)。当然,压缩比会受到惩罚,但可以通过更改此类重启的频率来进行调整。 - Charles Duffy
3个回答

4
这是一个使用fifo(一种管道)和tee命令的任务,用于备份时使用。
mkfifo mypipe
tail mypipe -1 > lastline.txt & mysqldump whatever | tee mypipe | gzip >dump.gz
rm mypipe

发生了什么?

mkfifo mypipe 将一个 fifo 对象放入当前工作目录。它看起来像一个文件,你可以同时写入和读取。

tail mypipe -1 >lastline.txt 使用 tail 读取你写入到 mypipe 的内容,并将最后一行保存到一个文件中。

mysqldump whatever | tee mypipe | gzip >dump.gz 执行你的转储操作,并将输出传输给 tee 命令。Tee 将输出写入到 mypipe 中,同时将其传输给 gzip

命令中两个部分之间的 & 导致两个部分同时运行。

rm mypipe 删除 fifo 对象。

Charles Duffy 指出一些 shell(包括 bash)具有进程替换功能,因此如果你使用其中一个 shell,则可以使你的命令更简单。

 mysqldump whatever | tee >(tail -1 > lastline.txt ) | gzip >dump.gz

在这种情况下,shell会为您创建自己的管道。
来源:将输出输入两个不同命令的管道

1
这很糟糕:它未能“检查转储文件的有效性”,而这本来是开始的全部意义。 - kmkaplan
这正是我正在寻找的:一种在不进行完整文件读取的情况下处理文件的最后一行的方法...就像在压缩时那样简单。谢谢。 - tdaget

1

您可以通过使用现有的验证(借助zcattail)并从stdin而非已写入的文件中读取,轻松确定在管道中处理的最后一行,而不是从磁盘中确定:

mysqldump args | gzip - | tee fullDump.gz | zcat - | tail -n1

这将为您提供最后一行已解压缩的处理数据,您可以将其与Dump completed字符串进行比对以检查是否成功。
这很简单,但不是完全可靠的,因为有小概率tee无法完成向磁盘的写入,但是已经完成了向标准输出的写入:
如果任何一个成功打开的文件操作数写入失败,则其他成功打开的文件操作数和标准输出的写入将继续,但退出状态将为非零。 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/tee.html 为了防止这种可能的失败,我们可以稍微调整一下此管道。
mysqldump args | gzip - | { tee foo.gz || echo "fail" | gzip -; } | zcat - | tail -n1

tee退出非0时,我们会将fail作为最后一行输出。如果你使用的是bash作为你的shell,你可以选择使用pipefailset -euxo pipefail),这将导致此管道在任何命令失败时退出非0(而不仅仅是最后一个)。


这很糟糕:它未能“检查转储文件的有效性”,而这本来是开始的全部意义。 - kmkaplan
公平的,固定的。我选择了最受欢迎的答案而不是问题本身@kmkaplan - Matthew Story
现在我感到困惑了。tee命令可以先将内容写入文件再输出到stdout,还是相反?这个规定是什么? - kmkaplan
@kmkaplan,我们还有一些工作要做:如果对任何成功打开的文件操作数进行写入失败,则对其他成功打开的文件操作数和标准输出的写入将继续进行,但退出状态应为非零。~http://pubs.opengroup.org/onlinepubs/9699919799/utilities/tee.html - Matthew Story
@kmkaplan,这个边缘情况现在已经被覆盖了。 - Matthew Story

0

如果您真的想要检查压缩文件的完整性,可以将格式从gz更改为其他格式,并执行类似的操作

# strings used in order to clean up if it gets messy
dd if=dump.compressed.not-gz bs=1m skip=195000 | compress-tool -df | strings | grep 'Dump complete'

编辑: 在压缩注入了“dump complete”字符串的转储时,您还可以调试gz并发现其签名。数据库转储类似,因此可能在所有转储上都是相同的。如果是这样,请像上面那样grep它,但不使用compress和strings命令。


1
在转储过程中,您可以查找该行。无论如何,最好使用更复杂的方法来验证备份。 - user933161

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接