第九周

最后一周专栏推荐了一些书,讲了一些用户的故事。第一次看还是很激动的,这次重读感觉还好。推荐的书好些都没看过,CSAPP 也只是过了一遍,没有细致地钻研。

总结一下,重读专栏的收获:

  1. 把所有能在实际工作中用到的命令全都记录下来了。以后的排查线上问题的时候,遇事应该不慌了。
  2. 对单机性能优化的考虑维度更丰富、全面了。对工作或者求职面试都应该有所帮助。
  3. 没有刻意去“背记”,理解为主。专栏本身的语言已经很精炼,需要用的时候再来看一遍就行了。
  4. 虽然很有用,但是现实中真正需要进行性能优化的场景不是很多,找线上 bug 的场景会更多。两个方面的原因:能跑就行了、堆机器。
  5. 不过分聚焦在单机性能优化,系统整体架构设计更能体现在实力。

第八周

最后 53-57 篇都比较核心,常读常查。

系统监控的核心是资源的使用情况,包括 CPU、内存、磁盘和文件系统、网络等硬件资源,以及文件描述符数、连接数、连接跟踪数等软件资源。而这些资源,都可以通过 USE(Utilization Saturation and Errors) 法来建立核心性能指标。

USE 法把系统资源的性能指标,简化成了三个类别,即使用率、饱和度以及错误数。 这三者任一类别过高时,都代表相对应的系统资源有可能存在性能瓶颈。

应用程序的核心指标,不再是资源的使用情况,而是请求数、错误率和响应时间。例子是 CPU 使用率低,但可能发生了死锁、RPC 调用等,而导致响应变慢。也被称为 RED 法:请求数(Rate)、错误数(Errors)以及响应时间(Duration)。

所以,应用程序的核心指标,不再是资源的使用情况,而是请求数、错误率和响应时间。这些指标不仅直接关系到用户的使用体验,还反映应用整体的可用性和可靠性。还需要监控:应用进程的资源使用情况、应用程序之间调用情况、应用程序内部核心逻辑的运行情况。

经常听到 ELK,原来它是一个技术栈,包含 Elasticsearch、Logstash 和 Kibana 三个组件。ELK 技术栈中的 Logstash 资源消耗比较大。所以,在资源紧张的环境中,我们往往使用资源消耗更低的 Fluentd,来替代 Logstash(也就是所谓的 EFK 技术栈)。

性能问题的来源,分为资源瓶颈、依赖服务瓶颈以及应用自身瓶颈这三类。

当套接字处于连接状态(Established)时:

  • Recv-Q 表示套接字缓冲还没有被应用程序取走的字节数(即接收队列长度)。

  • 而 Send-Q 表示还没有被远端主机确认的字节数(即发送队列长度)。

当套接字处于监听状态(Listening)时:

  • Recv-Q 表示全连接队列的长度。

  • 而 Send-Q 表示全连接队列的最大长度。

可以快速查询不同 Linux 版本的源代码:https://elixir.bootlin.com/linux/latest/source

第七周

容器本身通过 cgroups 进行资源隔离,所以,在分析时要考虑 cgroups 对应用程序的影响。

丢包通常会带来严重的性能下降,特别是对 TCP 来说,丢包通常意味着网络拥塞和重传,进而还会导致网络延迟增大、吞吐降低。

ksoftirqd。它是一个用来处理软中断的内核线程,并且每个 CPU 上都有一个。

动态追踪技术,通过探针机制,来采集内核或者应用程序的运行信息,从而可以不用修改内核和应用程序的代码,就获得丰富的信息,帮你分析、定位想要排查的问题。见的动态追踪方法,包括 ftrace、perf、eBPF 以及 SystemTap 等。

这一期,动态追踪技术不是太好理解,第二次看了,还是不太懂,先跳过。

第六周

网络章节比较难,像 NAT 相关的,快速过了一遍,实际遇到的比较少,后面有用到的再来看吧。

