在数据库备份过程中,我生成一个文本转储文件。由于数据库很大,转储文件也很大,所以我用gzip压缩了它。压缩是在生成转储时内联完成的(感谢Unix管道!)。
在过程结束时,我通过观察最后一行来检查转储文件的有效性,并检查“转储完成”字符串的存在。在我的脚本中,我通过将最后一行提取到变量中来做到这一点:
str=`zcat ${PATHSAVE}/dumpFull.sql.gz | tail -n1`
由于数据库转储文件很大(当前超过200Gb),因此此最终过程检查需要大量时间(当前超过180分钟)运行。
我正在寻找一种方法来更快地提取.gz文件的最后一行……有人知道吗?
注1:为了说明上下文,我们可以说数据库是MySql社区,备份工具是mysqldump,生成的dumpfile是全文文件。操作系统是CentO。备份脚本是Bash shell脚本。
注意2:我知道Percona xtraBackup,但就我而言,我想针对此特定备份作业使用mysqldump。恢复时间不成问题。
答案 0 :(得分: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指出,某些外壳程序(包括bash
)具有进程替换功能,因此,如果您使用这些外壳程序之一,则命令可以更简单。
mysqldump whatever | tee >(tail -1 > lastline.txt ) | gzip >dump.gz
在这种情况下,shell为您创建了自己的管道。
答案 1 :(得分:1)
仅通过使用现有验证(使用zcat
和tail
)并从stdin中读取而不是从书面中读取,您可以轻松地确定管道中处理的最后一行,而不是从磁盘中确定文件:
mysqldump args | gzip - | tee fullDump.gz | zcat - | tail -n1
这将为您提供未压缩的最后处理行,您可以根据Dump completed
字符串检查是否成功。
这很简单,但并不是100%防弹,因为tee
极有可能无法完成写入磁盘,但无法完成向stdout的写入:
如果对任何成功打开的文件操作数的写操作失败,则对其他成功打开的文件操作数的写操作将继续,并且标准输出应继续,但退出状态应为非零。
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/tee.html
为了防止这种可能的失败,我们可以简单地修饰一下管道:
mysqldump args | gzip - | { tee foo.gz || echo "fail" | gzip -; } | zcat - | tail -n1
在fail
退出非0的情况下,我们发出tee
作为最后一行。如果您将bash用作shell,则可以交替使用pipefail
(set -euxo pipefail
),如果有任何命令失败(而不仅仅是最后一个命令),这将导致该管道退出非0。 >
答案 2 :(得分: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'
编辑: 您也可以在压缩转储时调试gz,在该转储中您已经注入了“ dump complete”字符串并发现了其签名。数据库转储是相似的,因此也许所有转储都相同。如果是这样,只需像上面那样使用grep即可,但不使用compress和strings命令