前记:
有好长时间工作项目用的都是 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
文章源自灵鲨社区-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...]
这将导出指定的数据库和表到标准输出。
- -u, --user=#user:指定连接到 MySQL 服务器时使用的用户名。
- -p, --password[=#password] :指定连接到 MySQL 服务器时使用的密码。如果只使用
-p
,mysqldump
会提示输入密码。 - -h, --host=#hostname:指定 MySQL 服务器的主机名或 IP 地址。
- -P, --port=#port:指定连接到 MySQL 服务器的端口号。
- -S, --socket=#socket:指定用于本地 MySQL 服务器连接的 socket 文件。
- --databases, -B:导出所有指定的数据库。
- --all-databases:导出所有数据库。
- --tables, -T:导出所有指定的表。
- --no-create-info:在导出的文件中不包含创建表的 SQL 语句。
- --no-data:只导出表结构,不导出数据。
- --complete-insert:使用完整的 INSERT 语句,包含列名。
- --extended-insert:使用扩展的 INSERT 语句,提高导出效率。
- --single-transaction:对于事务性表(InnoDB),使用事务来导出数据,确保数据的一致性。
- --where=#expr:只导出满足特定条件的行。
- --lock-tables:在导出之前锁定所有表。
- --skip-lock-tables:在导出时不锁定表。
- --compress, -C:使用压缩协议来传输数据。
- --order-by-primary:按照主键顺序导出数据。
- --results-file=#file:将导出的结果写入到指定的文件中。
- --routines, -R:导出存储过程和函数。
- --triggers:导出触发器。
- --events:导出事件。
- --column-statistics=0:不导出列的统计信息。
- --default-character-set=#charset:指定默认字符集。
- --tz-utc:使用 UTC 时间戳。
- --max-allowed-packet=#bytes:设置最大数据包大小。
- --verbose, -v:显示更多的信息。
- --help, -? :显示帮助信息。
- --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
编写备份脚本 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
,执行完成查看数据没有问题,数据大小也是对的。
设置定时任务:
crontab -e
打开定时任务配置,添加下面的配置,设置每天的 1 点去执行备份数据:
* * * * * /wwwroot/shell/backup.sh
为了先测试定时任务是否可以正常执行,暂时先设置每分钟去执行一遍:
一分钟过后,查看数据,发现数据文件大小很小,可以判断为数据为空:
这是为什么呢? 开始查找答案:
修改定时任务的命令: * * * * * /wwwroot/shell/backup.sh > /wwwwroot/backup/msql/log.log 2>&1
监控错误输出 device is not a TTY
不认识这个错误,查查 豆包看看回复:
"device is not a TTY" 这个错误信息通常出现在尝试在非终端(TTY)设备上执行需要交互式输入的命令或脚本时。TTY(Teletypewriter)是一个传统的术语,指的是可以输入和输出文本的设备,比如终端或控制台窗口。
以下是一些可能导致这个错误的原因和相应的解决方法:
- 脚本或命令需要交互式输入:如果脚本或命令设计为需要用户输入,而在非交互式环境中运行(如cron作业),则可能遇到此错误。解决方法是修改脚本以接受命令行参数或配置文件输入,而不是依赖交互式输入。
- 使用管道或重定向:在使用管道(
|
)或重定向(>
或>>
)时,输出设备可能不是TTY,导致某些命令无法正常工作。确保所有需要交互的命令都有正确的输出目标。- cron作业:在cron作业中,环境与交互式shell不同。如果脚本中有命令需要交互式环境,可以尝试使用
expect
脚本或类似工具来自动化交互过程。- SSH会话:在使用SSH远程执行命令时,如果会话不是交互式的,也可能出现这个错误。确保SSH配置允许交互式会话,或者修改命令以适应非交互式环境。
- 脚本中的特定命令:某些命令,如
read
、passwd
等,需要交互式环境。如果这些命令在脚本中使用,而脚本在非交互式环境中运行,就会出现错误。解决方法是修改脚本逻辑或使用其他不需要交互的命令。- 环境变量问题:确保脚本中使用的环境变量在非TTY环境中也被正确设置。有时,交互式和非交互式环境之间的环境变量设置可能不同。
- 权限问题:确保执行脚本的用户有足够的权限在非TTY环境中运行脚本中的命令。
- 检查脚本的shebang行:脚本的第一行通常是shebang(#!)指定解释器的路径,如
#!/bin/bash
。确保这一行正确无误,并且指定的解释器在非TTY环境中可用。
根据第三点来说,目前遇到的确实是这个问题,因为 mysqldump 需要交互式的输入 password 才能执行。
mysqldump 免密执行一般有下面几种方法:
- 使用配置文件: 你可以在
~/.my.cnf
或/etc/my.cnf
文件中设置认证信息。以下是一个配置文件的示例:ini
复制代码
[client] user=your_username password=your_password
- 使用
--defaults-file
选项: 如果你不想将密码存储在全局配置文件中,可以创建一个只包含密码信息的文件,并使用--defaults-file
选项指定该文件:css
复制代码
mysqldump --defaults-file=/path/to/your_config.cnf your_database > backup.sql
- 使用
--defaults-extra-file
选项:css
复制代码
mysqldump --defaults-extra-file=/path/to/your_extra.cnf your_database > backup.sql
- 使用环境变量配置密码
ini
复制代码
MYSQL_PWD=your_password mysqldump -u your_username your_database > backup.sql
- 使用
expect
脚本:使用
expect
来自动化脚本,可以编写一个脚本来自动输入密码
- 使用 SSH 隧道:
如果数据库服务器和应用程序服务器不在同一个地方,你可以使用 SSH 隧道来安全地连接到数据库服务器,并运行
mysqldump
。
对于我,上面的几个方法我都逐一尝试过,我的答案是不行。还是报错:device is not a TTY
继续问问豆包,给到的回复是:
貌似跟上面的回答是一样的。
突然灵机一闪,这个命令 docker exec -it mysql mysqldump -u root -p root aimage | gzip > ${backup_file}
-t 参数是干嘛的呢?
-t, --tty: 分配一个伪终端。如果你想要容器内的标准输入保持打开状态,即使没有附加到终端,这个选项很有用。
?,貌似找到了答案。现在就是 tty 的问题,那我们吧命令中 -it => -i
是不是就好了。赶紧修改代码:
测试 crontab:
奇迹就这样发生了。一切也改结束了 ?。
所以以后如果执行类似的命令一定要吧 -t
参数去掉。
方案2:
上面也说了,第二个方案就是在启动 docker 容器的时候记得加上 -v 数据卷目录映射。这样一旦 doker 容器 mysql 有问题,可以重新安装指定相同的 -v 参数就可以立即回复数据。保证不丢失。
那对于已经启动的容器改如何解决呢?
给大家提供一个不是方法的方法:
1、查看 mysql 容器的数据卷默认挂载的目录:
查看容器的 ID:
使用 docker inspect 容器 id
查看容器详细信息:
找到这一段数据后, Source 是宿主机存放目录的地方,Destination 是容器里面的数据存储地方,他两是对应的,那我们另辟蹊径,将Source指向的地址做个备份是不是也没问题?
嗯,看一眼没有任何问题。我们可以重新启动一个容器并吧这个目录使用 -v 参数做数据卷映射。然后观察数据是否跟备份的数据是一致的。
总结:
这篇文章主要介绍的是在 使用 mysqldump 命令过程中遇到的一些问题,以及解决过程。
- 如果 mysql 是在实体机器上部署,使用 -u -p 参数是没有任何问题的。在 crontab 中执行也是没有问题的。
- 如果要执行 docker 中的 mysqldump 那么,命令中一定记得吧 -t 参数去掉,否则执行失败,报错
device is not a TTY
。 - 解决过程可以使用豆包或者搜索引擎,建议豆包,回答题更直接。
- 备份数据很重要,甚至要多备份,做好数据问题的后备处理,如果你的系统数据量比较大,那么你的备份至少需要一天 2 次备份甚至更多。备份的数据也需要做到备份。
评论