从攻击的原理上来看,DDos 有这几种:耗尽带宽、耗尽操作系统的资源、消费应用程序的运行资源(如构造大量不同的域名来攻击 DNS 服务器)。

Nagle 算法,是 TCP 协议中用于减少小包发送数量的一种优化算法,目的是为了提高实际带宽的利用率。它通过合并 TCP 小包,提高网络带宽的利用率。Nagle 算法规定,一个 TCP 连接上,最多只能有一个未被确认的未完成分组;在收到这个分组的 ACK 前,不发送其他分组。这些小分组会被组合起来,并在收到 ACK 后,用同一个分组发送出去。

但 Nagle 算法如果遇到了Linux 默认的延迟确认机制后(可以设置 TCP_QUICKACK,即快速确认),就有问题了:一方在等 ACK,另一方又延迟确认(即延迟发 ACK),“死锁”了 40 ms 后才会发出确认 ACK,这增加了延迟。

只有设置了 TCP_NODELAY 后,Nagle 算法才会禁用。

第五周

因为 io 章节上周就完成了,所以网络这周早早地就完成了任务。

C10k 那一章内容比较多,面试前可以多看看。

我们常用带宽、吞吐量、延时、PPS(Packet Per Second)等指标衡量网络的性能。

带宽表示链路的最大传输速率,单位通常为 b/s (比特 / 秒)。吞吐量,表示单位时间内成功传输的数据量,单位通常为 b/s(比特 / 秒)或者 B/s(字节 / 秒)。吞吐量受带宽限制,而吞吐量 / 带宽,也就是该网络的使用率。

使用套接字接口的时候,也要分配一个文件描述符,后续所有的 I/O 都通过这个文件描述符来操作(包括IO模型中要判断可读写状态)。

第四周

周末花了一个整块的时间来看 I/O 这一章。

对 I/O 请求排序的过程,也就是我们熟悉的 I/O 调度。Linux 内核支持四种 I/O 调度算法,分别是 NONE、NOOP、CFQ 以及 DeadLine。

磁盘性能的衡量标准,有五个指标:使用率,饱和率,IOPS,吞吐量,响应时间。

过高的使用率(比如超过 60%)通常意味着磁盘 I/O 存在性能瓶颈。

阻塞 / 非阻塞和同步 / 异步,其实就是两个不同角度的 I/O 划分方式。它们描述的对象也不同,阻塞 / 非阻塞针对的是 I/O 调用者(即应用程序),而同步 / 异步针对的是 I/O 执行者(即系统)。

IO性能问题的思路:

  1. 首先可以通过 top 查看机器的整体负载情况,一般会出现 CPU 的 iowait 较高的现象;
  2. 然后使用 pidstat -d 1 找到读写磁盘较高的进程;
  3. 然后通过 strace -f -TT 进行跟踪,查看系统读写调用的频率和时间;
  4. 通过 lsof 找到 strace 中的文件描述符对应的文件 opensnoop 可以找到对应的问题位置。

第三周

本周主要是学习关于内存相关的知识,有些关于块设备的操作,怕把环境搞崩溃了,没跟着教程做。不过看着命令集不断地“壮大”,还是挺不错的。

内存调优最重要的就是,保证应用程序的热点数据放到内存中,并尽量减少换页和交换。

活跃和非活跃的内存页,按照类型的不同,又分别分为文件页和匿名页,对应着缓存回收和 Swap 回收。

OOM 触发的时机基于虚拟内存。换句话说,进程在申请内存时,如果申请的虚拟内存加上服务器实际已用的内存之和,比总的物理内存还大,就会触发 OOM。

磁盘是存储数据的块设备,也是文件系统的载体。所以,文件系统确实还是要通过磁盘,来保证数据的持久化存储。在读写普通文件时,I/O 请求会首先经过文件系统,然后由文件系统负责,来与磁盘进行交互。而在读写块设备文件时,会跳过文件系统,直接与磁盘交互,也就是所谓的“裸 I/O”。文件系统管理的缓存,其实就是 Cache 的一部分。而裸磁盘的缓存,用的正是 Buffer。

