【问题标题】:Get last line of a huge gziped file获取一个巨大的 gzip 文件的最后一行
【发布时间】:2018-12-08 18:57:20
【问题描述】:

在数据库备份过程中,我生成了一个文本转储文件。由于数据库很大,转储文件也很大,所以我用 gzip 压缩它。压缩是在生成转储时内联完成的(感谢 Unix 管道!)。

在流程结束时,我通过查看最后一行检查转储文件的有效性并检查“转储完成”字符串是否存在。在我的脚本中,我通过将最后一行提取到变量中来做到这一点:

str=`zcat ${PATHSAVE}/dumpFull.sql.gz | tail -n1`

由于数据库转储文件很大(目前超过 200 Gb),此结束进程检查需要很长时间才能运行(目前超过 180 分钟)。

我正在寻找一种方法来更快地提取 .gz 文件的最后一行...有人知道吗?

注1:为了解释上下文,我们可以说数据库是MySql社区,备份工具是mysqldump,生成的dumpfile是一个全文文件。操作系统是 CentOs。备份脚本是 Bash shell 脚本。

注意 2: 我知道 Percona xtraBackup,但在我的情况下,我想将 mysqldump 用于这个特定的备份工作。恢复所需的时间不是问题。

【问题讨论】:

  • 你能改变gzip文件的创建方式吗? gzip 格式的一个子集被称为“rsyncable”gzip,它每隔一段时间就会重置压缩表;对于那些人来说,中途开始阅读是可行的(只丢弃直到下一个重置点的信息)。当然,压缩比会有所损失,但可以通过更改此类重启的频率来调整。

标签: mysql bash shell


【解决方案1】:

这是 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 会为您创建自己的管道。

信用:Pipe output to two different commands

【讨论】:

  • 这很糟糕:它无法“检查转储文件的有效性”,这是开始的重点。
  • 这正是我正在搜索的内容:一种无需读取完整文件即可处理文件最后一行的方法……就像在压缩时执行此操作一样简单。谢谢
【解决方案2】:

如果你真的想检查压缩文件的完整性,你可以从 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'

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

【讨论】:

  • 您可以在转储过程中查找该行。无论如何,您最好使用更复杂的方法来验证备份。
【解决方案3】:

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

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

这将为您提供最后处理的行,解压缩后,您可以检查 Dump completed 字符串是否成功。

这很简单,但不是 100% 防弹,因为 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,您可以交替使用 pipefail (set -euxo pipefail),如果任何命令失败(而不仅仅是最后一个命令),这将导致此管道退出非 0。

【讨论】:

  • 这很糟糕:它无法“检查转储文件的有效性”,这是开始的重点。
  • 公平,已修复。离开了最受欢迎的答案,而不是@kmkaplan 的问题
  • 现在我很困惑。 tee 命令可以在标准输出之前写入文件......或者相反。指定了吗?
  • @kmkaplan 我们还有一些工作要做:如果写入任何成功打开的文件操作数失败,写入其他成功打开的文件操作数和标准输出应继续,但退出状态应为非-零。 ~pubs.opengroup.org/onlinepubs/9699919799/utilities/tee.html
  • @kmkaplan 现在已经涵盖了这种边缘情况
猜你喜欢
  • 2011-05-06
  • 2015-09-07
  • 2015-09-26
  • 1970-01-01
  • 1970-01-01
  • 2012-08-23
  • 2021-05-29
相关资源
最近更新 更多