文件系统笔记

概述
术语
模型
方法:性能分析的方法===观察法和实验法
工具:静态和动态工具
调优

概述
    文件系统性能比磁盘性能更重要
    文件系统通过缓存、缓冲以及异步IO等手段来缓和磁盘(或者远程系统)的延时对应用程序的影响。    
术语:
    文件系统:
        一种把数据组织成文件和目录的存储方式,提供了基于文件的存取接口,并通过文件权限控制访问。
        还包括一些表示设备、套接字和管道的特殊文件类型
        以及包含文件访问时间戳的元数据。
    文件系统缓存:
        主存(通常是DRAM)的一块区域,用来缓存文件系统的内容,可能包含各种数据和元数据
    操作:文件系统的操作是对文件系统的请求,包括
        read()
        write()
        open()
        close()
        stat()
        mkdir()
        以及其他操作。
    I/O:输入/输出。
        文件系统I/O有好几种定义,这里仅仅指直接读写(执行I/O)的操作,包括
            read()
            write()
            stat()(读的统计信息)
            mkdir() (创建一个新的目录项)。
            
        注意:不包括open()和close()。
    逻辑I/O:由应用程序发给文件系统的IO.
    物理I/O:由文件系统直接发给磁盘的I/O(或者通过裸IO)。
    吞吐量:当前应用程序和文件系统之间的数据传输率,单位是B/s。
    inode:一个索引节点( inode )是一种含有文件系统对象元数据的数据结构,其中有访问权限、时间戳以及数据指针。
    VFS:虚拟文件系统,一个为了抽象与支持不同文件系统类型的内核接口。
        在Solaris上,一个VFS inode被称为一个vnode。
    卷管理器:灵活管理物理存储设备的软件,在设备上创建虚拟卷供操作系统使用。
    
    fsck
    IOPS
    操作率(Operate Rate)
    POSIX
模型                    
                逻辑操作        【文件系统】        物理
        【应用程序】 ------->    read()    ------->【磁盘】        
               <------        write() <------    
                            open()
                            ......
                        ========================    
        【系统工具】            mount()
                        unmount()
                        sync()
                        ......
                        
    读操作从缓存返回(缓存命中)或者从磁盘返回(缓存未命中)。
    未命中的操作被存储在,缓存中,并填充缓存(热身)。
    
    文件系统缓存可能也用来缓冲写操作,使之延时写入(刷新)。
    
    二级缓存:二级缓存可能是各种存储介质
        | 一级缓存(RAM)
        | 二级缓存:
        ↓ 高密度磁盘
        
概念:
    文件系统延时
    缓存
    随机IO与顺序IO
        文件系统逻辑IO,按照每个IO的文件偏移量,可以分为随机IO与顺序IO
            顺序IO:每个IO都开始于上一个I/O结束的地址。
            随机IO:找不出IO之间的关系,偏移量随机变化。
        
        文件系统尽可能在磁盘上顺序和连续地存放文件数据,以努力减小随机IO的数目。
        当文件系统未能达成这个目标时,文件的摆放变得杂乱无章,顺序的逻辑I/O被分解成随机的物理I/O,我们称为碎片化。
    预取:
        通过检查当前和上一个10的文件偏移量,可以检测出当前是否是顺序读负载,并且做出预测,在应用程序请求前向磁盘发出读命令,以填充文件系统缓存。
        如果应用程序真的发出了读请求,就会命中缓存(需要的数据已经在缓存里)。过程通常如下:
            1. 一个应用程序对某个文件调用read (),把控制权交给内核。
            2, 文件系统发起磁盘读操作。
            3, 将上一次文件偏移量指针和当前地址进行比对,如果发现是顺序的,文件系统就会发起额外的读请求。
            4, 第一次的读取结束返回,内核把数据和控制权交还给应用程序。
            5, 额外的读请求也结束返回,并填进缓存,以备将来应用程序的读取。
    预读:
        预取一直也被认为是预读。
        最近, Linux采用了“预读”这个词作为一个系统调用,readahead(2),允许应用程序显式地预热文件系统缓存。
    写回缓存:
        写回缓存原理是
            当数据写入主存后,就认为写入已经结束并返回,之后再异步地把数据刷入磁盘。
            文件系统写入“脏”数据的过程称为刷新( flushing )。
                1, 应用程序发起一个文件的write()请求,把控制权交给内核。
                2, 数据从应用程序地址空间复制到内核空间。
                3. write ()系统调用被内核视为已经结束,并把控制权交还给应用程序。
                4,一段时间后,一个异步的内核任务定位到要写入的数据,并发起磁盘的写请求。这期间牺牲了可靠性。
                
                基于DRAM的主存是不可靠的, “脏”数据会在断电的情况下丢失,而应用程序却认为写入已经完成。并且,数据可能被非完整写入,这样磁盘上的数据就是在一种破坏( corrunted)的状态.
                如果文件系统的元数据遭到破坏,那可能无法加载。到了这一步,只能从系统备份中还原,造成长时间的宕机。
