记录一次使用 Mysqldump 备份数据的bug排查过程,你绝对想不到是什么?

零 Mysql教程评论71字数 4984阅读16分36秒阅读模式

记录一次使用 Mysqldump 备份数据的bug排查过程,你绝对想不到是什么?

前记:

有好长时间工作项目用的都是 PostgresSQL,没有用到 Mysql。

最近自己突发奇想,花了两周的时间做了个小程序项目并还上线了。今天先不说小程序用户的事儿,主要是前期啥也没考虑就直接开干导致现在需要还技术债来了。文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/16784.html

项目架构

简单说一下,因为做个小程序,而且是个人的那种,所以没有啥负担,也没有怎么考虑。文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/16784.html

  • 服务端 golang + go-zero
  • 数据库 Mysql docker
  • 前端就是小程序了

也许你觉得没啥架构,确实没有?。文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/16784.html

数据库直接使用 Docker 安装的 Mysql,启动命令:文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/16784.html

docker run --name=mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:8.1文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/16784.html

这样数据库就运行起来了。是很简单吧,不过也给今天的我制造了一个小小的困难。文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/16784.html

问题发现

今天本地的 Docker 提示我更新版本,然后我就按照他的提示去更新版本:文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/16784.html

image-20240705230359476文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/16784.html

按照提示去更新后需要重启 Docker,起来突然发现Docker 部署的容器都没有了,那意味着我的本地数据也已经没有了。文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/16784.html

突然意识 Mysql 数据库两个问题(也许你已经从上面 docker 的启动命令看出来了):文章源自灵鲨社区-https://www.0s52.com/bcjc/mysqljc/16784.html

  • docker 启动命令没有 -v 参数
  • 没有做数据备份

上面两个一个都没有做那就意味着一旦发生 Docker 丢失容器的问题,就会导致数据库中的数据全部丢失,以至于找不回来。(个人项目如此,那么公司的项目不管是开发者还是运维都需要考虑数据备份的问题)

既然已经发现了致命的,重要的,紧急的事情那么直接开干,备份数据。

备份数据

方案 1:

Mysql 数据备份最直接的操作或者命令就是 mysqldump,使用简单(几乎所有的备份数据都用它)。

mysqldump命令详解

mysqldump 是一个用于导出 MySQL 数据库的命令行工具。它可以将数据库或特定表的数据导出到一个文本文件中,通常用于备份或迁移数据库。

mysqldump [OPTIONS] DATABASE [TABLE...]