第二周

由于是双周,少了一个周日的时间来看专栏,有点赶,加上 0607 晚上又有一个交流会,这次笔记写得有点匆忙。当然,专栏上的文字内容是早就看完了。

这次的感觉是重新看一遍感觉比上次看要容易很多。果然难的东西要看第二遍、第三遍就比较清晰。

持续在思考的就是怎样把这些东西融汇贯通?

如果能在实践中直接用的话,是比较有成就感的。比如:https://qcrao.com/2020/04/27/codec-accident/

听了大家的分享,赶紧有一群人一起学习还是挺好的。

先完成,再完美。

后面的模式是每周写一些心得感受,然后更新汇总的命令。争取在专栏完成的时候有一个速查手册,遇到性能方面的问题能直接拿出来参考。

all

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# 查看 CPU 核心数
$ grep 'model name' /proc/cpuinfo | wc -l

# 节拍率 HZ
$ grep 'CONFIG_HZ=' /boot/config-$(uname -r)

# 从所有进程中查找PID是24344的进程
$ ps aux | grep 24344

# 用树状形式显示所有进程之间的关系
$ pstree | grep stress

# -a 表示输出命令行选项
# p表PID
# s表示指定进程的父进程
$ pstree -aps 3084

# -t表示显示线程,-a表示显示命令行参数
pstree -t -a -p 27458

# 查看启动用户
ps aux | grep "nginx: worker process" | awk '{print $1}'

# 显示none就是物理机,显示 kvm 则是虚拟机
$ systemd-detect-virt

# 内核版本
$ uname -r

# 查看装了哪些 linux-tools
$ apt list linux-tools*
# 显示更多信息
$ apt show linux-tools* -a

# 可以查看系统的整体内存和 Swap 使用情况。
# 查看整个系统物理内存 Mem 和交换分区 Swap 的使用情况,以字节为单位
# 读取 /proc/meminfo 获得数据
# Buffer 是对磁盘数据的缓存,而 Cache 是对文件数据的缓存,它们既会用在读请求中,也会用在写请求中
$ free

# 显示处理器在 Node 的分布情况
$ numactl --hardware

# 调整文件页和匿名页的回收倾向。
# 系统会根据此值,倾向于选择合适的回收类型,比如回收不活跃的匿名页,或者不活跃的文件页。
$ cat /proc/sys/vm/swappiness

# 关闭 swap 机制
$ swapoff -a

# 常用的 Swap 空间清理方法
$ swapoff -a && swapon -a

# 开启 swap 机制
# 创建Swap文件
$ fallocate -l 8G /mnt/swapfile
# 修改权限只有根用户可以访问
$ chmod 600 /mnt/swapfile
# 配置Swap文件
$ mkswap /mnt/swapfile
# 开启Swap
$ swapon /mnt/swapfile

# 查询 OOM 日志,查看哪些进程被 OOM 杀死了
$ dmesg | grep -i "Out of memory"

# 统计所有进程的物理内存使用量
# 使用grep查找Pss指标后,再用awk计算累加值
# 每个进程的 PSS ,是指把共享内存平分到各个进程后,再加上进程本身的非共享内存大小的和。
$ grep Pss /proc/[1-9]*/smaps | awk '{total+=$2}; END {printf "%d kB\n", total }'

# 日志处理工具:awk,sed,grep,sort,uniq,xargs
# 读取日志文件,每行按空格划分,打印出第 1 列,按字母顺序排序,过滤重复行且输出计数,对数字进行排序(-n)并逆序返回(-r),最后输出前 5 行
cat x.log | awk '{print $1}' | sort | uniq -c | sort -r -n | head -n 5

