CE 阶段调优方法回顾
在以前的课程中,/proc、/sys 目录是几乎没有接触和用到的,在CE 阶段,其实就已经接触过一部分性能调优了,我们在/etc/sysctl.conf 配置文件中写入的内核参数,例如:net.ipv4.ip_forward = 1,加入这样一行参数,那么系统在开机的时候就会读取这个配置文件里,从而使这个参数生效,其实这个参数对应的文件就在/proc/sys/net/ipv4/xxx 这样的文件中。
除此以外,我们还在CE 阶段接触过内核参数调优,在RHEL 8 中,是/etc/default/grub 这个目录,可以在这里写内核参数,开机的时候给内核传参。
比如说加入:
selinux=0
然后执行一个命令叫:
grub2-mkconfig -o /boot/grub2/grub.cfg
它会读取/etc/default/grub 进而生成grub.cfg
为什么调内核呢?是因为内核文件是编译的时候生成的,这个内核有哪些功能呢?其实是看这个文件:
等于y 的就表示这个功能在内核中开启了, 还有m 的就表示它是以模块化的方式来配置的,按需加载这个功能。但如果是你需要修改这个功能,不可以在这个文件中把y 修改成n,这个文件只是展示系统内核当前的功能。
那如果要修改怎么办?需要重新编译内核。那不可能说我改一个功能就重新编译内核呀,那为了解决这个问题怎么办?所以就做了一个功能叫/etc/default/grub,这样很清楚了。
使用内核帮助文档
在RHEL 6 阶段,光盘里面是有一个包叫kernel-doc,RHEL 7 开始,光盘里面这个包没有了,因为这个包很大,当时红帽为了让iso文件不会很大,不超过4G,就把一些额外的包放到红帽官网,iso里面就没有放。现在iso文件已经远远超过4G了,既然不可避免地增大,干脆就把这个包又放进来了。
接下来我们就装一下这个包,查一下yum仓库:
安装:
这个包集成了几乎全部的内核参数的解释,不过是英文的。
有时候想要了解一个内核参数的功能, 百度出来的结果是不太准确的,最好的方式是看内核的帮助文档。
帮助文档的目录在/usr/share/doc/kernel-doc-4.18.xxxxxx 类似于这样的目录中。
这个目录里面就是所有内核的帮助文档,全部分门别类地放到这里了。
如果你要搜索一个内核参数的说明文档,那在众多的文档中,我怎么知道它在哪里呢?这就要学到一个命令了:
-i 忽略大小写
-r 递归
-n 显示行号
-l 只列出文件名,不显示文件里面的内容
再介绍一个好玩的功能:
在这个文件中,有说明一些system request 值,可以模拟一些场景。
比如说:
1、模拟强制重启,但没有包含数据回写和卸载磁盘的动作:
2、模拟系统崩溃:
监控
要对系统调优,首先就是要找到性能的瓶颈,那么如何找到瓶颈,就是要通过监控来实现。
那么怎么监控呢?我们将要利用自带的工具,不依赖于外部的监控软件。
常见的命令有:iostat、sar、vmstat、top、ps、fio、ps 等等...
可以这样来查询一个命令属于什么包:
在学习监控工具之前,我们先要了解一个系统自带的计算器功能,因为我们监控出来的数据,常常需要进行计算。
bc 是一个命令行下的计算器,直接输入bc 回车,进入交互式视图,输入表达式就可以进行计算了。
默认不保留小数,如果需要保留小数位,这样:
如果以后看到这样的单位:
KiBi:这个换算单位是1024,B 是字节
Kibi:这个b 是bit
KB:这个换算单位是1000,B 是字节
这几个单位在我们调优的课程中,要特别关注。
这条命令直接执行的结果:
第一部分是内核(主机名) 日期 cpu架构 cpu核心数
第二部分是cpu的平均负载,这里是系统自开机以来的平均负载,如果系统是1000天没有重启过,那就是1000天的平均负载,所有字段的值加在一起是100%
%idle:空闲率
%user:如果cpu的使用率很高,这个值又很高,说明是应用程序导致的,说明我们系统的瓶颈是应用程序,是应用程序消耗了过多的cpu资源
%nice:cpu 计算nice 优先级消耗的资源,一般来说不会是瓶颈
%system:如果这个值很高,说明是内核使用了过多的cpu资源
%iowait: 与io 有关,计算io 所消耗的cpu 资源
%steal:这个值跟虚拟化有关,如果是虚拟机,虚拟机占用的是宿主机的资源,如果这个值比较高,代表我这台机器所在的宿主机比较繁忙影响到我了,而不是我虚拟机本身繁忙,这个值通常在1% ~ 2%,不会太高,一般不是瓶颈。
第三部分是磁盘相关的监控指标
所谓io,就是input 与 output,我们所说的IO 设备一般是指磁盘和网络。
虚拟化中的virtio 通常是指磁盘和网络的io,因为我们不可能是把键盘和鼠标设备拿来做调优。
如果你要显示当前的值,那么比如可以加个数字1,每一秒钟显示一次:
下面这个表示:一秒钟显示一次,连续显示5次:
那么这个就是实时监控了。
后面我们经常会讲的两个词:
Kernel Space:内核空间 内核态
User Space: 用户空间 应用程序 用户态
我们经常执行的ls、cp 命令都是内核提供的机制:
如果我们打开一个火狐浏览器,那很显然,它是应用提供的,这个操作是在用户空间进行的。
从RHEL 8 开始,iso 光盘里面的应用程序分为两个文件夹,一个是AppStream,一个是BaseOS。像vsftpd、httpd程序是属于用户层的,在AppStream 中。
所以我们在观察监控项的时候,如果是%user 过高,那就是应用程序导致的,如果是%system过高,那就是内核机制引起的,比如说:防火墙、selinux、文件系统、进程,这些功能都是内核提供的。
你可以执行一条命令:
把零字符输出到空设备,丢到后台执行。这就好比开车挂空挡,发动机狂转,但车不会跑。dd 命令内核提供的,这个时候再看监控项,%system 的值就升高了,%idle 空闲率下降。
nice 优先级是在CE 阶段学习过的,在系统很繁忙的时候用。
如果要模拟系统繁忙,可以通过下面这几条命令模拟:
如果cpu 是双核的,那么到第二条命令敲下去的时候就系统就已经很繁忙了,idle 空间率为零,这个时候再敲第三条,系统依然可以正常运行,因为进程的优先级都是相同的,系统会对这些进程轮循,每个进程得到的时间片是相同的。
nice:指定优先级运行程序
renice:对一个已经运行的进程调整优先级
范围:-20 ~ 19,数字越小,优先级越高
这个时候,这个进程优先处理。
再来一个:
这样很清楚了。
如果是RHEL 5,这样做,系统就死机了, 从RHEL 6 开始,就没有。它用了一个算法:
进程算法:CFS 完全公平原则
尽可能让每个进程都能得到时间片。
系统会将所有的进程进行分组,给每个组分配时间片,组中的进程根据优先级来分配时间片的多少。
如果是RHEL 5,会存在进程被饿死的情况,所以会死机。
了解一下即可。
如果我只想看某块磁盘的io监控,这样:
拷贝文件:
这个时候%system 和 %iowait 值会升高。
还有一条专门查看io 的命令,叫iotop,安装它:
再来执行:
可以看到每秒钟读、每秒钟写、io 占用率。用iostat 可以看到总的io 占用率,而iotop 可以观察到具体是哪一个任务占用的io 比较高。
top 命令第一行右边也有一段是显示cpu 的平均负载,分别是1分钟、5分钟、15分钟的平均负载:
现在运行了两个md5 计算的任务,这个负载已经在逐步上升了,最终会到2 左右,因为cpu 是双核。
如果是64 核,那么这个值到64 左右才算是极限,所以这个值跟cpu 的数量有关。负载率太高,不行,性能达到瓶颈,造成应用程序卡顿,太低,也不行,资源浪费。理想的值是:阈值 * 70% 那么,双核就是1.4 左右。
现在系统是双核的,如果再继续新增任务,这个值其实是可以超过2 的甚至达到3,那么表示cpu 的负载达到瓶颈,至少需要3 核处理器才能处理得过来。
有些时候,一个进程就足以把一个物理cpu的资源耗尽,尤其是处理高并发的任务,像数据库。这个时候,我们调优,通常会调整使这个任务均衡地分布到多个物理cpu上运行,不至于把单个cpu 耗死,这个会在后面的内容中介绍到。
接着讲第三部分,磁盘:
同样的,这样显示的是自开机以来的数值,如果要显示实时的,需加上刷新间隔和显示次数。
kB_read/s:每秒钟平均读了多少kB
kB_read/s:每秒钟平均写了多少kB
kB_read:一共读了多少kB
kB_wrtn:一共写了多少kB
tps:每秒钟处理的IO 数量(对于这个设备而言每秒钟的请求数,每秒钟处理了多少个IO)
未来我们针对于IO 的调优涉及到:
小IO 场景:一般来说,小于16k 的io 叫小io
大IO 场景:大于16k 的io 叫大io
例如:
写一个大约300M 的文件,直接写入到磁盘,不写缓存,即透写,加一个参数oflag:
可以看到,回显的数据328 MB 比 312 MiB 大,因为MB 是以1000 为换算单位,MiB 是以1024 为换算单位。
这次换成小io,把bs(block size)换成4k,count 数量换成80000:
同样的数据量,写入的速度却大相径庭,可见io 的大小对性能影响是比较大的。
一般来说,衡量io 的性能,我们看三个指标:
1、IOPS:每秒钟处理的IO 数量
2、带宽:每秒能写入多少数据
3、时延:一般以毫秒ms 为单位,表示从下发一个io 请求到最终写入数据到磁盘这个中间过程的时间。
如果一台存储在写入数据的时候,都是小io,用iops 来衡量其性能,
如果写入的是大io,则用带宽衡量。
一般来说,固态硬盘的io 能力更强。
https://support.huaweicloud.com/productdesc-evs/zh-cn_topic_0044524691.html
所以我们针对于小io 和大io 的场景去做测试,是不一样的效果,我们今天不讨论如何针对于小io 和大io 的场景做调优,而更多的是想知道在实际的业务场景中,怎么判断是大io 还是小io呢?那这个时候就要测试了。
如何测试?
按16k来测,然后做监控,从tps 可以看出来,每秒钟处理大概1700 个io,我们拿最后一个数据来算:
得到计算结果:16k
再来算一个:
刚好等于16
这样就得到了io 大小,以此来判断是大io 场景还是小io 场景。
大io 与小io 的调优方法是不一样的,用的调度算法不一样。
在真实的业务场景中,是用 ( kB_read/s + kB_wrtn/s ) / tps 来得到io 大小。
iostat 命令可以指定一个选项-d,显示某块磁盘相关的监控数据:
也可以指定一个-x 选项,显示更详细的监控数据:
r/s:每秒钟能处理的读请求数
w/s:每秒钟能处理的写请求数
sec/s:每秒钟能处理的扇区数
rrqm/s:每秒钟能处理的读请求的整合数
areq-sz:平均的io 请求的大小
svctm:每一个io请求所需要的服务时间
更多参数说明:man iostat
来看一个案例:
其实存储的底层也是一个linux,在底层做了raid 以后,比如说用10 块盘raid 5,在操作系统这一层看到的是一块硬盘,但是,在存储底层看到的是10 块盘,这个时候如果是想排查,到底是哪块盘的问题,肯定是要进入到存储的底层执行命令查询,而不是在主机端执行。其实在存储底端,我们执行的很多查询命令也就是我们在系统调优这门课程中学习到的监控命令:iostat、sar 等等...
接下来再提到一款工具:fio,它可以用来做压力测试。
它是一个非常灵活的io 测试工具。
这里不展开说明,自行百度。
sar 相对于iostat 来说,它是一款综合的工具。
收集、记录、保存系统活动的信息。
-d:显示磁盘信息
第一字段:时间,12小时制
DEV:设备名
-u:显示cpu信息
-r:显示内存信息
如果要修改时间显示格式为24小时制,我们在,用户目录下加一个环境变量:
iostat 只能显示当前的监控数据和自开机以来的数据,
而sar 可以统计某一时刻的监控数据。
scsi 硬盘sda 一般主编号是8,次编号0
sdb 主编号是8,次编号是16
主编号8,代表scsi 硬盘,次编号是从0 开始编号,那为什么sdb 次编号是16呢?是因为一个硬盘最多能分15 个分区,所以即使你没有分15 个分区,系统也会为硬盘预留,所以轮到sdb,就是从16 开始了,sdb1 是17... 以此类推
如果有sdc,那么应该是8, 31
所以到了虚拟机里面,硬盘就是一个vda,它是一个VirtIO 设备,所以主编号就是252,sar 命令的显示数据DEV 字段就是dev252 开头。
加一个 -p 选项,DEV 列就是用设备名来显示:
但是sar 命令不能指定某一块磁盘,只能通过grep 过滤:
如果我想要统计某一时刻的监控数据:
运行过程中:
sar 命令有个好处就是会在最后显示一个平均值,但我想要的不是平均值,而是这期间负载最高的值是哪一个
需求:统计/dev/vda 硬盘在一天中什么时间段负载最高,达到多少?
sar 相比于iostat 来说还有一个更厉害的功能,它可以自动帮你统计历史监控数据,不需要你手动统计。在系统中,有这样一个文件:
另外一个路径是在:
这是一个系统的计划任务,默认情况下,每10分钟收集一次系统的状态:
这里的10分钟如果你觉得时间太长了,可以自己修改这个值。
在Linux 系统中,记住:只要手动修改了服务的配置,必须要执行一条命令,重载服务的配置文件,读到内存中来:
否则,就会出现这样的报错:
再执行重启,这样就生效了:
系统当中有个log,路径:
这是一个日志目录,里面有个文件sa18,为什么是18呢?因为今天是18号,换台机器看看:
也就是说,这个目录,会根据当天的日期生成一个文件。
到了第下一个月,就会把前面的内容覆盖,默认只保留一个月的内容。
这个文件是一个数据库文件,不能用vim文本编辑器查看和编辑它。
通过sar 命令指定 -f 选项,后面跟文件名来查看:
系统会在次日早山7:00,把昨天一整天的监控数据做一份记录:
现在只有一个sa18,本来应该还有一个sar18
这个服务的配置文件,其实应该是执行了这样一条命令:
还有一个脚本:
每天早上7 点对昨天的数据做一个汇总。
本质上是执行了这样一条命令:
所以,如果我想查看某个时间段的监控数据:
接下来介绍top命令:
第一行:
当前系统时间 开机时长 用户在线数量 cpu平均负载 1分钟 5分钟 15分钟
第二行:
进程数量 处于运行状态的进程数 处于休眠状态的进程数 处于停止状态的进程数 僵尸进程数
第三行:
cpu相关:用户态 内核态 优先级 空闲率 iowait 硬中断 软中断 虚拟化
第四行:
内存相关:总共内存大小 剩余内存大小 已使用内存大小 buff/cache 缓存
第五行:
swap相关:总共swap大小 剩余swap大小 已使用swap大小 可用的内存大小
着重简单描述一下一些概念:
僵尸进程:父进程已退出,子进程仍在运行,占用cpu和内存资源,对系统有较大危害
硬中断(hi,Hard Interrupt):由硬件产生,每个硬件在系统中有一个中断号,在后面讲cpu调优的时候再详细讲到。
软中断(si,Soft Interrupt):由软件产生,一般在程序交互特别复杂的时候,会产生软中断,代表一个程序在运行的时候被另外一个程序中断了。
那么在top 视图中,有很多快捷键可供使用:
1、常用的有数字1 键,可以列出所有cpu的使用情况;
2、按字母c 键,可以显示command 列详细信息
默认这个界面每5 秒钟刷新一次,如果你希望刷新的频率更高一些,可以通过 -d 选项指定,例如每2 秒刷新一次:
-n 选项可以指定次数,达到指定次数自动结束运行。
free命令
常用选项:
-m: 以MB 为单位显示
-g:以GB 为单位显示
-h:以人类易读的方式显示
total:总大小
used: 已使用大小
free:剩余大小
shared:进程间共用内存大小
buff/cache:读缓存,数据读取加速用的
available:可用剩余内存空间(free + buff/cache)
buff/cache 缓存可以通过这条命令释放:
有时候我们想查一下打开一个应用程序需要消耗多少内存,比如说火狐浏览器:
产生一个pid:10663
用pmap 命令查看:
最后一行total:换算过来差不多是2G
难以置信,打开一个火狐浏览器用了2G内存。
上面是打开一个火狐浏览器调用了哪些文件,每个文件占用的内存是多少,这些全部加在一起就是2G
火狐关闭,查看内存:
重新打开:
大概used 新增了一百多兆。
但为什么用pmap 查询会用了2G呢?
看pid 为11082 那行,2083736 是虚拟内存(VSZ),229532(RSS) 是真实的物理内存,这表示打开火狐浏览器需要2G内存,但真实情况是我们只为它分配了两百多兆。
这类似于虚拟化平台中磁盘的精简模式,等实际需要用更多的时候再分配。
一个应用程序运行时,需要多少内存,我们用:
这两条命令都可查看。
也可以通过:
这里有一个字段system 的in 和cs ,是之前没有出现过的,表示的是:
in:每秒钟进程的中断次数,包含时间
cs:每秒钟进程的上下文切换时间
如果看到这两个值很大,说明有大量的进程在交互。
还有一个pidstat 命令,可以看到每个进程使用cpu的情况:
mpstat 命令可以查看每一块cpu 的使用情况:
-P 选项指定cpu 的编号,从0 开始,ALL 表示所有的cpu
调优工具
很多初学者,不知道如何对系统调优,红帽官方提供了一个工具:tuned
RHEL 8 默认是已安装的,而且服务是开启的。
系统自带的调优方案在这个路径:
列出方案和使用场景:
每个方案里面都有一个配置文件,里面包含有默认调优参数:
我们可以根据自己的需要来调优,但是对于初学者,很多不知道怎么调,可以通过tuned-adm 命令一键调优。
常用的命令有:
那么,这样瞬间就会让方案里面的调优参数生效。比如:
关于tuned.conf ,可以查看帮助文档:
调优方法
在没有这个工具以前, 我们对系统调优,有几种方法:
1、我们系统当中有一个文件夹,/proc/sys,这里面有很多调优参数,比如说我们要开启ip转发或调整一些网络参数,它都是在/proc/sys/net 这个目录里面,调整文件系统的在/proc/sys/fs ,前面用过的buff/cache 缓存清理在/proc/sys/vm。
那系统当中一共有多少个这样的参数呢?
有955 个参数。
那我们过滤一下ip_forward:
一般来说,以前的系统调优我们会这样做:
修改以后,执行一个命令使之生效:
其实这个内核参数,它的完整路径在:
你也可以进到这里,直接修改这个文件:
这样就会立即生效:
但是,你希望下次开机的时候也立即生效怎么办呢?
仍然是写到/etc/sysctl.conf 文件中来。
所以/etc/sysctl.conf 默认就是对/proc/sys 中的文件做修改,因此net.ipv4.ip_forward 前面的/proc/sys 目录前缀可以不用写。
当然其实也可以写到/etc/sysctl.d/ 这个目录下,文件名以 .conf 结尾。
这样,下次开机的时候系统就会读取这个配置文件,使之生效。
如果我想让它立即生效,就执行:
我想查询当前内存中正在生效的值,例如:
这是一种调优方法。
在以前,还有一种方法是写开机脚本。
如果我们希望下次开机生效,会在下面这个目录中写开机脚本:
不过,今天在新版系统里面,已经很少提到这种方法了。
因为写到这个文件里面,属于开机脚本,开机的时候会读到,我们以前经常会把开机要生效的功能写到这个文件。这有一个问题,比如说:
我们要调整这样一个功能,但下次开机就不生效了,因为进程ID会变化,下次很有可能就不是1658 了,以前我们的做法就是写到开机脚本里面,类似于这样:
下次开机会生效。但是这样做有一个问题:
如果我当前把这个服务重启一下:
进程id 就发生变化,这个时候再来看,我们调的15 就不再生效了。
为了解决这个问题,从RHEL 7 开始,我们就很少写开机脚本了。
现在我们会在服务的配置文件里面修改:
这个文件里面是可以放脚本的,后面会讲到。
那这样,不论你怎样重启服务,下次仍会生效。
所以,以前的那些调优方法,现在都不怎么用了。
虽然,/etc/sysctl.conf 这个文件还在用,下次开机也能生效,但是,如果我们改变了某一个调优属性,可能下次它就不生效了。
现在,我们把它放到这个文件里面了,比如:
那我们把上面提到的调优参数写到这里:
这样它就生效了。
我们接下来写一个脚本:
接下来,模仿上面的内容来写:
新增:
现在我们进到/tmp 看一下,没有任何文件:
这样就生效了。
如果没有生效,可以读一下这个日志:
那么在工作中,可以把我们要调的参数,全部写成一个集合,执行一下这个集合,所有的功能就都生效了,下次我想要修改,也很方便。
或者你也可以这样:
这一段就是它的描述,改成这样:
即使重启,开机后也还是会生效。
持续更新中...