今天本来想上blog更新一点东西,结果发现上不去了,提示“Error establishing database connection”。连上服务器发现服务器的MariaDB数据已经退出,尝试用systemctl restart重启无效。

用journalctl -xe发现了如下的日志:

Jan 15 10:43:27 chariri-wp mariadbd[1238314]: 2022-01-15 10:43:27 0 [ERROR] [FATAL] InnoDB: InnoDB is trying to free page [page id: space=14, page number=135] though it is already marked as free in the tablespace! The tablespace free space info is corrupt. You may need to dump your tables and recreate the whole database!Please refer to https://mariadb.com/kb/en/library/innodb-recovery-modes/ for information about forcing recovery.
Jan 15 10:43:27 chariri-wp mariadbd[1238314]: 220115 10:43:27 [ERROR] mysqld got signal 6 ;
Jan 15 10:43:27 chariri-wp mariadbd[1238314]: This could be because you hit a bug. It is also possible that this binary
Jan 15 10:43:27 chariri-wp mariadbd[1238314]: or one of the libraries it was linked against is corrupt, improperly built,
Jan 15 10:43:27 chariri-wp mariadbd[1238314]: or misconfigured. This error can also be caused by malfunctioning hardware.
Jan 15 10:43:27 chariri-wp mariadbd[1238314]: To report this bug, see https://mariadb.com/kb/en/reporting-bugs
Jan 15 10:43:27 chariri-wp mariadbd[1238314]: We will try our best to scrape up some info that will hopefully help
Jan 15 10:43:27 chariri-wp mariadbd[1238314]: diagnose the problem, but since we have already crashed,
Jan 15 10:43:27 chariri-wp mariadbd[1238314]: something is definitely wrong and this may fail.
Jan 15 10:43:27 chariri-wp mariadbd[1238314]: Server version: 10.5.13-MariaDB-0ubuntu0.21.10.1

参照第一行,貌似是数据库文件不consistent造成的问题。用mysqlcheck自然是无法自动修复的,于是如第一行所说的,我决定手动重建数据库。为了防止PHP读写数据库造成进一步的问题,我先关掉了PHP服务。

由于数据库目前处于一开就崩的状态,我们需要先在MariaDB的配置里添加“InnoDB强制恢复”选项。在我的服务器是 /etc/mysql/mariadb.conf.d/50-server.cnf 下的 [mysqld] 段下,添加 innodb_force_recovery = 1 语句。其中的1是恢复等级,支持1~6,越高的等级关闭的检查就越多,整个过程越激进,也越容易毁坏数据。因此在进行这种配置之前,应该先备份整个数据库文件夹。

关于innodb_force_recovery的官方文档在这里。里面提到了应该从1开始,一步一步提高等级直到MariaDB启动不崩溃。我在设置成2的时候成功启动了。

启动后我运行了 mysqlcheck -a -A 进行检查,提示cwp_postmeta这个表有问题。

貌似不是特别核心的表,因此我通过mysqldump和mysql,dump出来这个表,drop再恢复的方法重建了这个表。在配置文件中关掉innodb_force_recovery,重启MariaDB和PHP,网站恢复。

可能的原因

我实在是没有这次事故的原因的头绪。最可能出问题的应该就是前几天配置的restic。因为ext4文件系统没有类似Windows上VSS的机制,我又图省事直接用restic备份了MariaDB的datadir,可能restic锁住了数据库文件造成各文件inconsistent。同时我从restic上恢复下来的文件也没法用。

因此,一个教训是:不要用restic直接备份MariaDB的数据文件夹,应该考虑用mysqldump等工具完全备份下整个数据库,再用restic对备份下的.sql文件进行离线备份。


不想被自己的惰性打败。