# 查看文件系统的磁盘空间使用情况
df /dev/sda1
# -h 能提供更好的可读性
df -h /dev/sda1
# -i 查看索引节点的使用情况。索引节点的容量(个数)在格式化磁盘时就会设置好
# 当你发现索引节点空间不足,但磁盘空间充足时,很可能就是过多小文件导致的。
df -ih /dev/sda1

# 找到占用内存最多的缓存类型
# 按下c按照缓存大小排序,按下a按照活跃对象数排序
slabtop

# 查看进程打开文件列表,不过,这里的“文件”不只有普通文件,还包括了目录、块设备、动态库、网络套接字
# u 是指以读写方式
lsof -p #pid

# 给进程 18940 发送 SIGUSR2 信号
kill -SIGUSR2 18940

# 循环执行 curl 命令
$ while true; do time curl http://192.168.0.10:10000/popularity/word; sleep 1; done

# 根据线程号查看进程号
ps -efT | grep 514

# 重启 docker
sudo service docker restart

# 上一条命令退出时的返回值。0 成功,1 失败
echo $?

# 查看指定进程号对应的网络连接
# -i表示显示网络套接字信息
nsenter --target 12092 --net -- lsof -i

# 查看网络配置状态
ifconfig eth0
ip -s addr show dev eth0

# 查看网卡速度,也就是带宽,Bandwidth
ethtool eth0 | grep Speed

# -c3表示发送三次ICMP包后停止
$ ping -c3 114.114.114.114

# -w表示只输出HTTP状态码及总时间,-o表示将响应重定向到/dev/null
$ curl -s -w 'Http code: %{http_code}\nTotal time:%{time_total}s\n' -o /dev/null http://192.168.0.30/

# 循环访问某一地址
for ((i=0;i<30;i++)); do curl localhost:8080; sleep 1; done

# 访问三次
curl --max-time 3 http://192.168.0.30

# 直接查询 DROP 和 REJECT 等规则的统计信息
iptables -t filter -nvL

# 删除规则
iptables -t filter -D INPUT -m statistic --mode random --probability 0.30 -j DROP
iptables -t filter -D OUTPUT -m statistic --mode random --probability 0.30 -j DROP

# 查看 MTU 大小
cat /sys/class/net/eth0/mtu

# 要查找内核线程,我们只需要从 2 号进程开始,查找它的子孙进程即可
ps -f --ppid 2 -p 2
# 因为 cmd 都是在 [] 内,所以上面的命令等价于:
ps -ef | grep "\[.*\]"

# 获取页的大小
getconf PAGE_SIZE

install

1
2
3
4
5
6
7
8
9
10
11
12
13
# 下载安装 execsnoop
1 cd /usr/bin
2 wget https://raw.githubusercontent.com/brendangregg/perf-tools/master/execsnoop
3 chmod 755 execsnoop

# 下载安装火焰图工具
# git clone https://github.com/brendangregg/FlameGraph

# 生成火焰图
# 1. 执行perf记录事件
$ perf record -g
# 2. 切换到FlameGraph安装路径执行下面的命令生成火焰图
$ perf script -i ~/perf.data | ./stackcollapse-perf.pl --all | ./flamegraph.pl > nginx.svg

bcc

1
2
3
4
5
6
7
8
# 下载安装 bcc
# Install bcc
# bcc 软件包提供了一系列的 Linux 性能分析工具,常用来动态追踪进程和内核的行为。
# 安装完成后,位于 /usr/share/bcc/tools
$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4052245BD4284CDD
$ echo "deb https://repo.iovisor.org/apt/bionic bionic main" | sudo tee /etc/apt/sources.list.d/iovisor.list
$ sudo apt-get update
$ sudo apt-get install -y bcc-tools libbcc-examples linux-headers-$(uname -r)

先 cd 到安装目录:

cd /usr/share/bcc/tools

filetop

