MySQL 数据库从宕机状态恢复服务到卸载重装 MySQL
前言
前几天上一家公司老板突然找我,让我帮他部署一下之前因为服务器被勒索攻击而宕机的应用服务。说实话,这位老板人品太差,不太想帮他。考虑到现在公司工资发的时间太诡异无常了,就想着赚个辛苦钱吧,把他服务器的服务恢复一下。也跟他明确讲清楚,只负责服务器代码部署,其他的不管。事实证明我年轻了,他的划水忽悠能力很强,美其名让我多赚点,其实扣扣索索想让我付出更多,然后自己一毛不拔。这个暂且不提,主要记录一下服务器上 MySQL 数据库的恢复过程。
过程
拿到服务器的账号密码,进去发现代码都还在,但数据库连不上了。没有 MySQL 服务的情况下,尝试登录得到就是 cannot connect to the mysql server through socket 'tmp/mysql.sock'
和 Can't connect to MySQL server on '127.0.0.1' (111)
的报错。service 和 systetmctl 指令都不能启动服务,后者还报了错:Failed to start mysqld.service: Unit not found
。
百度 start mysqld.service: Unit not found
,得到的解决方案是安装 mariadb-server。因为 MySQL 高版本的内核服务改名叫 MariaDB,安装 MySQL 的时候还需要安装这些依赖,详见:CentOS7 中找不到 mysql 服务(yum安装)。猜测大概是 MySQL 数据库遭到攻击,部分服务被删除了。按照教程上讲 MariaDB 相关的依赖都安装之后,需要启动 mariaDB 服务:systemctl start mariadb.service
,添加到开启自启:systemctl enable mariadb.service
。但启动服务时又报错了:Cannot change ownership of the database directories to the /var/part1/data
。
查看了一下回想起来,这个目录地址是之前修改后数据库默认存储路径,详见:修改mysql 数据库默认存储路径。尝试查看目录,发现目录已经为空了,fdisk -lh
看到之前挂在的数据盘也丢失了。存储数据的目录没了,find / -name my.cnf
全局查找 MySQL 的配置文件,修改 datadir 设置到原来默认的地址 /usr/local/mysql/var
。再次启动 mariaDB 服务,成功。service mysql restart
尝试启动 MySQL 数据库,又报错了:Starting MySQL... ERROR! The server quit without updating PID file
,尝试新建一个 /usr/local/mysql/var2
目录并修改 datadir 路径,再次启动 MySQL,终于成功了。
尝试创建可远程连接的用户,以方便后续通过 navicat 备份还原数据库。show database;
查看数据库发现,竟然没有 mysql 数据库,更不谈 user 表了。突然回想到之前是怎么用密码登录进来的,检查发现,默认 root 账号不需要密码,可以直接登录的。那么 root 账号应该是存在于某个地方的,也就是说 mysql 数据库是存在的,但不显示也找不到。网上找了一圈教程,大概讲因为 MySQL 重新安装之前的版本没有卸载干净导致 mysql 数据库不显示了。这种情况没有办法处理,只能卸载重修安装,并且要把之前的安装目录内容和配置文件全部删除干净。yum 卸载所有相关软件,rm -rf /usr/local/mysql
删除安装目录,然后再用 yum 重新安装。
安装好后,启动 mariadb-server 服务,启动 MySQL 仍然提示 Unit 服务不存在。但 mysql -u -p
已经可以登录进去了。ps aux | grep mysql
有查看到 mysqld 进程,但是不管是 mysql 还是 mysqld 服务都显示不存在。但 MySQL 服务确实已经可以用了。猜测 MySQL 新版本(5.5) mariadb-server 服务就是 MySQL 服务了。创建好远程连接用户,最后就是将数据库还原。
首先需要将数据库导入到本地,然后通过 navicat 的备份还原功能快速创建好线上的数据库。现实又狠狠扇了我一巴掌。之前的数据库是 sql 文件形式,有两个问题,一个是很多字段定义不标准,没有默认值,或者其他各种情况导致导入不完全。另一个问题是里面数据量太大,有些表的 insert 语句有两百多万的记录,有些字段还报错:Row size too large (> 8126)
,这也会直接导致导入失败。后者主要针对 create 语句中定义了 ROW_FORMAT 类型的字段,需要将其属性改成 COMPRESSED 或者 DYNAMIC。
前面一个问题就不好搞了,需要一个表接着一个表去排查字段默认值,类型等等问题,主要遇到的是 datetime 和 timestamp 字段的默认值问题。之前可能不设置默认值也可以通过的,或者都设置为 CURRENT_TIMESTAMP、'0000-00-00 00:00:00'。现在不行,检查机制可能更加严格,datetime 需要设置为 CURRENT_TIMESTAMP,timestamp 虽然显示跟 datetime 差不多,但内部存储不一样,还是要设置成其所属整型 0。