美文网首页
MySQL:为什么lsof会看到这么多临时文件

MySQL:为什么lsof会看到这么多临时文件

作者: 重庆八怪 | 来源:发表于2020-09-12 23:35 被阅读0次

    版本: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)
    省略很多.....
    

    因此我们的说法得到证明。

    相关文章

      网友评论

          本文标题:MySQL:为什么lsof会看到这么多临时文件

          本文链接:https://www.haomeiwen.com/subject/pyxgektx.html