1
2
3
# -C 选项表示输出新内容时不清空屏幕 
# 观察一下文件的读写情况。分析系统调用 write()
./filetop -C

memleak

专门用来检测内存泄漏的工具,memleak。memleak 可以跟踪系统或指定进程的内存分配、释放请求,然后定期输出一个未释放内存和相应调用栈的汇总情况(默认 5 秒)。

类似的工具:valgrind

位于 /usr/share/bcc/tools/memleak

1
2
3
# -a 表示显示每个内存分配请求的大小以及地址
# -p 指定案例应用的PID号
$ /usr/share/bcc/tools/memleak -a -p $(pidof app)

cachestat

提供了整个操作系统缓存的读写命中情况。

cachetop

提供了每个进程的缓存命中情况。cachetop 工具并不把直接 I/O 算进来。

1
2
# 找出 top 5
$ /usr/share/bcc/tools/cachetop 5

opensnoop

1
2
# 可以动态跟踪内核中的 open 系统调用。查看系统调用的文件路径
./opensnoop

ab

ab(apache bench)是一个常用的 HTTP 服务性能测试工具。

1
2
3
4
5
# 并发10个请求测试Nginx性能,总共测试100个请求
$ ab -c 10 -n 100 http://192.168.0.10:10000/

# 并发5个请求测试Nginx性能,总共测试10分钟
$ ab -c 5 -t 600 http://192.168.0.10:10000/

stress

安装:apt install stress

stress 是一个 Linux 系统压力测试工具,这里我们用作异常进程模拟平均负载升高的场景。

  • 模拟一个 CPU 使用率 100% 的场景
1
stress --cpu 1 --timeout 600
  • 模拟 I/O 压力,即不停地执行 sync
1
stress -i 1 --timeout 600
  • 模拟 8 个进程
1
stress -c 8 --timeout 600

sysbench

安装:apt install sysbench

sysbench 是一个多线程的基准测试工具,一般用来评估不同系统参数下的数据库负载情况。

1
2
# 以10个线程运行5分钟的基准测试,模拟多线程切换的问题
$ sysbench --threads=10 --max-time=300 threads run

sysstat

安装:apt install sysstat

sysstat 包含了常用的 Linux 性能工具,用来监控和分析系统的性能。案例会用到这个包的两个命令 mpstat 和 pidstat。

mpstat 是一个常用的多核 CPU 性能分析工具,用来实时查看每个 CPU 的性能指标,以及所有 CPU 的平均指标。

pidstat 是一个常用的进程性能分析工具,用来实时查看进程的 CPU、内存、I/O 以及上下文切换等性能指标。pidstat 只是一个进程的性能分析工具,并不提供任何关于中断的详细信息。

  • 查看所有 CPU 的情况
1
2
# -P ALL 表示监控所有CPU,后面数字5表示间隔5秒后输出一组数据
$ mpstat -P ALL 5
  • 以进程视角查看 CPU 使用率
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 每间隔5秒输出一组数据,-u表示CPU指标(周期性)
$ pidstat -u 5

# 间隔5秒后输出一组数据,-u表示CPU指标(一次)
$ pidstat -u 5 1

# 每隔5秒输出1组数据。查看每个进程上下文切换的情况
$ pidstat -w 5

# 每隔1秒输出1组数据(需要 Ctrl+C 才结束)
# -w参数表示输出进程切换指标,而-u参数则表示输出CPU使用指标
$ pidstat -w -u 1

# 每隔1秒输出一组数据(需要 Ctrl+C 才结束)
# -wt 参数表示输出线程的上下文切换指标
$ pidstat -wt 1

# 指定进程
pidstat -p 24344

# -d 展示 I/O 统计数据,-p 指定进程号,间隔 1 秒输出 3 组数据
$ pidstat -d -p 4344 1 3

# 间隔 1 秒输出多组数据 (这里是 20 组)
$ pidstat -d 1 20

vmstat