架构
    文件系统IO栈===参见图
    
    
    文件系统
    文件系统缓存
    
    
    文件系统特性:
        块和区段
            基于块的文件系统把数据存储在固定大小的块里,被存储在元数据块里的指针所引用。
            对于大文件,这种方法需要大量的块指针和元数据块,而且数据块的摆放可能会变得零零碎碎,造成随机IO,
            解决办法:
                1. 尝试通过把块连续摆放=======连续的内存块存放?
                2. 使用变长的块大小,随着文件的增长采用更大的数据块,也能减小元数据的开销。
        日志
        写时复制:
            写时复制的文件系统从不覆写当前使用中的块,而是按照以下步骤完成写入:
                1. 把数据写到一个新块(新的拷贝)。
                2. 更新引用指向新块。
                3. 把老块放到空闲链表中。在系统宕机时这能够有效地维护文件系统的完整性,并且通过把随机写变成连续写,改善了写入性能。
        擦洗
        
    文件系统种类
        FFS
        UFS
        ext3
        ext4
        ZFS
        btrfs
    卷和池
        通常文件系统建立在一块磁盘或者一个磁盘分区上。
        卷和池使文件系统可以建立在多块磁盘上,并可以使用不同的RAID策略
            卷把多块磁盘组合成一块虚拟磁盘,在此之上可以建立文件系统。
                在整块磁盘上建文件系充时(不是分片或者分区) ,卷能够隔离负载,降低竞争,缓和性能问题。· 
        卷管理软件包括
            Linux的逻辑卷管理器(Logical Volume Manager, LVM)
            Solaris卷管里器(SVM ) 。
        
            卷或虚拟磁盘可以由硬件RAID控制器提供。
            
        池存储把多块磁盘放到一个存储池里,池上可以建立多个文件系统。
            池存储比卷存储更灵活【池上可以建立多个文件系统】,文件系统可以增长或者缩小而不牵涉下面的设备。这种方法被现代文件系统采用,包括ZFS和btrfs.
            
