性能分析工具
top
线程的各种状态:
R 是 Running 或 Runnable 的缩写,表示进程在 CPU 的就绪队列中,正在运行或者正在等待运行。
D 是 Disk Sleep 的缩写,也就是不可中断状态睡眠(Uninterruptible Sleep),一般表示进程正在跟硬件交互,并且交互过程不允许被其他进程或中断打断。
Z 是 Zombie 的缩写,如果你玩过“植物大战僵尸”这款游戏,应该知道它的意思。它表示僵尸进程,也就是进程实际上已经结束了,但是父进程还没有回收它的资源(比如进程的描述符、PID 等)。
S 是 Interruptible Sleep 的缩写,也就是可中断状态睡眠,表示进程因为等待某个事件而被系统挂起。当进程等待的事件发生时,它会被唤醒并进入 R 状态。
I 是 Idle 的缩写,也就是空闲状态,用在不可中断睡眠的内核线程上。前面说了,硬件交互导致的不可中断进程用 D 表示,但对某些内核线程来说,它们有可能实际上并没有任何负载,用 Idle 正是为了区分这种情况。要注意,D 状态的进程会导致平均负载升高, I 状态的进程却不会。
T 或者 t,也就是 Stopped 或 Traced 的缩写,表示进程处于暂停或者跟踪状态。
X,也就是 Dead 的缩写,表示进程已经消亡,所以你不会在 top 或者 ps 命令中看到它。
+ 表示前台进程组
s 表示是一个会话的领导进程
pstree
用法:
# -a 表示输出命令行选项
# p 表 PID
# s 表示指定进程的父进程
$ pstree -aps 3084
systemd,1
└─dockerd,15006 -H fd://
└─docker-containe,15024 --config /var/run/docker/containerd/containerd.toml
└─docker-containe,3991 -namespace moby -workdir...
└─app,4009
└─(app,3084)
mpstat
用法:
mpstat -P ALL 5 # 查看所有CPU的使用情况
vmstat
用于查看系统中断和上下文切换此时,就绪队列的长度等信息
用法:
vmstat 5 # 每5秒输出一次
pidstat
pidstat -u -w -t 5 10 # 5秒输出一次,共输出10次;w:上下文切换次数 t:输出线程指标 d:进程的IO情况
# 查看IO情况
pidstat -d 1
13:39:51 UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command
13:39:52 102 916 0.00 4.00 0.00 0 rsyslogd
perf
用于查看每个函数或指令的CPU使用情况
用法:
perf top # 实时显示占用CPU最多的函数或指令
perf record # 保存数据用于离线分析
perf report # 分析离线数据
示例:
# -g 开启调用关系分析,-p 指定 php-fpm 的进程号 21515
$ perf top -g -p 21515
proc
cat /proc/interrupts # 查看内核中断
cat /proc/softirqs # 查看软中断
tcpdump
用法:
# -i eth0 只抓取 eth0 网卡,-n 不解析协议名和主机名
# tcp port 80 表示只抓取 tcp 协议并且端口号为 80 的网络帧
$ tcpdump -i eth0 -n tcp port 80
15:11:32.678966 IP 192.168.0.2.18238 > 192.168.0.30.80: Flags [S], seq 458303614, win 512, length 0
bcc工具箱
需安装bcc,并配置PATH路径:export PATH=$PATH:/usr/share/bcc/tools
,CentOS还需要手动升级内核版本到4.1以上后才能用,升级方法参考:https://www.jianshu.com/p/997e0a6d8e09,或者参考它的 Github 网站https://github.com/iovisor/bcc
cachestat
提供了整个操作系统缓存的读写命中情况
用法:
$ cachestat 1 3
TOTAL MISSES HITS DIRTIES BUFFERS_MB CACHED_MB
2 0 2 1 17 279
2 0 2 1 17 279
2 0 2 1 17 279
cachetop
提供了每个进程的缓存命中情况
用法:
$ cachetop
11:58:50 Buffers MB: 258 / Cached MB: 347 / Sort: HITS / Order: ascending
PID UID CMD HITS MISSES DIRTIES READ_HIT% WRITE_HIT%
13029 root python 1 0 0 100.0% 0.0%
memleak
用法:
$ /usr/share/bcc/tools/memleak -p $(pidof app) -a
Attaching to pid 12512, Ctrl+C to quit.
[03:00:41] Top 10 stacks with outstanding allocations:
addr = 7f8f70863220 size = 8192
addr = 7f8f70861210 size = 8192
addr = 7f8f7085b1e0 size = 8192
addr = 7f8f7085f200 size = 8192
addr = 7f8f7085d1f0 size = 8192
40960 bytes in 5 allocations from stack
fibonacci+0x1f [app]
child+0x4f [app]
start_thread+0xdb [libpthread-2.27.so]
filetop
跟踪内核文件的读写情况:
# 切换到工具目录
$ cd /usr/share/bcc/tools
# -C 选项表示输出新内容时不清空屏幕
$ ./filetop -C
TID COMM READS WRITES R_Kb W_Kb T FILE
514 python 0 1 0 2832 R 669.txt
514 python 0 1 0 2490 R 667.txt
514 python 0 1 0 2685 R 671.txt
514 python 0 1 0 2392 R 670.txt
514 python 0 1 0 2050 R 672.txt
...
TID COMM READS WRITES R_Kb W_Kb T FILE
514 python 2 0 5957 0 R 651.txt
514 python 2 0 5371 0 R 112.txt
514 python 2 0 4785 0 R 861.txt
514 python 2 0 4736 0 R 213.txt
514 python 2 0 4443 0 R 45.txt
opensnoop
跟踪内核中的open系统调用,找出打开文件的文件名和路径:
opensnoop
12280 python 6 0 /tmp/9046db9e-fe25-11e8-b13f-0242ac110002/650.txt
12280 python 6 0 /tmp/9046db9e-fe25-11e8-b13f-0242ac110002/651.txt
12280 python 6 0 /tmp/9046db9e-fe25-11e8-b13f-0242ac110002/652.txt
pcstat
查看指定文件在内存中的缓存大小
该工具基于go语言开发,需安装go环境:
$ export GOPATH=~/go
$ export PATH=~/go/bin:$PATH
$ go get golang.org/x/sys/unix
$ go get github.com/tobert/pcstat/pcstat
用法:
$ ls
$ pcstat /bin/ls
+---------+----------------+------------+-----------+---------+
| Name | Size (bytes) | Pages | Cached | Percent |
|---------+----------------+------------+-----------+---------|
| /bin/ls | 133792 | 33 | 33 | 100.000 |
+---------+----------------+------------+-----------+---------+
strace
查看进程的系统调用
用法:
# strace -p $(pgrep app) # -f:追踪多线程
strace: Process 4988 attached
restart_syscall(<\.\.\. resuming interrupted nanosleep \.\.\.>) = 0
openat(AT_FDCWD, "/dev/sdb1", O_RDONLY|O_DIRECT) = 4
mmap(NULL, 33558528, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f448d240000
read(4, "8vq\213\314\264u\373\4\336K\224\25@\371\1\252\2\262\252q\221\n0\30\225bD\252\266@J"\.\.\., 33554432) = 33554432
write(1, "Time used: 0.948897 s to read 33"\.\.\., 45) = 45
close(4) = 0
sar
sar 是一个系统活动报告工具,既可以实时查看系统的当前活动,又可以配置保存和报告历史统计数据。
用法:
# -n DEV 表示显示网络收发的报告,间隔 1 秒输出一组数据
$ sar -n DEV 1
15:03:46 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
15:03:47 eth0 12607.00 6304.00 664.86 358.11 0.00 0.00 0.00 0.01
15:03:47 docker0 6302.00 12604.00 270.79 664.66 0.00 0.00 0.00 0.00
15:03:47 lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
15:03:47 veth9f6bbcd 6302.00 12604.00 356.95 664.66 0.00 0.00 0.00 0.05
# 间隔 1 秒输出一组数据
# -r 表示显示内存使用情况,-S 表示显示 Swap 使用情况
$ sar -r -S 1
04:39:56 kbmemfree kbavail kbmemused %memused kbbuffers kbcached kbcommit %commit kbactive kbinact kbdirty
04:39:57 6249676 6839824 1919632 23.50 740512 67316 1691736 10.22 815156 841868 4
04:39:56 kbswpfree kbswpused %swpused kbswpcad %swpcad
04:39:57 8388604 0 0.00 0 0.00
04:39:57 kbmemfree kbavail kbmemused %memused kbbuffers kbcached kbcommit %commit kbactive kbinact kbdirty
04:39:58 6184472 6807064 1984836 24.30 772768 67380 1691736 10.22 847932 874224 20
04:39:57 kbswpfree kbswpused %swpused kbswpcad %swpcad
04:39:58 8388604 0 0.00 0 0.00
…
04:44:06 kbmemfree kbavail kbmemused %memused kbbuffers kbcached kbcommit %commit kbactive kbinact kbdirty
04:44:07 152780 6525716 8016528 98.13 6530440 51316 1691736 10.22 867124 6869332 0
04:44:06 kbswpfree kbswpused %swpused kbswpcad %swpcad
04:44:07 8384508 4096 0.05 52 1.27
iostat
查看每块盘的IO情况,查看每个进程的IO情况使用pidstat
用法:
# -d -x 表示显示所有磁盘 I/O 的指标
$ iostat -d -x 1
Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %rrqm %wrqm r_await w_await aqu-sz rareq-sz wareq-sz svctm %util
loop0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
loop1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sda 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdb 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
iotop
根据IO大小对进程进行排序,类似top
用法:
iotop
Total DISK READ : 0.00 B/s | Total DISK WRITE : 7.85 K/s
Actual DISK READ: 0.00 B/s | Actual DISK WRITE: 0.00 B/s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
15055 be/3 root 0.00 B/s 7.85 K/s 0.00 % 0.00 % systemd-journald
slabtop
查看缓存大小。
用法:
# 按下 c 按照缓存大小排序,按下 a 按照活跃对象数排序
$ slabtop
Active / Total Objects (% used) : 277970 / 358914 (77.4%)
Active / Total Slabs (% used) : 12414 / 12414 (100.0%)
Active / Total Caches (% used) : 83 / 135 (61.5%)
Active / Total Size (% used) : 57816.88K / 73307.70K (78.9%)
Minimum / Average / Maximum Object : 0.01K / 0.20K / 22.88K
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
69804 23094 0% 0.19K 3324 21 13296K dentry
16380 15854 0% 0.59K 1260 13 10080K inode_cache
58260 55397 0% 0.13K 1942 30 7768K kernfs_node_cache
485 413 0% 5.69K 97 5 3104K task_struct
1472 1397 0% 2.00K 92 16 2944K kmalloc-2048
lsof
查看进程打开了哪些文件:
lsof -p 18940
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
python 18940 root cwd DIR 0,50 4096 1549389 /
python 18940 root rtd DIR 0,50 4096 1549389 /
…
python 18940 root 2u CHR 136,0 0t0 3 /dev/pts/0
python 18940 root 3w REG 8,1 117944320 303 /tmp/logtest.txt
其中,FD 表示文件描述符号,TYPE 表示文件类型,NAME 表示文件路径。
压力测试工具
ad - HTTP性能压测工具
ab(apache bench)是一个常用的 HTTP 服务性能测试工具。
安装方法:
# Ubuntu
$ apt-get install -y apache2-utils
# CentOS
$ yum install -y httpd-tools
测试示例:
# -c 表示并发请求数为 1000,-n 表示总的请求数为 10000
$ ab -c 1000 -n 10000 http://192.168.0.30/
...
Server Software: nginx/1.15.8
Server Hostname: 192.168.0.30
Server Port: 80
...
Requests per second: 1078.54 [#/sec] (mean)
Time per request: 927.183 [ms] (mean)
Time per request: 0.927 [ms] (mean, across all concurrent requests)
Transfer rate: 890.00 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 27 152.1 1 1038
Processing: 9 207 843.0 22 9242
Waiting: 8 207 843.0 22 9242
Total: 15 233 857.7 23 9268
Percentage of the requests served within a certain time (ms)
50% 23
66% 24
75% 24
80% 26
90% 274
95% 1195
98% 2335
99% 4663
100% 9268 (longest request)
...
# Time per second:每个请求的延迟,分为两行,第一行表示平均延迟,包括了线程运行调度时间和网络请求响应时间,第二行表示实际请求的响应大小
# Transfer rate:表示吞吐量
hping3 - 网络包处理能力压测工具
hping3 是一个可以构造 TCP/IP 协议数据包的工具。
用法:
# -S 参数表示设置 TCP 协议的 SYN(同步序列号),-p 表示目的端口为 80
# -i u100 表示每隔 100 微秒发送一个网络帧
# 注:如果你在实践过程中现象不明显,可以尝试把 100 调小,比如调成 10 甚至 1
$ hping3 -S -p 80 -i u100 192.168.0.30
fio - IO压测工具
文件系统和磁盘IO基准测试工具。
安装:
# Ubuntu
apt-get install -y fio
# CentOS
yum install -y fio
用法:
# 随机读
fio -name=randread -direct=1 -iodepth=64 -rw=randread -ioengine=libaio -bs=4k -size=1G -numjobs=1 -runtime=1000 -group_reporting -filename=/dev/sdb
# 随机写
fio -name=randwrite -direct=1 -iodepth=64 -rw=randwrite -ioengine=libaio -bs=4k -size=1G -numjobs=1 -runtime=1000 -group_reporting -filename=/dev/sdb
# 顺序读
fio -name=read -direct=1 -iodepth=64 -rw=read -ioengine=libaio -bs=4k -size=1G -numjobs=1 -runtime=1000 -group_reporting -filename=/dev/sdb
# 顺序写
fio -name=write -direct=1 -iodepth=64 -rw=write -ioengine=libaio -bs=4k -size=1G -numjobs=1 -runtime=1000 -group_reporting -filename=/dev/sdb
各参数的意义:
- direct,表示是否跳过系统缓存。上面示例中,我设置的 1 ,就表示跳过系统缓存。
- iodepth,表示使用异步 I/O(asynchronous I/O,简称 AIO)时,同时发出的 I/O 请求上限。在上面的示例中,我设置的是 64。
- rw,表示 I/O 模式。我的示例中, read/write 分别表示顺序读 / 写,而 randread/randwrite 则分别表示随机读 / 写。
- ioengine,表示 I/O 引擎,它支持同步(sync)、异步(libaio)、内存映射(mmap)、网络(net)等各种 I/O 引擎。上面示例中,我设置的 libaio 表示使用异步 I/O。
- bs,表示 I/O 的大小。示例中,我设置成了 4K(这也是默认值)。
- filename,表示文件路径,当然,它可以是磁盘路径(测试磁盘性能),也可以是文件路径(测试文件系统性能)。示例中,我把它设置成了磁盘 /dev/sdb。不过注意,用磁盘路径测试写,会破坏这个磁盘中的文件系统,所以在使用前,你一定要事先做好数据备份。
报告示例:
read: (g=0): rw=read, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=64
fio-3.1
Starting 1 process
Jobs: 1 (f=1): [R(1)][100.0%][r=16.7MiB/s,w=0KiB/s][r=4280,w=0 IOPS][eta 00m:00s]
read: (groupid=0, jobs=1): err= 0: pid=17966: Sun Dec 30 08:31:48 2018
read: IOPS=4257, BW=16.6MiB/s (17.4MB/s)(1024MiB/61568msec)
slat (usec): min=2, max=2566, avg= 4.29, stdev=21.76
clat (usec): min=228, max=407360, avg=15024.30, stdev=20524.39
lat (usec): min=243, max=407363, avg=15029.12, stdev=20524.26
clat percentiles (usec):
| 1.00th=[ 498], 5.00th=[ 1020], 10.00th=[ 1319], 20.00th=[ 1713],
| 30.00th=[ 1991], 40.00th=[ 2212], 50.00th=[ 2540], 60.00th=[ 2933],
| 70.00th=[ 5407], 80.00th=[ 44303], 90.00th=[ 45351], 95.00th=[ 45876],
| 99.00th=[ 46924], 99.50th=[ 46924], 99.90th=[ 48497], 99.95th=[ 49021],
| 99.99th=[404751]
bw ( KiB/s): min= 8208, max=18832, per=99.85%, avg=17005.35, stdev=998.94, samples=123
iops : min= 2052, max= 4708, avg=4251.30, stdev=249.74, samples=123
lat (usec) : 250=0.01%, 500=1.03%, 750=1.69%, 1000=2.07%
lat (msec) : 2=25.64%, 4=37.58%, 10=2.08%, 20=0.02%, 50=29.86%
lat (msec) : 100=0.01%, 500=0.02%
cpu : usr=1.02%, sys=2.97%, ctx=33312, majf=0, minf=75
IO depths : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=0.1%, >=64=100.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.1%, >=64=0.0%
issued rwt: total=262144,0,0, short=0,0,0, dropped=0,0,0
latency : target=0, window=0, percentile=100.00%, depth=64
Run status group 0 (all jobs):
READ: bw=16.6MiB/s (17.4MB/s), 16.6MiB/s-16.6MiB/s (17.4MB/s-17.4MB/s), io=1024MiB (1074MB), run=61568-61568msec
Disk stats (read/write):
sdb: ios=261897/0, merge=0/0, ticks=3912108/0, in_queue=3474336, util=90.09%
重点的几项:
slat ,是指从 I/O 提交到实际执行 I/O 的时长(Submission latency);
clat ,是指从 I/O 提交到 I/O 完成的时长(Completion latency);
lat ,指的是从 fio 创建 I/O 到 I/O 完成的总时长
bw,吞吐量
精确模拟应用程序IO模式:
# 使用 blktrace 跟踪磁盘 I/O,注意指定应用程序正在操作的磁盘
$ blktrace /dev/sdb
# 查看 blktrace 记录的结果
# ls
sdb.blktrace.0 sdb.blktrace.1
# 将结果转化为二进制文件
$ blkparse sdb -d sdb.bin
# 使用 fio 重放日志
$ fio --name=replay --filename=/dev/sdb --direct=1 --read_iolog=sdb.bin
pktgen - 网络性能压测工具
用于测试网络性能(PPS,吞吐量),pktgen是作为一个内核线程来运行的,需要加载pktgen内核模块,再通过/proc文件系统来交互。
启动pktgen:
$ modprobe pktgen
$ ps -ef | grep pktgen | grep -v grep
root 26384 2 0 06:17 ? 00:00:00 [kpktgend_0]
root 26385 2 0 06:17 ? 00:00:00 [kpktgend_1]
$ ls /proc/net/pktgen/
kpktgend_0 kpktgend_1 pgctrl
测试示例:
# 定义一个工具函数,方便后面配置各种测试选项
function pgset() {
local result
echo $1 > $PGDEV
result=`cat $PGDEV | fgrep "Result: OK:"`
if [ "$result" = "" ]; then
cat $PGDEV | fgrep Result:
fi
}
# 为 0 号线程绑定 eth0 网卡
PGDEV=/proc/net/pktgen/kpktgend_0
pgset "rem_device_all" # 清空网卡绑定
pgset "add_device eth0" # 添加 eth0 网卡
# 配置 eth0 网卡的测试选项
PGDEV=/proc/net/pktgen/eth0
pgset "count 1000000" # 总发包数量
pgset "delay 5000" # 不同包之间的发送延迟 (单位纳秒)
pgset "clone_skb 0" # SKB 包复制
pgset "pkt_size 64" # 网络包大小
pgset "dst 192.168.0.30" # 目的 IP
pgset "dst_mac 11:11:11:11:11:11" # 目的 MAC
# 启动测试
PGDEV=/proc/net/pktgen/pgctrl
pgset "start"
测试报告示例:
$ cat /proc/net/pktgen/eth0
Params: count 1000000 min_pkt_size: 64 max_pkt_size: 64
frags: 0 delay: 0 clone_skb: 0 ifname: eth0
flows: 0 flowlen: 0
...
Current:
pkts-sofar: 1000000 errors: 0
started: 1534853256071us stopped: 1534861576098us idle: 70673us
...
Result: OK: 8320027(c8249354+d70673) usec, 1000000 (64byte,0frags)
120191pps 61Mb/sec (61537792bps) errors: 0
# Params是测试选项
# Current是测试进度,pkts-sofar(packets so far)表示已经发生了100万个包
# Result是测试结果,包含测试所用时间、网络包数量和分片、PPS、吞吐量以及错误数
iperf - TCP/UDP吞吐量压测工具
以客户端和服务器通信的方式,测试一段时间内的平均吞吐量。
使用方法:
# Ubuntu
apt-get install iperf3
# CentOS
yum install iperf3
# 在服务器端启动
# -s 表示启动服务端,-i 表示汇报间隔,-p 表示监听端口
$ iperf3 -s -i 1 -p 10000
# 在客户端启动
# -c 表示启动客户端,192.168.0.30 为目标服务器的 IP
# -b 表示目标带宽 (单位是 bits/s)
# -t 表示测试时间
# -P 表示并发数,-p 表示目标服务器监听端口
$ iperf3 -c 192.168.0.30 -b 1G -t 15 -P 2 -p 10000
测试报告实例:
[ ID] Interval Transfer Bandwidth
...
[SUM] 0.00-15.04 sec 0.00 Bytes 0.00 bits/sec sender
[SUM] 0.00-15.04 sec 1.51 GBytes 860 Mbits/sec receiver
# SUM行表示测试的汇总结果,包括测试时间、数据传输量和带宽(吞吐量)
系统知识
内存
- Buffer是对磁盘数据的缓存,Cache是对文件数据的缓存
- 在读写普通文件时,会经过文件系统,由文件系统负责与磁盘交互;而读写磁盘或者分区时,就会跳过文件系统,也就是所谓的“裸I/O“。这两种读写方式所使用的缓存是不同的,也就是的Cache 和 Buffer 区别
- 降低 Swap 的使用,可以提高系统的整体性能
- 绝大部分 Java 的应用都建议关 swap,这个和 JVM 的 gc 有关,它在 gc 的时候会遍历所有用到的堆的内存,如果这部分内存是被 swap 出去了,遍历的时候就会有磁盘IO,参考文章:文章1 文章2
配置swap文件操作
# 创建 Swap 文件
$ fallocate -l 8G /mnt/swapfile
# 修改权限只有根用户可以访问
$ chmod 600 /mnt/swapfile
# 配置 Swap 文件
$ mkswap /mnt/swapfile
# 开启 Swap
$ swapon /mnt/swapfile
# 关闭swap
swapoff -a
# 清理swap空间
swapoff -a && swapon -a
查看内存回收偏好
取值区间为0-100,数值越大,越积极使用 Swap,也就是更倾向于回收匿名页;数值越小,越消极使用 Swap,也就是更倾向于回收文件页。
cat /proc/sys/vm/swappiness
60
查看使用Swap最多的进程
# 按 VmSwap 使用量对进程排序,输出进程名称、进程 ID 以及 SWAP 用量
$ for file in /proc/*/status ; do awk '/VmSwap|Name|^Pid/{printf $2 " " $3}END{ print ""}' $file; done | sort -k 3 -n -r | head
dockerd 2226 10728 kB
docker-containe 2251 8516 kB
snapd 936 4020 kB
networkd-dispat 911 836 kB
polkitd 1004 44 kB
磁盘
文件系统
索引节点和目录项
- 文件系统,本身是对存储设备上的文件进行组织管理的机制。组织方式不同,就会形成不同的文件系统
- Linux文件系统为每个文件分配两个数据结构,索引节点(index node)和目录项(directory entry)。
- 索引节点:简称inode,用来记录文件的元数据,比如inode编号、文件大小、访问权限、修改日期、数据的位置等等。索引节点和文件一一对应,并且存储在磁盘中,占用磁盘空间。
- 目录项:简称dentry,用来记录文件的名字、索引节点指针以及其他目录项的关联关系,多个关联的目录项,就构成了文件系统的目录结构。目录项是由内核维护的一个内存数据结构,所以通常也被叫做目录项缓存,通过磁盘中的数据构建(会根据需要动态构建)。目录项维护的是系统的树状结构。
- 索引节点的容量(即inode的个数),是在格式化磁盘时设定好的,一般由格式化工具自动生成。
- 目录项和索引节点是多对一关系,为一个文件创建一个硬链接会创建一个目录项,但不会创建索引节点
- 磁盘读写的最小单位是512B,为了提高效率,文件系统把连续的扇区组成逻辑块作为最小单元来管理,常见的逻辑块大小为4KB,也就是8个扇区。
- 磁盘在文件系统执行格式化时,会被分成3个存储区:超级块、索引节点区和超级块区
- 超级块:存储整个文件系统的状态
- 索引节点区:存储索引节点
- 数据块区:存储文件数据
- 索引节点、目录项和磁盘的关系如下图:
虚拟文件系统
- 目录项、索引节点、超级块和逻辑块构成了Linux文件系统的四大基本要素。
- 文件系统类型包括:基于磁盘的文件系统(Ext4、XFS、OverlayFS 等)、基于内存的文件系统(/proc、/sys等)以及基于网络的文件系统(NFS、SMB、iSCSI等)
- 为了支持不同类型的文件系统,Liunx内核在用户程序和文件系统之间,引入了一个抽象层,也就是虚拟文件系统VFS(Virtual File System)。
- 所有的文件系统都要先挂载到VFS的某个子目录(挂载点)下,才能访问其中的文件。
- Linux文件系统架构图:
文件系统I/O
- 缓冲I/O与非缓冲I/O:利用标准库缓存来加速文件访问,而标准库内部再通过系统调用访问文件。如很多程序遇到换行时才真正输出,换行前的内容就是被标准库暂时缓存起来的;非缓冲IO则直接通过系统调用来访问文件。
- 直接I/O与非直接IO:非直接IO在进行文件读写时,先要经过系统的页缓存,再由内核或额外的系统调用真正写入到磁盘中;直接IO则直接跟文件系统交互来访问文件。
- 裸IO:跳过文件系统,直接写磁盘。
- 阻塞/非阻塞和同步/异步IO的描述对象不同,阻塞/非阻塞针对的是IO调用者(即应用程序),同步/异步针对的是IO执行者(系统调用)
- 对于机械磁盘和固态磁盘来说,连续IO都要比随机IO快很多,对于机械磁盘来说,随机IO需要更多的磁头寻道和盘片旋转,固态磁盘也需要先擦除再写入。另外,连续IO还可以通过预读的方式来减少IO次数。
- MySql的MyISAM引擎本身只缓存索引,并不缓存数据,需要依赖系统缓存来加速磁盘IO的访问,但系统缓存并不可靠。应用程序的性能优化并不应该完全建立在系统缓存上,最后能在应用程序的内部分配内存,构建完全自主控制的缓存,MySql的InnoDB引擎就同时缓存了索引和数据;也可以利用第三方缓存应用,比如Memcached,Redis等
磁盘IO
磁盘类型
- 机械磁盘的最小读写单位是扇区,一般大小是512B
- 固态磁盘的最小读写单位是页,一般大小是4KB、8KB等
- 不同接口的磁盘设备,一般会被分配不同的名称前缀,比如IDE接口的设备前缀是hd,SCSI和SATA接口的设备的前缀是sd。
- 把多块磁盘组成一个逻辑磁盘可以构成冗余独立磁盘阵列(RAID)。RAID0具有最优的读写性能,但不提供数据冗余功能,而其它级别的RAID,在提供数据冗余的基础上,对读写性能也有一定优化。
- 在Linux中,磁盘实际上是作为一个块设备来管理的,也就是以块为单位读写数据。
通用块层
- 通用块层是处在文件系统和磁盘驱动之间的一个块设备抽象层,是Linux磁盘IO的核心。
- 通用块层向上文件系统和应用程序提供了块设备的标准接口,向下,把各种异构的块设备抽象为统一的块设备,并提供统一的框架来管理这些设备的驱动程序。通用块层还会给文件系统和应用程序发来的IO请求排队,并通过重新排序、请求合并等方式,提供磁盘读写的效率。
- 对IO请求的排序过程,就是我们熟悉的IO调度算法。Linux内核支持4中IO调度算法,分别是:NONE(常用语虚拟机),NOOP,CFQ(许多发行版默认的调度算法),DeadLine。
磁盘性能指标
- 五个基本指标:
- 使用率:磁盘处理IO的时间百分比。
- 饱和度:磁盘处理IO的繁忙程度。
- IOPS:每秒的IO请求数。
- 吞吐量:每秒的IO请求大小。
- 响应时间:IO请求从发出到收到响应的时间。
- 在数据库、大量小文件等这类随机读写比较多的场景中,IOPS更能反映系统的整体性能;而在多媒体等顺序读写较多的场景中,吞吐量才更能反映系统的整体性能。
- 性能测试工具推荐fio。
- 性能测试需要测试出不同IO大小(一般为512B~1M的若干中间值)分别在随机读、顺序读、随机写和顺序写等各种情况下的性能情况。
网络
性能指标
- 带宽:表示链路的最大传输率,单位是b/s
- 吞吐量:表示单位时间内成功传输的数据量,单位通常为b/s或B/s。吞吐量/带宽=网络使用率
- 延时:网络请求发出后,一直到收到远端响应,所需要的时间延迟
- PPS:Packet Per Second,表示以网络包为单位的传输速率,通常用来评估网络的转发能力,比如硬件交换机,通常可以接近理论最大值,而Linux服务器的转发,则容易受网络包大小的影响。千兆交换机的PPS可以达到150万PPS
- 网络可用性、并发连接数(TCP连接数量)、丢包率、重传率也是常用的性能指标
网络配置
网络接口状态
- ifconfig或ip命令可以用来查看接口状态
- ifconfig的RUNNING或ip的LOWER_UP表示物理网络是连通的,即网卡已经连接到了交换机或路由器中,否则通常表示网线被拔掉了
- TX和RX的各个指标
- errors:表示发生错误的数据包数,比如校验错误、帧同步错误等
- dropped:表示丢弃的数据包数,即数据包已经收到了Ring Buffer,但因为内存不足等原因丢包
- overruns:表示超限数据包数,即网络IO速度过快,导致Ring Buffer中的数据包来不及处理(队列满)而导致丢包
- carrier表示发生carrier错误的数据包数,比如双工模式不匹配、物理电缆出现问题等
- collisions表示碰撞数据包数
性能优化
- DPDK:用户态网络标准,它跳过内核协议栈,直接由用户态进程通过轮询的方式来处理网络接收,如果在网络包很多的情况下(如C10M问题),由于每时每刻都有网络包需要处理,即使是轮询效率也很快。DPDK是目前最主流的高性能网络方案,需要支持DPDK的网卡配合使用
- XDP:允许网络包在进入内核协议栈之前,就进行处理,也可以带来更高的性能。基于XDP的应用程序通常是专用的网络应用,可用于IDS(入侵检测系统)、DDoS防御等