vmstat 是一个常用的系统性能分析工具,主要用来分析系统的内存使用情况,也常用来分析 CPU 上下文切换和中断的次数。

  • 系统整体情况。如系统整体的上下问切换情况
1
2
3
4
5
6
7
# 每隔5秒输出1组数据。
# buff 和 cache 的单位是 KB
# bi 和 bo 则分别表示块设备读取和写入的大小,单位为块/秒。因为 Linux 中块的大小是 1KB,所以这个单位也就等价于 KB/s
$ vmstat 5

# 间隔1秒后输出1组数据
$ vmstat 1 1

dstat

可以同时查看 CPU 和 I/O 这两种资源的使用情况。

1
2
# 间隔1秒输出10组数据
$ dstat 1 10

/proc

/proc 实际上是 Linux 的一个虚拟文件系统,用于内核空间与用户空间之间的通信。/proc/interrupts 就是这种通信机制的一部分,提供了一个只读的中断使用情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# -d 参数表示高亮显示变化的区域
$ watch -d cat /proc/interrupts

# 只保留各个CPU的数据。/proc/stat 提供的就是系统的 CPU 和任务统计信息
# 以进程的视角 /proc/[pid]/stat
$ cat /proc/stat | grep ^cpu

# 将 sshd 进程的 oom_adj 调小为 -16,这样, sshd 进程就不容易被 OOM 杀死
# [-17, 15],其中 -17 表示禁止 OOM
$ echo -16 > /proc/$(pidof sshd)/oom_adj

# 通过 /proc 系统清理系统缓存
# 写入 3 表示清理文件页、目录项、Inodes 等各种缓存
$ echo 3 > /proc/sys/vm/drop_caches
# 清理 dentries 和 inodes
echo 2 > /proc/sys/vm/drop_caches
# 清理 page cache
echo 1 > /proc/sys/vm/drop_caches

# 可查看三个内存阈值(页最小阈值、页低阈值和页高阈值)
$ cat /proc/zoneinfo

# -d 表示高亮变化的字段
# -A 表示仅显示Normal行以及之后的15行输出;-B 表示之前
$ watch -d grep -A 15 'Normal' /proc/zoneinfo

# 按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 | headdockerd

# grep表示只保留包含active的指标
# -i 忽略大小写
# sort表示按照字母顺序排序
$ cat /proc/meminfo | grep -i active | sort


# 查看所有目录项和各种文件系统索引节点的缓存情况
# dentry 行表示目录项缓存,inode_cache 行,表示 VFS 索引节点缓存,其余的则是各种文件系统的索引节点缓存
cat /proc/slabinfo | grep -E '^#|dentry|inode'

重调度中断(RES),这个中断类型表示,唤醒空闲状态的 CPU 来调度新的任务运行。这是多处理器系统(SMP)中,调度器用来分散任务到不同 CPU 的机制,通常也被称为处理器间中断(Inter-Processor Interrupts,IPI)。

perf

perf 是 Linux 2.6.31 以后内置的性能分析工具。它以性能事件采样为基础,不仅可以分析系统的各种事件和内核性能,还可以用来分析指定应用程序的性能问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 它能够实时显示占用 CPU 时钟最多的函数或者指令,因此可以用来查找热点函数
# 虽然实时展示了系统的性能信息,但它的缺点是并不保存数据,也就无法用于离线或者后续的分析
$ perf top

# perf record 则提供了保存数据的功能
# 加上 -g 参数,开启调用关系的采样
$ perf record # 按Ctrl+C终止采样
$ perf report # 展示类似于perf top的报告

# -g开启调用关系分析,-p指定php-fpm的进程号21515
$ perf top -g -p 21515

# 采样30s后退出
perf record -a -g -p 9 -- sleep 30
# 生成 perf.data 后,生成火焰图
$ git clone https://github.com/brendangregg/FlameGraph
$ cd FlameGraph
$ perf script -i /root/perf.data | ./stackcollapse-perf.pl --all | ./flamegraph.pl > ksoftirqd.svg

