为什么ib_logfile被覆盖Mysql还能正常运行!?

2022-05-12 09:42:42 浏览数 (2)

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

注意要确保文件无写入!

0 人点赞