版本:5.7.29
一、问题提出
一般情况下我们会使用lsof命令来查看MySQL当前使用的临时文件的使用,这是因为这些临时文件使用ls命令并不能显示,在5.7中其建立方式是使用Liunx api mkstemp进行的建立,这种文件是进程专用的,返回文件描述符后会使用api unlink进行删除。源码主要就是这一段,其包含在create_temp_file函数中。
org_file=mkstemp(to);
if (mode & O_TEMPORARY)
(void) my_delete(to, MYF(MY_WME));
在5.7中如下常见的一些功能会用到这种临时文件,比如:
- 执行计划file sort 文件名字MY开头
lsof|grep delete
如:/tmp/MYdRH1GW (deleted)
- 大事物binary log缓存 文件名字ML开头
lsof|grep delete
如:/tmp/MLq9INFu (deleted)
- online DDL 涉及排序比如add key
alter table testsort add key(id);
lsof|grep delete
如:
/tmp/ibCxlYQg (deleted)
/tmp/ib51nvZ1 (deleted)
设置 innodb_tmpdir可以将这类文件放到指定的目录
但是当一个MySQLD进程刚刚启动的时候我们去查看这类文件的时候,会发现很多这类文件,如下:
[root@mgr2 ~]# lsof|grep delete|grep mysql|wc -l
215
[root@mgr2 ~]#
这些文件大小基本都是0,且都已ib开头,曾经有朋友问过我这个问题,这里详细做一下解释。
二、MySQLD初始化后的临时文件种类
实际上在5.7中这类文件均由函数create_temp_file建立,那么我们就可以在MySQLD启动的时候将断点放在上面进行分析了。下面这样一些文件,均使用的是ib开头的临时文件。
-
srv_monitor_file (srv0start.cc:2022):这是我们通常show engine innodb status命令输出的时候使用到的文件,主要函数为srv_printf_innodb_monitor。栈针:
image.png -
srv_dict_tmpfile (srv0start.cc:2032):主要和外键创建信息输出有关。
-
srv_misc_tmpfile (srv0start.cc:2041):主要和外键抛错输出有关。
-
lock_latest_err_file (lock0lock.cc:465):主要和死锁报错输出有关。
-
dict_foreign_err_file (dict0dict.cc:1245):主要和外键抛错输出有关。
我们可以发现实际上这些文件都不会占用太大,实际上这5个文件初始化后就已经建立好了。
三、为什么lsof默认的输出会多很多
很明显我们上面ib打头的文件只有5个,那么我们lsof(不加任何参数)的时候看到的会多很多呢?如下是我初始化启动的情况下看到的个数:
[root@mgr2 support-files]# lsof|grep delete|grep mysql|wc -l
215
[root@mgr2 support-files]# lsof|grep delete|grep mysql
mysqld 12916 mysql 10u REG 8,5 9765 17109405 /tmp/ibpuzts2 (deleted)
mysqld 12916 mysql 11u REG 8,5 0 23137683 /tmp/ibA4q9iX (deleted)
mysqld 12916 mysql 12u REG 8,5 0 23137684 /tmp/ibRdXEl4 (deleted)
mysqld 12916 mysql 13u REG 8,5 0 23137685 /tmp/ibe6hfHJ (deleted)
mysqld 12916 mysql 19u REG 8,5 0 23137686 /tmp/ibfb7rps (deleted)
mysqld 12916 12920 mysql 10u REG 8,5 9765 17109405 /tmp/ibpuzts2 (deleted)
mysqld 12916 12920 mysql 11u REG 8,5 0 23137683 /tmp/ibA4q9iX (deleted)
mysqld 12916 12920 mysql 12u REG 8,5 0 23137684 /tmp/ibRdXEl4 (deleted)
mysqld 12916 12920 mysql 13u REG 8,5 0 23137685 /tmp/ibe6hfHJ (deleted)
mysqld 12916 12920 mysql 19u REG 8,5 0 23137686 /tmp/ibfb7rps (deleted)
mysqld 12916 12944 mysql 10u REG 8,5 9765 17109405 /tmp/ibpuzts2 (deleted)
mysqld 12916 12944 mysql 11u REG 8,5 0 23137683 /tmp/ibA4q9iX (deleted)
mysqld 12916 12944 mysql 12u REG 8,5 0 23137684 /tmp/ibRdXEl4 (deleted)
mysqld 12916 12944 mysql 13u REG 8,5 0 23137685 /tmp/ibe6hfHJ (deleted)
mysqld 12916 12944 mysql 19u REG 8,5 0 23137686 /tmp/ibfb7rps (deleted)
mysqld 12916 12945 mysql 10u REG 8,5 9765 17109405 /tmp/ibpuzts2 (deleted)
mysqld 12916 12945 mysql 11u REG 8,5 0 23137683 /tmp/ibA4q9iX (deleted)
mysqld 12916 12945 mysql 12u REG 8,5 0 23137684 /tmp/ibRdXEl4 (deleted)
此处省略....
我们主要关注以下几列:
- PID: is the Process IDentification number of the process.
- TID: is the task (thread) IDentification number
- FD: is the File Descriptor number of the file
- SIZE/OFF:is the size of the file or the file offset in bytes
- NAME:is the name of the mount point and file system on which the file resides
更加详细的自行参考man。
从输出中我们可以发现
- PID都是12916这正是MySQLD的PID,而它们的TID则不同,这些当然就是多线程照成的原因了。
- FD和NAME实际上是有规律的重复的,其实只有5个值而已。这代表我们上面说的5个临时文件
- SIZE都比较小。
因此我们可以认为虽然输出多达215行,但是实际上整个MySQLD进程只打开了5个文件而已也就是我们前面说的那5个临时文件,这是因为线程间文件描述符(FD)是共享的,每一个线程lsof查看的时候都会显示这5个临时文件,如果我们的MySQL有很多session,那么线程会很多很多,那么lsof看到的临时文件数量就是线程数据量*5。因此我们在检查临时文件使用空间情况的时候不要被过多的输出而吓到,我们只要输出MySQLD进程的临时文件即可,输出如下:
[root@mgr2 proc]# lsof|grep delete|grep mysql |awk '{if ($3=="mysql") print}'
mysqld 12916 mysql 10u REG 8,5 9765 17109405 /tmp/ibpuzts2 (deleted)
mysqld 12916 mysql 11u REG 8,5 0 23137683 /tmp/ibA4q9iX (deleted)
mysqld 12916 mysql 12u REG 8,5 0 23137684 /tmp/ibRdXEl4 (deleted)
mysqld 12916 mysql 13u REG 8,5 0 23137685 /tmp/ibe6hfHJ (deleted)
mysqld 12916 mysql 19u REG 8,5 0 23137686 /tmp/ibfb7rps (deleted)
或者加上lsof加上参数只看进程的临时文件,而不去查看子线程的临时文件
[root@mgr2 ~]#lsof -p 12916|grep delete
mysqld 12916 mysql 10u REG 8,5 9765 17109405 /tmp/ibpuzts2 (deleted)
mysqld 12916 mysql 11u REG 8,5 0 23137683 /tmp/ibA4q9iX (deleted)
mysqld 12916 mysql 12u REG 8,5 0 23137684 /tmp/ibRdXEl4 (deleted)
mysqld 12916 mysql 13u REG 8,5 0 23137685 /tmp/ibe6hfHJ (deleted)
mysqld 12916 mysql 19u REG 8,5 0 23137686 /tmp/ibfb7rps (deleted)
注意MySQL8.0.21下这些临时文件的名字有一些变化,Liunx下可能直接(O_TMPFILE flag)使用这种方式建立如下:
open(dirname_buf, O_RDWR | O_TMPFILE | O_CLOEXEC,
S_IRUSR | S_IWUSR)
我测试得到的名字如下:
[root@mgr4 ~]# lsof|grep a.out|grep delete
a.out 11703 root 3u REG 8,5 0 24237415 /tmp/#24237415 (deleted)
MySQLD启动后查看的临时文件名如下:
[root@mgr4 ~]# lsof -p 11488|grep delete
mysqld 11488 mysql 10u REG 8,5 0 24237413 /tmp/#24237413 (deleted)
mysqld 11488 mysql 11u REG 8,5 0 24237414 /tmp/#24237414 (deleted)
mysqld 11488 mysql 12u REG 8,5 0 24237416 /tmp/#24237416 (deleted)
mysqld 11488 mysql 19u REG 8,5 0 24237417 /tmp/#24237417 (deleted)
虽然临时文件名有所变化,但是基本的用途和5.7差不多
四、线程间的文件描述符(FD)是共享的
这一段没什么好解释的借用Linux系统编程的一段说明如下:
image.png
五、测试
我们可以写一段简单的多线程的代码来测试如下(不做任何错误判断):
#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
void* u_sleep(void* t)
{
char file_temp[]="ibXXXXXX";
int fd = mkstemp(file_temp);
unlink( file_temp);
int i = 0;
char* teststr="aasd";
printf("thead tmpfile: %s\n",file_temp);
for(i = 0;i<100000;i++)
{
write(fd,teststr,strlen(teststr));
}
sleep(100);
}
int main(void)
{
int ret = 0;
pthread_t tid[5];
int i = 0;
int fd = 0;
int tid_num = 0;
int tmp_file_num=5;
char file_temp[]="ibXXXXXX";
for(i=0;i<tmp_file_num;i++)
{
strcpy(file_temp,"ibXXXXXX");
mkstemp(file_temp);
printf("%s\n",file_temp);
unlink( file_temp);
}
for (i = 0;i<sizeof(tid)/sizeof(pthread_t);i++)
{
pthread_create(tid+tid_num,NULL,u_sleep,NULL);
tid_num++;
}
for(i = 0;i<sizeof(tid)/sizeof(pthread_t);i++)
{
ret = pthread_join( *(tid+i) , NULL );
}
}
这段代码实际上就是模拟在主进程中通过mkstemp和unlink建立了5个临时文件且也是以ib打头(模拟MySQL的临时文件),然后建立了5个线程,每个线程再各自建立一个临时文件,写点东西进去,然后线程睡眠一会,主线程会等待线程回收资源,因此可以有足够的时间观察到。这样来观察是线程之间文件描述符(FD)是否共享,预期我们能够观察到的输出为60个(1个主控线程,5个子线程,主控线程建立了5个临时文件6个线程共享就是30个,然后每个子线程建立了1个临时文件又是5个临时文件,6个线程共享又是30个)如下输出:
[root@mgr2 ~]# lsof|grep delete|grep a.out|wc -l
60
[root@mgr2 ~]# lsof|grep delete|grep a.out|awk '{if ($3=="root") print}'
a.out 13460 root 3u REG 8,5 0 43691141 /root/ibpotqYK (deleted)
a.out 13460 root 4u REG 8,5 0 43691142 /root/ibxlgopk (deleted)
a.out 13460 root 5u REG 8,5 0 43691144 /root/ibHOmmQT (deleted)
a.out 13460 root 6u REG 8,5 0 43691145 /root/ibvmykht (deleted)
a.out 13460 root 7u REG 8,5 0 43691146 /root/ib3TViI2 (deleted)
a.out 13460 root 8u REG 8,5 400000 43691147 /root/ibEn9hAb (deleted)
a.out 13460 root 9u REG 8,5 400000 43691148 /root/ibkexi9B (deleted)
a.out 13460 root 10u REG 8,5 400000 43691149 /root/ibJJZi1K (deleted)
a.out 13460 root 11u REG 8,5 400000 43691150 /root/ibRRxKtk (deleted)
a.out 13460 root 12u REG 8,5 400000 43691151 /root/ibWuKsWT (deleted)
[root@mgr2 ~]# lsof|grep delete|grep a.out|more
a.out 13460 root 3u REG 8,5 0 43691141 /root/ibpotqYK (deleted)
a.out 13460 root 4u REG 8,5 0 43691142 /root/ibxlgopk (deleted)
a.out 13460 root 5u REG 8,5 0 43691144 /root/ibHOmmQT (deleted)
a.out 13460 root 6u REG 8,5 0 43691145 /root/ibvmykht (deleted)
a.out 13460 root 7u REG 8,5 0 43691146 /root/ib3TViI2 (deleted)
a.out 13460 root 8u REG 8,5 400000 43691147 /root/ibEn9hAb (deleted)
a.out 13460 root 9u REG 8,5 400000 43691148 /root/ibkexi9B (deleted)
a.out 13460 root 10u REG 8,5 400000 43691149 /root/ibJJZi1K (deleted)
a.out 13460 root 11u REG 8,5 400000 43691150 /root/ibRRxKtk (deleted)
a.out 13460 root 12u REG 8,5 400000 43691151 /root/ibWuKsWT (deleted)
a.out 13460 13461 root 3u REG 8,5 0 43691141 /root/ibpotqYK (deleted)
a.out 13460 13461 root 4u REG 8,5 0 43691142 /root/ibxlgopk (deleted)
a.out 13460 13461 root 5u REG 8,5 0 43691144 /root/ibHOmmQT (deleted)
a.out 13460 13461 root 6u REG 8,5 0 43691145 /root/ibvmykht (deleted)
a.out 13460 13461 root 7u REG 8,5 0 43691146 /root/ib3TViI2 (deleted)
a.out 13460 13461 root 8u REG 8,5 400000 43691147 /root/ibEn9hAb (deleted)
a.out 13460 13461 root 9u REG 8,5 400000 43691148 /root/ibkexi9B (deleted)
a.out 13460 13461 root 10u REG 8,5 400000 43691149 /root/ibJJZi1K (deleted)
a.out 13460 13461 root 11u REG 8,5 400000 43691150 /root/ibRRxKtk (deleted)
a.out 13460 13461 root 12u REG 8,5 400000 43691151 /root/ibWuKsWT (deleted)
省略很多.....
因此我们的说法得到证明。
网友评论