strace

strace 正是最常用的跟踪进程系统调用的工具。

1
2
3
4
5
6
7
8
9
10
11
12
13
# -p 参数指定 PID 号
$ strace -p 6082

# 过滤一下 write 调用
strace -p 12280 2>&1 | grep write

# 跟踪所有线程
strace -fp pid

# -f表示跟踪子进程和子线程,-T表示显示系统调用的时长,-tt表示显示跟踪时间
strace -f -T -tt -p 9085
# -e 指定系统调用
strace -f -p 9085 -T -tt -e fdatasync

sar

1
2
3
4
5
6
7
8
# 间隔1秒输出一组数据
# -r表示显示内存使用情况,-S表示显示Swap使用情况
# 指标名称前面的 kb 前缀,表示这些指标的单位是 KB。
$ sar -r -S 1

# 查看网络的统计信息
# 数字1表示每隔1秒输出一组数据
$ sar -n DEV 1

iostat

1
2
3
4
# -d -x表示显示所有磁盘I/O的指标
# 它提供了每个磁盘的使用率、IOPS、吞吐量等各种常见的性能指标
# 指标实际上来自 /proc/diskstats
iostat -d -x 1

pidstat

1
2
3
4
5
# 加上 -d 参数,你就可以看到进程的 I/O 情况
pidstat -d 1

# -t表示显示线程,-p指定进程号
pidstat -t -p 29457 1

iotop

1
2
# 按照 I/O 大小对进程排序
iotop

docker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 查看容器状态
docker ps

# 强制删除容器
docker rm -f dockerid/dockername

# 查看数据库底层文件
# MYD 文件用来存储表的数据;
# MYI 文件用来存储表的索引;
# frm 文件用来存储表的元信息(比如表结构);
# opt 文件则用来存储数据库的元信息(比如字符集、字符校验规则等)。
docker exec -it mysql ls /var/lib/mysql/test/

# 查询 mysqld 配置的数据路径
docker exec -i -t mysql mysql -e 'show global variables like "%datadir%";'

# 进入 mysql 命令行
docker exec -i -t mysql mysql

# 获取 redis append 策略配置
docker exec -it redis redis-cli config get 'append*'
# 设置 appendfsync 策略
docker exec -it redis redis-cli config set appendfsync everysec

# 查询新容器中进程的Pid
PID=$(docker inspect tomcat -f '{{.State.Pid}}')
# 使用
pidstat -t -p $PID 1

# 进入到容器内部命令行
docker exec -it nginx bash

MySQL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 查看当前正在执行的 SQL 语句
show full processlist;

# explain
explain select * from products where productName='geektime';

# 查询表结构
show create table products;

# 加索引
CREATE INDEX products_index ON products (productName);
# 指定一个前缀长度
CREATE INDEX products_index ON products (productName(64));
# 删除索引
DROP INDEX products_index ON products;

netstat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# head -n 3 表示只显示前面3行
# -l 表示只显示监听套接字
# -n 表示显示数字地址和端口(而不是名字)
# -p 表示显示进程信息
$ netstat -nlp | head -n 3

# 查看协议栈的信息
# 协议的收发汇总,以及错误信息了
netstat -s

# 只关注套接字统计。可查看是否有丢包现象
netstat -s | grep socket

# 查看网卡是否丢包
netstat -i

# 查看半连接信息
# -n表示不解析名字,-p表示显示连接所属进程
netstat -n -p | grep SYN_REC

# 查看 TIME_WAIT 状态的连接
netstat -alepn | grep TIME_WAIT

# 检测 eth0 是否配备了 tc 规则
tc -s qdisc show dev eth0
# 删掉 netem 模块
tc qdisc del dev eth0 root netem loss 30%

ss

1
2
3
4
5
6
7
8
9
10
# Socket Statistics的缩写

