概述
术语
模型
方法:性能分析的方法===观察法和实验法
工具:静态和动态工具
调优
概述
文件系统性能比磁盘性能更重要
文件系统通过缓存、缓冲以及异步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
......