ib_logfile0和ib_logfile1被覆盖但是mysql还在正常运行,复现问题记录排查流程,涉及文件系统的一些知识点。
- 速查
- 拿到FD:lsof | grep /u01/database/data/ | grep delete
- 查看FD:stat /proc/23141/fd/4
复现问题
docker1新建空实例,删除后docker1还可以正常使用
代码语言:javascript复制rm ib_logfile0
rm ib_logfile1
问题排查
1 为什么文件被删除了还能正常运行
在linux中,每个文件都有两个 link 计数器:
- i_count:文件使用者或者被调用的数量,理解为内存引用的计数器。文件被进程打开使用的时候,自增 1。
- i_nlink:硬链接的数量,理解为磁盘引用计数器。创建文件的硬链接的时候,自增 1。
执行rm操作的时候,实际是 i_nlink-1,不一定真正删除文件,只有当 i_nlink=0 & i_count=0 时,文件才会被真正删除。
案例中的 ib_logfile[*]由于没有新创建硬链接,所以 i_nlink = 1,加上此时 3306实例处于运行中,需要调用 到 ib_logfile[*]文件,所以 i_count = 1( 当前无其他进程使用到ib_logfile[*] ),当文件被删除的时候,i_nlink =0 但是 i_count=0,故文件不会被真正删除,仅删除 inode 连接,并没有删除 磁盘的数据块。
那么被进程调用的文件,遭遇 rm 操作,那么它将何去何从呢?
首先,该文件的 i_nlink被删除,剩下 i_count,故仅删除磁盘硬链接,内容未删除。可以通过 proc 文件系统查找文件。每个进程都有进程id,可以通过 proc文件系统查找到该进程打开及调用的文件的链接。
代码语言:javascript复制ps -ef | grep /usr/sbin/mysqld
polkitd 23141 22443 0 Jan04 pts/14 00:01:22 /usr/sbin/mysqld --defaults-file=/u01/database/my.cnf --basedir=/usr --datadir=/u01/database/data --plugin-dir=/usr/lib/mysql/plugin --user=mysql --log-error=/u01/database/log/alert.log --pid-file=/u01/database/run/mysqld.pid --socket=/u01/database/run/mysql.sock --port=3306
4uW,9uW COMMAND:进程的名称 PID:进程标识符 PPID:父进程标识符(需要指定-R参数) USER:进程所有者 PGID:进程所属组 FD:文件描述符,应用程序通过文件描述符识别该文件。如cwd、txt等: (1)cwd:表示current work dirctory,即:应用程序的当前工作目录,这是该应用程序启动的目录,除非它本身对这个目录进行更改 (2)txt :该类型的文件是程序代码,如应用程序二进制文件本身或共享库,如上列表中显示的 /sbin/init 程序 (3)lnn:library references (AIX); (4)er:FD information error (see NAME column); (5)jld:jail directory (FreeBSD); (6)ltx:shared library text (code and data); (7)mxx :hex memory-mapped type number xx. (8)m86:DOS Merge mapped file; (9)mem:memory-mapped file; (10)mmap:memory-mapped device; (11)pd:parent directory; (12)rtd:root directory; (13)tr:kernel trace file (OpenBSD); (14)v86 VP/ix mapped file; (15)0:表示标准输入 (16)1:表示标准输出 (17)2:表示标准错误 一般在标准输出、标准错误、标准输入后还跟着文件状态模式:r、w、u等 (1)u:表示该文件被打开并处于读取/写入模式 (2)r:表示该文件被打开并处于只读模式 (3)w:表示该文件被打开并处于 (4)空格:表示该文件的状态模式为unknow,且没有锁定 (5)-:表示该文件的状态模式为unknow,且被锁定 同时在文件状态模式后面,还跟着相关的锁 (1)N:for a Solaris NFS lock of unknown type; (2)r:for read lock on part of the file; (3)R:for a read lock on the entire file; (4)w:for a write lock on part of the file;(文件的部分写锁) (5)W:for a write lock on the entire file;(整个文件的写锁) (6)u:for a read and write lock of any length; (7)U:for a lock of unknown type; (8)x:for an SCO OpenServer Xenix lock on part of the file; (9)X:for an SCO OpenServer Xenix lock on the entire file; (10)space:if there is no lock. TYPE:文件类型,如DIR、REG等,常见的文件类型: (0)REG:文件 (1)DIR:表示目录 (2)CHR:表示字符类型 (3)BLK:块设备类型 (4)UNIX: UNIX 域套接字 (5)FIFO:先进先出 (FIFO) 队列 (6)IPv4:网际协议 (IP) 套接字 DEVICE:指定磁盘的名称 SIZE:文件的大小 NODE:索引节点(文件在磁盘上的标识) NAME:打开文件的确切名称
文件已经被删了,上面看到df是4和9,检查进程使用的fd链到哪了
代码语言:javascript复制[root@ecs /proc/23141/fd]# stat /proc/23141/fd/4
File: ‘/proc/23141/fd/4’ -> ‘/u01/database/data/ib_logfile0 (deleted)’
Size: 64 Blocks: 0 IO Block: 1024 symbolic link
Device: 3h/3d Inode: 63597018 Links: 1
Access: (0700/lrwx------) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2020-01-05 21:07:39.435295386 0800
Modify: 2020-01-04 20:27:58.000253194 0800
Change: 2020-01-04 20:27:58.000253194 0800
Birth: -
[root@ecs /proc/23141/fd]# stat /proc/23141/fd/9
File: ‘/proc/23141/fd/9’ -> ‘/u01/database/data/ib_logfile1 (deleted)’
Size: 64 Blocks: 0 IO Block: 1024 symbolic link
Device: 3h/3d Inode: 63597023 Links: 1
Access: (0700/lrwx------) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2020-01-05 21:07:39.435295386 0800
Modify: 2020-01-04 20:27:58.000253194 0800
Change: 2020-01-04 20:27:58.000253194 0800
Birth: -
2 数据写到哪去了?
方便看下数据写到哪里去了,这里把ibdata1也删了
代码语言:javascript复制lsof | grep /u01/database/data/ | grep delete | grep /u01/database/data/ibdata1
mysqld 23141 polkitd 10uW REG 252,0
12582912 7340630 /u01/database/data/ibdata1 (deleted)
lsof | grep /u01/database/data/ | grep delete | grep /u01/database/data/ibdata1
(size)
12582912 7340630 /u01/database/data/ibdata1 (deleted)
灌些数据进去
sysbench oltp_common --mysql-host=172.17.0.3 --mysql-user=root --mysql-port=3306 --mysql-password=root --mysql-db=server_234_db2 --db-driver=mysql --tables=128 --table-size=10000 --report-interval=1 --threads=128 prepare
再看文件大小已经变化了!(stat看不到,删除的只能用lsof看)
所以数据实际是写入被删除的文件中的
3 如何恢复
停写后用文件句柄把数据捞回来,例如上图的ibdata
代码语言:javascript复制cat /proc/23141/fd/10 > /u01/database/data/ibdata1
注意要确保文件无写入!