方法
    磁盘分析
    延时分析
    负载特征归纳
    性能监控
    事件跟踪
    静态性能调优
    缓存调优
    负载分离
    内存文件系统
    微型基准测试
            
    建议按照以下顺序进行:
        1. 延时分析、
        2. 性能监控、
        3. 负载特征归纳
        4. 微型基准测试、
        5. 静态性能调优和事件跟踪。
        
    延时分析:
        文件系统延时分析的目标:
            应用程序===》系统调用接口===》VFS===》直接在文件系统上
            
            应用程序文档:有些应用程序已经提供了文件系统延时的指标,或者收集这些数据的方法。
            操作系统工具:操作系统可能也提供了延时指标,理想情况下能对每个文件系统或者应用程序提供单独的统计信息。
            动态跟踪:如果你的系统支持动态跟踪,那所有层都可以通过自定义的脚本进行检查,无须重启。
            延时关注
                单位时间平均值:如每秒平均读延时。
                全分布:如直方图或热图,
                单位操作延时:列出每个操作,注意:对于缓存命中率高(大于99%)的文件系统,单位时间平均值可能完全被缓存命中淹没。
    性能监控:
        操作频率
        操作延时
        
    系统负载归纳:
        需要归纳的几个基本属性:
            操作频率
            操作类型
            文件IO吞吐量
            文件IO大小
            读写比例
            同步写比例
            文件随机和连续访问比例
            
    磁盘分析:=========》先分析文件系统
        我们容易忽略文件系统而关注磁盘分析
        
        
    文件系统分析工具
        Linux                            Solaris            描述
        -                                vfsstat            文件系统统计信息,包括平均延时
        -                                fsstast            文件系统统计信息
        strace                            truss            系统调用调试器
        DTrace                            DTrace            动态跟踪文件系统操作和延时
        free                            -                缓存容量统计信息
        top                                top                包括内存使用概要
        vmstat                            vmstat            虚拟内存统计信息
        sar                                sar                多种统计信息,包括历史信息
        slabtop                            mdb::kmastat    内核slab分配器统计信息
        -                                fcachestat        各种缓存命中率和大小
        /proc/meminfo                    mdb::memsta     内存使用情况分解
        -                                kstat            内核各种文件系统和缓存统计信息
        
        【Solaris】
        ~]# vfsstat 1

        【Solaris】
        ~]# fsstat /var 1
        
        【Linux】strace  &&  【Solaris】truss=======会影响性能
            ~]# yum install strace
             CPU 主要消耗在内核态「sy」,而不是用户态「us」时,我们可以使用strace跟踪
            ~]# strace -h
                -tt在左侧打印出相对时间戳,时间确定到微秒级。还可以使用-ttt打印相对时间
                -T在右侧打印出系统调用时间。
                -p pid
                
            ~]# strace -ttT -p 845
                04:26:02.248463 wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG, NULL) = 25035 <0.000175>
                系统调用wait4,系统调用的时间0.000175s
                【注意】直接用 strace 跟踪某个进程的话,往往是满屏翻滚的字符,想从这里看出问题的症结并不是一件容易的事情,在 strace  可以按操作汇总时间
                ~]# strace -cp <PID>
                    -c 统计每一系统调用的所执行的时间,次数和出错的次数等. 
                    -p pid
                按下ctrl+c终止strace,输出统计结果
                ~]# strace -cp 24299
                strace: Process 24299 attached
                ^C^Cstrace: Process 24299 detached
                % time     seconds  usecs/call     calls    errors syscall
                ------ ----------- ----------- --------- --------- ----------------
                 93.63   41.537588       87447       475           wait4
                  6.10    2.705174       10246       264           clone
                  0.16    0.068979         139       495       290 select
                  0.04    0.018225          88       205           accept
                  0.04    0.017844          11      1612           rt_sigprocmask
                  0.01    0.006333          28       226           setsockopt
                  0.01    0.002606          12       208           close
                  0.01    0.002300           7       311       290 rt_sigreturn
                  0.00    0.001654           8       205           getsockname
                  0.00    0.000734          38        19           kill
                  0.00    0.000064          21         3           open
                  0.00    0.000042          14         3           read
                ------ ----------- ----------- --------- --------- ----------------
                100.00   44.361543                  4026       580 total
                
                我们能看到 CPU 主要被 wait4 操作消耗了,还可以单独跟踪一下 wait4:
                strace -T -e clone -p <PID>
                    -e 选项可以跟踪某个操作
                    ~]# strace -T -e wait4 -p 24299
                    strace: Process 24299 attached
                    --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=18523, si_uid=50008, si_status=0, si_utime=0, si_stime=0} ---
                    wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG, NULL) = 18523 <0.000341>
                    wait4(-1, 0x7fff1eb326f4, WNOHANG, NULL) = 0 <0.000099>
                    --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=18525, si_uid=50008, si_status=0, si_utime=0, si_stime=0} ---
                    wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG, NULL) = 18525 <0.000340>
                    wait4(-1, 0x7fff1eb326f4, WNOHANG, NULL) = 0 <0.000114>
                    ......
                    一个进程结束之后,就会变成僵尸进程,需要父进程替它收尸
                    1、如果其父进程在其死掉之前就已经死掉,则该进程就编程了孤儿进程,由init进程接管,死后也由init进程为其收尸 
                    2、如果父进程没有调用wait函数对子进程进行收尸,子进程死后也是变成了僵尸进程,最终在父进程死了之后由init进程为其收尸
                    
                    wait4会挂起当前进程,等待指定的子进程状态改变,并且会返回关于子进程使用资源的信息。所谓的状态的改变包括终止,挂起所有的进程状态的改变。
                    在linux中进程终止后不会释放其资源,它会进入一种僵死的状态,内核会为僵死态的进程保留最少的信息(进程标识,终止状态和资源使用信息).
                    而wait4就可以释放与子进程关联的资源。
                    
                另外,strace跟踪程序使用的底层系统调用,可输出系统调用被执行的时间点以及各个调用耗时;pstack工具对指定PID的进程输出函数调用栈。两者结合起来,方便定位程序问题
                1. 找到需要跟踪的进程id  ps -elf | grep keyword | grep -v grep
                2. strace跟踪程序
                    recvfrom server接收数据
                    sendto  将消息发出
                    确认慢的根源
                3. pstack查看函数堆栈
                    pstack是一个脚本工具,其核心实现就是使用了gdb以及thread apply all bt命令
                    从输出信息可以看出,函数调用关系
                    
                    ~]# git clone https://github.com/bangerlee/strace_pstack

                    ~]# sh pstack.sh 24299
                    #0  0x00007f12b3c63983 in __select_nocancel () from /lib64/libc.so.6
                    #1  0x0000000000468c4a in ServerLoop ()
                    #2  0x0000000000659d67 in PostmasterMain ()
                    #3  0x000000000046a21e in main ()
                    
                    函数调用关系为:main->PostmasterMain->ServerLoop->__select_nocancel,因而我们可以找到PostmasterMain函数进行分析和优化修改。

        【Linux】DTrace &&  【Solaris】DTrace
            DTrace能从系统调用接口、VFS接口,或者文件系统内部的角度来查看文件系统行为。用于负载特征归纳和延时分析。
            在安装dtrace-utils之前需要安装dtrace-modules(这个可以从公共yum上获取)==============好像支持的是Oracle Linux,不是Centos
            如果你使用的Oracle Linux,因为sun被Oracle收购后,Oracle Linux版本的DTrace可以直接在Oracle官网进行下载。
            下载地址
            http://www.oracle.com/technetwork/server-storage/linux/downloads/linux-dtrace-2800968.html
            安装方法
            http://docs.oracle.com/cd/E37670_01/E50705/html/ol_intro_dtrace.html
            使用方法
            http://docs.oracle.com/cd/E37670_01/E38608/html/dt_about.html


            ~]#  /usr/bin/dtrace --help
            Usage /usr/bin/dtrace [--help] [-h | -G] [-C [-I<Path>]] -s File.d [-o <File>]
                D语言中的变量是不需要预定义就可以直接使用的。但是在没有赋值之前,是不能出现在谓词中和赋值运算等号右侧。
                # dtrace -n 'BEGIN{a=1;exit(0);}END{printf("a=%d\\n",a);}'
                
            在Linux上通过syscall和fbt provider行观察【fsinfo provider没有提供】。
            ~]# dtrace -n 'fbt::vfs_*:entry { @[execname] = count();}' ============Centos7.9执行报错
                ('/usr/bin/dtrace', 'invalid option', '-n')
                Usage /usr/bin/dtrace [--help] [-h | -G] [-C [-I<Path>]] -s File.d [-o <File>]
                Linux上找到的dtrace不是Linux systemtap附带的dtrace,您可以在其他所有Linux发行版中找到它.
                相反,it is a port of Solaris dtrace由Oracle提供,仅在Oracle Linux上可用.
                标准的Linux内核跟踪工具称为systemtap
            安装bcc
                ~]# wget https://copr-be.cloud.fedoraproject.org/results/alonid/llvm-3.9.0/epel-7-x86_64/00505197-clang-3.9.0/clang-3.9.0-3.9.0-3.1.el7.centos.alonid.src.rpm
                ~]# rpm -ivh clang-3.9.0-3.9.0-3.1.el7.centos.alonid.src.rpm
                $ sudo yum install centos-release-scl
                $ sudo yum install llvm-toolset-7
                #Enable llvm-toolset-7:
                [root@k8s1 tools]# scl enable llvm-toolset-7 bash
                [root@k8s1 tools]# clang --version
                clang version 5.0.1 (tags/RELEASE_501/final)
                Target: x86_64-unknown-linux-gnu
                Thread model: posix
                InstalledDir: /opt/rh/llvm-toolset-7/root/usr/bin
                
                
                ~]# yum install bcc-tools
                这些工具默认会被安装到
                /usr/share/bcc/tools/
            
                解决:安装对应版本的kernel-devel-uname-r包
                         ~]# sudo yum install "kernel-devel-uname-r == $(uname -r)"
            安装bpftrace
                ~]# yum install bpftrace*
            安装完的路径在 
            /usr/share/bpftrace/tools/execsnoop.bt
            /usr/share/bcc/tools

            文件打开:opensnoop,统计open()系统调用信息
                ~]# /usr/share/bcc/tools/opensnoop -e
            
            【Solaris】DTrace
            ~]# dtrace -n 'fsinfo::: {@[execname] = count(); }'
                这个Solaris行命令使用了fsinfo (文件系统信息) provider,按应用程序名统计了文件系统操作
                操作类型可以按probename合计,而不仅是execname。例子如下:
                ~]# dtrace -n 'fsinfo::: /execname ="splunkd"/{ @[probename] = count(); }
        
        【Linux】sar
            sar系统活动报告器(system activity reporter),提供了各种文件系统统计信息,还可以配置以进行长期记录。
            ~]# sar -h
                -r,打印了分别代表缓冲区高速缓存大小和页缓存大小的kbbuffers和kbcached, 以KB为单位。
            每隔一段时间报告一次当前的活动:
            ~]# sar -v 1
            Linux 3.10.0-957.el7.x86_64 (pg2)       11/02/2021      _x86_64_        (24 CPU)

            03:16:58 AM dentunusd   file-nr  inode-nr    pty-nr
            03:16:59 AM    159653      3024     26548         6
            03:17:00 AM    159667      3120     26562         6
            ......
            dentunusd: 目录项缓存未用计数(可用项)。
            file-nr:使用中的文件描述符个数。
            inode-nx:使用中的inode个数。
            
            ~]# sar -rv 1
            Linux 3.10.0-957.el7.x86_64 (pg2)       11/02/2021      _x86_64_        (24 CPU)

            03:19:56 AM kbmemfree kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
            03:19:57 AM  27647692   5129700     15.65         0   3134540   6613184     20.18   2776600   1717932        92

        【Linux】slabtop
            Linux的slabtop (1)命令打印出有关内核slab缓存的信息,其中有些用于文件系统缓存
            ~]# slabtop -o
             Active / Total Objects (% used)    : 1405417 / 1833308 (76.7%)
             Active / Total Slabs (% used)      : 32898 / 32898 (100.0%)
             Active / Total Caches (% used)     : 71 / 97 (73.2%)
             Active / Total Size (% used)       : 202787.38K / 290018.62K (69.9%)
             Minimum / Average / Maximum Object : 0.01K / 0.16K / 8.00K

              OBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME
            316329 108592  34%    0.10K   8111       39     32444K buffer_head
            181120 176746  97%    0.03K   1415      128      5660K kmalloc-32
            180180 179903  99%    0.19K   4290       42     34320K dentry
            170496 168076  98%    0.01K    333      512      1332K kmalloc-8
            160310 159465  99%    0.02K    943      170      3772K fsnotify_mark_connector
            150784 147555  97%    0.02K    589      256      2356K kmalloc-16
            ......
            
            dentry:目录项缓存
            inode_cache: inode缓存。
            ext3inode_cache: ext3的inode缓存。
            ext4inode_cache: ext4的inode缓存。

        【Solaris】mdb:kmastat=====================了解即可
        Solaris内核内存分配器的详细统计信息,通过mdb -k里的::kmstat查看,其中还包括了文件系统使用的多种缓存
        
        【Solaris】fcachestat
            Solaris上的开源工具,调用了Perl的Sun::Solaris:Kstat库,打印出适合UFS缓存活动分析的统计信息
        
        【Solaris】mdb::memstat
            Solaris上mdb -k里的::memstat命令提供了Solaris内存使用的概况分解
        【Solaris】kstat
            kstat的统计数据可以通过以下途径获取:
                Perl的Sun:Solaris:Kstat库
                C的libkstat库
                kstat (1)命令
                
        【Linux】/proc/meminfo
            Linux的/proc/meminfo文件提供了内存使用状况的分解,如free (1)的一些工具也读这个文件
            ~]# cat /proc/meminfo
            MemTotal:       32777392 kB
            MemFree:        27632676 kB
            MemAvailable:   28298076 kB
            Buffers:               0 kB
            Cached:          3139316 kB
            SwapCached:            0 kB
            
            包括:
                缓冲区高速缓存(Buffers)
                页缓存(Cached) 
                并且提供了系统内存使用情况的其他概况分解

        

        【Linux】free    
            ~~]# free --help
                -m把结果以MB为单位进行显示。
                free (1)命令显示了内存和交换区的统计信息:
                buffers一列展示了缓冲区高速缓存的大小
                cached一列展示了页缓存大小
                
            ~]# free -m
                          total        used        free      shared  buff/cache   available
            Mem:          32009        2875         290        4143       28843       24416
            Swap:             0           0           0

        df (1) :报告文件系统使用情况和容量统计信息。
        mount (8) :显示文件系统挂载选项(静态性能调优)。
        inotify: Linux文件系统事件监控框架。
            
~]# cat /proc/sys/vm/drop_caches
0

释放page缓存
~]# echo 1 > /proc/sys/vm/drop_caches
释放dentries目录缓存和inodes缓存
~]# echo 2 > /proc/sys/vm/drop_caches
释放page缓存,dentries目录缓存和inodes缓存
~]# echo 3 > /proc/sys/vm/drop_caches

查看使用的文件系统
    ~]# df -h
    Filesystem                    Size  Used Avail Use% Mounted on
    devtmpfs                      7.8G     0  7.8G   0% /dev
    tmpfs                         7.8G     0  7.8G   0% /dev/shm
    ......

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值