# -l 表示只显示监听套接字
# -t 表示只显示 TCP 套接字
# -n 表示显示数字地址和端口(而不是名字)
# -p 表示显示进程信息
$ ss -ltnp | head -n 3

# 查看协议栈的信息。连接数的信息
ss -s

wrk

1
2
3
4
5
6
7
8
9
10
# -c表示并发连接数1000,-t表示线程数为2
# wrk 支持 lua 脚本
$ wrk -c 1000 -t 2 http://192.168.0.30/

# 测试80端口性能
# --latency 会输出耗时分位数
wrk --latency -c 100 -t 2 --timeout 2 http://192.168.0.30/

# 查看系统调用
strace -f wrk --latency -c 100 -t 2 --timeout 2 http://192.168.0.30:8080/

nslookup

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 查询 DNS 的配置
cat /etc/resolv.conf

# 查询域名的 A 记录
nslookup time.geekbang.org

# 显示 dns 的过程
nslookup -debug time.geekbang.org

# +trace表示开启跟踪查询
# +nodnssec表示禁止DNS安全扩展
# 结果会展示整个查询的过程
dig +trace +nodnssec time.geekbang.org

# 显示时间
time nslookup time.geekbang.org

# 启动 dns 缓存
/etc/init.d/dnsmasq start

tcpdump

1
2
3
4
5
6
7
8
9
# -nn ,表示不解析抓包中的域名(即不反向解析)、协议以及端口号
# udp port 53 ,表示只显示 UDP 协议的端口号(包括源端口和目的端口)为 53 的包
# host 35.190.27.188 ,表示只显示 IP 地址(包括源地址和目的地址)为 35.190.27.188 的包。
# 这两个过滤条件中间的“ or ”,表示或的关系,也就是说,只要满足上面两个条件中的任一个,就可以展示出来。
tcpdump -nn udp port 53 or host 35.190.27.188

# -i eth0 只抓取eth0网卡,-n不解析协议名和主机名
# tcp port 80表示只抓取tcp协议并且端口号为80的网络帧
tcpdump -i eth0 -n tcp port 80

hping3

ping 基于 ICMP 协议,不需要认证,常被很多网络攻击利用,比如端口扫描工具 nmap、组包工具 hping3 等等。所以很多服务会把 ICMP 禁止掉,导致无法使用 ping。但可以用 hping3 的 TCP 和 UDP 模式来获取网络延迟。

1
2
3
4
5
6
7
8
# -S参数表示设置TCP协议的SYN(同步序列号),-p表示目的端口为80# -i u10表示每隔10微秒发送一个网络帧
hping3 -S -p 80 -i u10 192.168.0.30

# -c表示发送3次请求,-S表示设置TCP SYN,-p表示端口号为80
hping3 -c 3 -S -p 80 baidu.com

# 测试80端口延迟
hping3 -c 3 -S -p 80 192.168.0.30

sysctl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 默认的半连接数
sysctl net.ipv4.tcp_max_syn_backlog
# 修改默认的半连接数
sysctl -w net.ipv4.tcp_max_syn_backlog=1024

# 修改重试次数
sysctl -w net.ipv4.tcp_synack_retries=1

# 开启 syncookies
sysctl -w net.ipv4.tcp_syncookies=1

# sysctl 命令修改的配置都是临时的,重启后这些配置就会丢失
# 需要持久化,你还应该把这些配置,写入 /etc/sysctl.conf 文件中
cat /etc/sysctl.conf

# 动态生效修改的 sysctl.conf 文件
sysctl -p

# 系统级监听套接字的上限
sysctl net.core.somaxconn

# 查看系统配置的临时端口范围
sysctl net.ipv4.ip_local_port_range
# 设置系统配置的临时端口范围
sysctl -w net.ipv4.ip_local_port_range="10000 65535"

# 查看是否重用端口号
sysctl net.ipv4.tcp_tw_reuse