这将导出指定的数据库和表到标准输出。

  1. -u, --user=#user:指定连接到 MySQL 服务器时使用的用户名。
  2. -p, --password[=#password] :指定连接到 MySQL 服务器时使用的密码。如果只使用 -pmysqldump 会提示输入密码。
  3. -h, --host=#hostname:指定 MySQL 服务器的主机名或 IP 地址。
  4. -P, --port=#port:指定连接到 MySQL 服务器的端口号。
  5. -S, --socket=#socket:指定用于本地 MySQL 服务器连接的 socket 文件。
  6. --databases, -B:导出所有指定的数据库。
  7. --all-databases:导出所有数据库。
  8. --tables, -T:导出所有指定的表。
  9. --no-create-info:在导出的文件中不包含创建表的 SQL 语句。
  10. --no-data:只导出表结构,不导出数据。
  11. --complete-insert:使用完整的 INSERT 语句,包含列名。
  12. --extended-insert:使用扩展的 INSERT 语句,提高导出效率。
  13. --single-transaction:对于事务性表(InnoDB),使用事务来导出数据,确保数据的一致性。
  14. --where=#expr:只导出满足特定条件的行。
  15. --lock-tables:在导出之前锁定所有表。
  16. --skip-lock-tables:在导出时不锁定表。
  17. --compress, -C:使用压缩协议来传输数据。
  18. --order-by-primary:按照主键顺序导出数据。
  19. --results-file=#file:将导出的结果写入到指定的文件中。
  20. --routines, -R:导出存储过程和函数。
  21. --triggers:导出触发器。
  22. --events:导出事件。
  23. --column-statistics=0:不导出列的统计信息。
  24. --default-character-set=#charset:指定默认字符集。
  25. --tz-utc:使用 UTC 时间戳。
  26. --max-allowed-packet=#bytes:设置最大数据包大小。
  27. --verbose, -v:显示更多的信息。
  28. --help, -? :显示帮助信息。
  29. --version:显示版本信息。

执行命令备份命令,因为我是 docker 中部署的 mysql,那么需要在 docker 中执行 mysqldump 命令:

shell

复制代码
 docker exec -it mysql mysqldump -u root -p root aimage | gzip > /wwwroot/backup/mysql/aimage_2024-07-05.sql.gz

查看文件 ls -lh /wwwroot/backup/mysql

image-20240705232848000

编写备份脚本 shell:

看到数据文件已经有了,大小也是对的。命令没有问题。既然命令没有问题那么去编写shell脚本,使用 Linux的定时任务 crontab 去执行,总之不能手动执行。

shell

复制代码
 #!/usr/bin/bash
 ​
 curent_date=$(date +'%Y-%m-%d')
 ​
 mysql_backup_directory="/wwwroot/backup/mysql"
 backup_file=$mysql_backup_directory/aimage_$curent_date.sql.gz
 ​
 # 启动 docker exec 命令并使用管道执行
 ​
 docker exec -it mysql mysqldump -u root -p root aimage | gzip > ${backup_file}

脚本编写完成后赋予可执行权限 chmod =x ./backup.sh

手动执行脚本,测试脚本知识正常:./backup.sh,执行完成查看数据没有问题,数据大小也是对的。

image-20240705233523518

设置定时任务:

crontab -e 打开定时任务配置,添加下面的配置,设置每天的 1 点去执行备份数据:

* * * * * /wwwroot/shell/backup.sh 为了先测试定时任务是否可以正常执行,暂时先设置每分钟去执行一遍:

image-20240705234016937

一分钟过后,查看数据,发现数据文件大小很小,可以判断为数据为空:

image-20240705235057938

这是为什么呢? 开始查找答案:

修改定时任务的命令: * * * * * /wwwroot/shell/backup.sh > /wwwwroot/backup/msql/log.log 2>&1 监控错误输出 device is not a TTY

不认识这个错误,查查 豆包看看回复:

"device is not a TTY" 这个错误信息通常出现在尝试在非终端(TTY)设备上执行需要交互式输入的命令或脚本时。TTY(Teletypewriter)是一个传统的术语,指的是可以输入和输出文本的设备,比如终端或控制台窗口。

以下是一些可能导致这个错误的原因和相应的解决方法:

  1. 脚本或命令需要交互式输入:如果脚本或命令设计为需要用户输入,而在非交互式环境中运行(如cron作业),则可能遇到此错误。解决方法是修改脚本以接受命令行参数或配置文件输入,而不是依赖交互式输入。
  2. 使用管道或重定向:在使用管道(|)或重定向(> 或 >>)时,输出设备可能不是TTY,导致某些命令无法正常工作。确保所有需要交互的命令都有正确的输出目标。
  3. cron作业:在cron作业中,环境与交互式shell不同。如果脚本中有命令需要交互式环境,可以尝试使用expect脚本或类似工具来自动化交互过程。
  4. SSH会话:在使用SSH远程执行命令时,如果会话不是交互式的,也可能出现这个错误。确保SSH配置允许交互式会话,或者修改命令以适应非交互式环境。
  5. 脚本中的特定命令:某些命令,如readpasswd等,需要交互式环境。如果这些命令在脚本中使用,而脚本在非交互式环境中运行,就会出现错误。解决方法是修改脚本逻辑或使用其他不需要交互的命令。
  6. 环境变量问题:确保脚本中使用的环境变量在非TTY环境中也被正确设置。有时,交互式和非交互式环境之间的环境变量设置可能不同。
  7. 权限问题:确保执行脚本的用户有足够的权限在非TTY环境中运行脚本中的命令。
  8. 检查脚本的shebang行:脚本的第一行通常是shebang(#!)指定解释器的路径,如#!/bin/bash。确保这一行正确无误,并且指定的解释器在非TTY环境中可用。

根据第三点来说,目前遇到的确实是这个问题,因为 mysqldump 需要交互式的输入 password 才能执行。

mysqldump 免密执行一般有下面几种方法:

  1. 使用配置文件: 你可以在 ~/.my.cnf 或 /etc/my.cnf 文件中设置认证信息。以下是一个配置文件的示例:

ini

复制代码
 [client]
 user=your_username
 password=your_password
  1. 使用 --defaults-file 选项: 如果你不想将密码存储在全局配置文件中,可以创建一个只包含密码信息的文件,并使用 --defaults-file 选项指定该文件:

css

复制代码
  mysqldump --defaults-file=/path/to/your_config.cnf your_database > backup.sql
  1. 使用 --defaults-extra-file 选项

css

复制代码
 mysqldump --defaults-extra-file=/path/to/your_extra.cnf your_database > backup.sql
  1. 使用环境变量配置密码

ini

复制代码
  MYSQL_PWD=your_password mysqldump -u your_username your_database > backup.sql
  1. 使用 expect 脚本

使用 expect 来自动化脚本,可以编写一个脚本来自动输入密码

  1. 使用 SSH 隧道

如果数据库服务器和应用程序服务器不在同一个地方,你可以使用 SSH 隧道来安全地连接到数据库服务器,并运行 mysqldump

对于我,上面的几个方法我都逐一尝试过,我的答案是不行。还是报错:device is not a TTY

继续问问豆包,给到的回复是:

image-20240706001151304

貌似跟上面的回答是一样的。

突然灵机一闪,这个命令 docker exec -it mysql mysqldump -u root -p root aimage | gzip > ${backup_file} -t 参数是干嘛的呢?

image-20240706002347129

-t, --tty: 分配一个伪终端。如果你想要容器内的标准输入保持打开状态,即使没有附加到终端,这个选项很有用。

?,貌似找到了答案。现在就是 tty 的问题,那我们吧命令中 -it => -i是不是就好了。赶紧修改代码:

image-20240706002657681

测试 crontab:

image-20240706003034789

奇迹就这样发生了。一切也改结束了 ?。

所以以后如果执行类似的命令一定要吧 -t 参数去掉。

方案2:

上面也说了,第二个方案就是在启动 docker 容器的时候记得加上 -v 数据卷目录映射。这样一旦 doker 容器 mysql 有问题,可以重新安装指定相同的 -v 参数就可以立即回复数据。保证不丢失。

那对于已经启动的容器改如何解决呢?

给大家提供一个不是方法的方法:

1、查看 mysql 容器的数据卷默认挂载的目录:

查看容器的 ID:

image-20240706003613966

使用 docker inspect 容器 id 查看容器详细信息:

image-20240706003722013

找到这一段数据后, Source 是宿主机存放目录的地方,Destination 是容器里面的数据存储地方,他两是对应的,那我们另辟蹊径,将Source指向的地址做个备份是不是也没问题?

image-20240706004215634

嗯,看一眼没有任何问题。我们可以重新启动一个容器并吧这个目录使用 -v 参数做数据卷映射。然后观察数据是否跟备份的数据是一致的。

总结:

这篇文章主要介绍的是在 使用 mysqldump 命令过程中遇到的一些问题,以及解决过程。

  • 如果 mysql 是在实体机器上部署,使用 -u -p 参数是没有任何问题的。在 crontab 中执行也是没有问题的。
  • 如果要执行 docker 中的 mysqldump 那么,命令中一定记得吧 -t 参数去掉,否则执行失败,报错 device is not a TTY
  • 解决过程可以使用豆包或者搜索引擎,建议豆包,回答题更直接。
  • 备份数据很重要,甚至要多备份,做好数据问题的后备处理,如果你的系统数据量比较大,那么你的备份至少需要一天 2 次备份甚至更多。备份的数据也需要做到备份。

零
  • 转载请务必保留本文链接:https://www.0s52.com/bcjc/mysqljc/16784.html
    本社区资源仅供用于学习和交流,请勿用于商业用途
    未经允许不得进行转载/复制/分享

发表评论