内存管理及调优

RH442 - 性能调优学习笔记(八)_内存管理及调优

32 位系统最大内存寻址空间为2^32=4GiB,64 位系统原则上最大内存寻址空间为2^64=64EiB,几乎没有内存空间限制,然后根据操作系统内核版本的不同,在RHEL 8 中,最大内存寻址空间是8TiB,其他64 位操作系统版本可能有支持最大寻址空间是256TiB 的,目前 257TiB - 16EiB 这段空间预留未开发。

ps aux 命令显示的列中,有两个参数,一个是VSS,表示进程申请的虚拟内存空间大小, 一个是RSS,表示实际为进程分配到的内存空间大小,原则上,如果不对进程做限制,它可以申请到系统所有的内存空间。

cat /proc/cpuinfo
  • 1.

RH442 - 性能调优学习笔记(八)_内存管理及调优_02

RHEL 8 内核支持最多申请8TiB 物理内存,最多256TiB 虚拟内存。

内存地址的分配是由CPU 的MMU(内存管理单元)管理和分配的,管理物理内存到虚拟内存的映射。

虚拟内存是线性的连续的地址空间,而物理内存空间可能并不连续,它是按需分配的。

RH442 - 性能调优学习笔记(八)_笔记_03

打开一个火狐浏览器:

firefox &
  • 1.

查看火狐浏览器申请了多少内存:

pmap $(pidof firefox)
  • 1.

RH442 - 性能调优学习笔记(八)_笔记_04

这里看到申请的内存差不多是3G,这并不是物理内存空间,而是虚拟内存空间,物理内存空间是按需分配的。

total 这一行的上面,每一行是打开火狐浏览器这个进程所需要调用的文件,每一个文件所需要消耗的内存空间。

RH442 - 性能调优学习笔记(八)_内存管理及调优_05

实际分配了大约250M 内存空间。

RH442 - 性能调优学习笔记(八)_笔记_06

仔细观察上面pmap 命令显示的结果会发现,每一个被调用的文件所占用的内存空间大小都是4 的整数倍,这是因为内存是有最小分配单元的,叫做PageSize(页大小),在x86 架构的系统上,默认是4KiB,在ARM 架构的处理器上,可能是64KiB

getconf -a | grep -i pagesize
  • 1.

RH442 - 性能调优学习笔记(八)_笔记_07

RH442 - 性能调优学习笔记(八)_内存管理及调优_08

RH442 - 性能调优学习笔记(八)_笔记_09

RH442 - 性能调优学习笔记(八)_内存管理及调优_10

buff/cache 是用来提升读性能的,脏页是用来提升写性能的。

vm.dirty_expire_centisecs 是脏页回收时间,单位是百分之一秒,3000就是30 秒,每隔30秒回收一次脏页。

vm.dirty_ratio 是脏页回收比例,很多中文翻译也叫水位值,脏数据大小超过内存剩余空间30% 开始回收脏页;

vm.dirty_writeback_centisecs 是脏页回收的检测时间,单位也是百分之一秒,500 就是5秒,每隔5秒检测一次脏页是否需要回收。

vm.dirty_bytes 是可以指定具体脏页数据达到多大空间开始回收,这里等于0 表示不关心这个参数。

vm.dirty_backgroud_ratio 这里等于10,表示某一个程序的脏数据达到内存剩余可用空间的10% 开始回收。

vm.dirty_backgroud_bytes 可以指定某一个程序脏数据具体达到多大空间开始回收,这里等于0 表示不关心这个参数。

sysctl -a | grep -i dirty >> /etc/sysctl.conf
vim /etc/sysctl.conf
  • 1.
  • 2.

RH442 - 性能调优学习笔记(八)_内存管理及调优_11

sysctl -p
  • 1.

调整到某个程序脏数据达到内存空间的5%就开始回收。

RH442 - 性能调优学习笔记(八)_笔记_12

dd if=/dev/urandom of=/dev/vdc
  • 1.

这个命令会生成大量的随机数,写入/dev/vdc 设备,执行过程中特别消耗内存脏页。

现在执行这条命令的主机内存是4G,现在来观察脏数据大小,应该到了10% (大约200M,实际肯定小于200)就会开始回收:

RH442 - 性能调优学习笔记(八)_笔记_13

RH442 - 性能调优学习笔记(八)_内存管理及调优_14

差不多到170M 就开始回收了。

当内存紧张时,更倾向于释放cache,还是倾向于保留cache(使用swap),读IO 很随机时,建议尽量保留cache

sysctl -a | grep swapp
  • 1.

RH442 - 性能调优学习笔记(八)_笔记_15

取值范围是0-100,默认是60,这是被调优过的。

RH442 - 性能调优学习笔记(八)_笔记_16

如果设置为0,表示在内存不足时更倾向于清理缓存释放空间;

如果设置为100,表示在内存不足时更倾向于保留缓存,使用swap空间。

很多程序调优时建议把这个值设置为0,因为使用swap 空间会让程序变得很卡顿。

RH442 - 性能调优学习笔记(八)_笔记_17

sysctl -a | grep overcomm
  • 1.

RH442 - 性能调优学习笔记(八)_笔记_18

vm.overcommit_kbytes 表示可过量分配的内存具体是多少,通常不做设置,为0 表示不关心这个参数;

vm.overcommit_memory 可以设置三个值,分别是0/1/2,为0 表示总是尝试过量分配,也可以说是尽可能地分配;为1 表示无脑过量分配,要多少给多少,哪怕是系统崩溃;为2 表示可过量分配的内存是RAM+swap 空间的总和 乘以一个百分比,百分比是由vm.overcommit_ratio 这个参数控制的,现在这个值是0,为0 或1 时不关心vm.overcommit_ratio 这个参数的值,只有为2 时才关心。

RH442 - 性能调优学习笔记(八)_内存管理及调优_19

过量分配可能会导致内存溢出。

一旦内存溢出,就会触发OOM Killer 结束系统中的一些进程,用于缓解内存紧张,有可能会结束一些关键进程,可以设置保护哪些进程不被OOM Killer 结束。

systemctl enable vsftpd --now
netstat -tulnp | grep 21
  • 1.
  • 2.

RH442 - 性能调优学习笔记(八)_内存管理及调优_20

进程ID 是 26730

cd /proc/26730
cat oom_adj
cat oom_score
  • 1.
  • 2.
  • 3.

RH442 - 性能调优学习笔记(八)_笔记_21

RH442 - 性能调优学习笔记(八)_笔记_22

每一个进程这里会有oom 的值,adj 是调整的意思,score 类似于票数的意思,每个进程都有这两个值,默认情况是0,也可能不是0

oom_adj:取值范围是 -17 ~ 15,数字越小,优先级越高,被kill 的概率越小,反之被kill 的概率越大。

echo 15 > oom_adj
  • 1.

RH442 - 性能调优学习笔记(八)_内存管理及调优_23

cat oom_score
  • 1.

RH442 - 性能调优学习笔记(八)_笔记_24

RH442 - 性能调优学习笔记(八)_笔记_25

RH442 - 性能调优学习笔记(八)_内存管理及调优_26

RH442 - 性能调优学习笔记(八)_笔记_27

RH442 - 性能调优学习笔记(八)_笔记_28

可以看到oom_score 的值是随着oom_adj 的值自动变化的。

RH442 - 性能调优学习笔记(八)_笔记_29

但是如果设置为 -17,oom_score 的值还是0,虽然显示为0,但是优先级还是比0 要高的,也就是相比于oom-adj 值为0 的进程优先被保护。

RH442 - 性能调优学习笔记(八)_内存管理及调优_30

调到最大。

这样设置是临时生效的,如果想要永久生效可以用写systemd 服务的方法,具体不展开。

安装一下内核帮助文档,我们使用内核自带的功能模拟内存溢出场景:

yum -y install kernel-doc
cd /usr/share/doc/kernel-doc-4.18.0/
grep -irn sysrq-trigger
  • 1.
  • 2.
  • 3.

RH442 - 性能调优学习笔记(八)_笔记_31

cd Documentation/admin-guide/
vim sysrq.rst
  • 1.
  • 2.

RH442 - 性能调优学习笔记(八)_内存管理及调优_32

RH442 - 性能调优学习笔记(八)_内存管理及调优_33

tail -f /var/log/messages
  • 1.
echo f > /proc/sysrq-trigger
  • 1.

RH442 - 性能调优学习笔记(八)_笔记_34

RH442 - 性能调优学习笔记(八)_内存管理及调优_35

vsftpd 进程被OOM Killer 结束了。

RH442 - 性能调优学习笔记(八)_笔记_36

在实验过程中,发现有一个服务进程sssd_nss 被kill 之后立刻自动重启。

这个故障自愈的效果是怎么实现的呢?

RH442 - 性能调优学习笔记(八)_笔记_37

它的服务配置文件里面有这一行,以后自己用systemd 管理别的服务也可以写这一行来实现故障自愈的功能。

sysctl -a | grep shm
  • 1.

RH442 - 性能调优学习笔记(八)_内存管理及调优_38

我们在安装数据库的时候,经常会有一些这样的设置。

shm 是share memory(共享内存)的缩写。

RH442 - 性能调优学习笔记(八)_笔记_39

kernel.shmmni 系统一共可以运行4096 个进程,每个进程最大可以使用kernel.shmmax 的共享内存。

kernel.shmall 系统一共可以分配多少空间给共享内存,单位是页。

共享内存是用来做进程间通讯,多个进程间需要共享内存。

RH442 - 性能调优学习笔记(八)_笔记_40

RH442 - 性能调优学习笔记(八)_笔记_41

RH442 - 性能调优学习笔记(八)_内存管理及调优_42

RH442 - 性能调优学习笔记(八)_内存管理及调优_43

RH442 - 性能调优学习笔记(八)_内存管理及调优_44

算出来这个值,案例中设置的是64G

上面是内存溢出,下面讲的是内存泄露。

内存泄露:由于应用程序开发出现bug,导致应用程序在关闭后,不能完全释放内存,windows 系统经常出现这个问题,随着计算机运行时间越来越久,内存泄露的空间越来越多,系统越来越卡顿,甚至死机,解决方案就是重启。

从运维的角度看,我们没有办法解决内存泄露的问题,只能检测。

有一个专门的工具,可以检测内存泄露的问题,叫valgrind

RH442 - 性能调优学习笔记(八)_笔记_45

yum -y install valgrind
  • 1.

比如说,检测一下ls 程序:

valgrind --tool=memcheck ls
  • 1.

RH442 - 性能调优学习笔记(八)_内存管理及调优_46

这个肯定是没有内存泄露的。

valgrind --tool=memcheck ./bigmem 256M
  • 1.

RH442 - 性能调优学习笔记(八)_内存管理及调优_47

bigmem 这个程序有内存泄露的问题。

valgrind --tool=memcheck --leak-check=full ./bigmem 256M
  • 1.

RH442 - 性能调优学习笔记(八)_内存管理及调优_48

这样大概能定位到造成内存泄露的原因。

RH442 - 性能调优学习笔记(八)_笔记_49

RH442 - 性能调优学习笔记(八)_笔记_50


RH442 - 性能调优学习笔记(八)_内存管理及调优_51

UMA 架构:一致性内存内存访问,CPU 通过FSB(前端总线)与内存交换数据,FSB 可能成为性能瓶颈。

RH442 - 性能调优学习笔记(八)_笔记_52

NUMA:非一致性内存访问,把某几个CPU 和某几条内存放在一个NUMA Node 里面,交换数据的时候尽可能在一个NUMA Node 里面进行,当这个NUMA Node 里面资源不够,它可以通过QPI(快速互联通道)去其他NUMA Node 获取资源,这种架构可以有效减少CPU 访问内存的总线开销,NUMA Node 之间是全互联的(两两之间互联)。

RH442 - 性能调优学习笔记(八)_内存管理及调优_53

如今大部分服务器都支持NUMA 架构,但不一定是有这么多NUMA Node

RH442 - 性能调优学习笔记(八)_内存管理及调优_54

这是华为的虚拟化平台FusionCompute,这里有一个开关,叫做虚拟机NUMA 结构自动化调整,这个功能打开意味着虚拟机开机的时候尽量给它分配在同一个NUMA Node 里面的CPU 和内存资源,但这样做有一个缺点:无法做内存复用。

RH442 - 性能调优学习笔记(八)_笔记_55

RH442 - 性能调优学习笔记(八)_笔记_56

这个实验有条件最好在物理服务器上做,红帽教室环境用的是kvm/qemu虚拟机,本来是没有办法做的,官方内置了脚本可以用来模拟:

lab memtuning-numa start
  • 1.

RH442 - 性能调优学习笔记(八)_内存管理及调优_57

ssh root@servera
vim /etc/default/grub
  • 1.
  • 2.

RH442 - 性能调优学习笔记(八)_内存管理及调优_58

其实就是在这里加了参数。

yum -y install numactl
numactl --hardware
  • 1.
  • 2.

RH442 - 性能调优学习笔记(八)_内存管理及调优_59

上面有显示每一个node 分配的内存,size 是内存大小,free 是剩余内存大小,然后是node 与node 之间的距离,每一个node 与node 之间的距离都是10,可以理解为总线开销,这是模拟出来的NUMA Node,如果是物理机,一般node 两两之间距离不是相等的,比如node0 到node 0 距离是10,node0 到node 1 可能是20

RH442 - 性能调优学习笔记(八)_内存管理及调优_60

使用bigmem 申请128M 内存,暂不退出:

bigmem 128M
  • 1.

查看bigmem 运行在哪些numa node 上:

numastat -c bigmem
  • 1.

RH442 - 性能调优学习笔记(八)_内存管理及调优_61

看Private 那一行,只有Node 0 和Node 1 这两列数字为非0,运行在Node 0 和Node 1 上了。

bigmem 512M
numastat -c bigmem
  • 1.
  • 2.

RH442 - 性能调优学习笔记(八)_内存管理及调优_62

bigmem 1024M
numastat -c bigmem
  • 1.
  • 2.

RH442 - 性能调优学习笔记(八)_笔记_63

指定运行在Node 1 上:

numactl --membind 1 -- bigmem 512M
numastat -c bigmem
  • 1.
  • 2.

RH442 - 性能调优学习笔记(八)_笔记_64

numactl --membind 1 -- bigmem 1024M
numastat -c bigmem
  • 1.
  • 2.

RH442 - 性能调优学习笔记(八)_内存管理及调优_65

申请了1024M 内存,系统还是尽可能地分配了,但实际上Node 1 只有762 M 的内存资源。

numactl --membind 0,1 -- bigmem 1024M
numastat -c bigmem
  • 1.
  • 2.

RH442 - 性能调优学习笔记(八)_笔记_66

指定程序可以运行在所有的NUMA Node 里面:

numactl --interleave all -- bigmem 1024M
numastat -c bigmem
  • 1.
  • 2.

RH442 - 性能调优学习笔记(八)_笔记_67

在系统中,用df 命令,你会经常看到tmpfs 这个设备:

RH442 - 性能调优学习笔记(八)_内存管理及调优_68

RH442 - 性能调优学习笔记(八)_笔记_69

这都是内存中的数据,1.9G 刚好是系统内存空间的一半,默认系统会分配一半的内存空间给tmpfs 设备。

上面有/dev/shm 这个挂载点,相当于把内存空间挂载到这里了。

RH442 - 性能调优学习笔记(八)_笔记_70

这里面什么都没有。

swap:将硬盘当做内存用,内存紧张时会使用swap;

shm:将内存当磁盘用,提升性能。

比如典型的服务 squid,叫做代理服务器,用在web 网站,提升网站的响应速度。

RH442 - 性能调优学习笔记(八)_笔记_71

对比写入速度差异明显。

因为是内存中的数据,重启以后就丢失了。

RH442 - 性能调优学习笔记(八)_笔记_72

yum -y install squid
setenforce 0
vim /etc/squid/squid.conf
  • 1.
  • 2.
  • 3.

RH442 - 性能调优学习笔记(八)_内存管理及调优_73

这里有一行配置,默认是注释的,这是配置一个缓存目录,最多占用100M的空间,生成16 个一级目录,每个一级目录里面生成256 个二级目录。

RH442 - 性能调优学习笔记(八)_内存管理及调优_74

下面这条命令是把两个挂载点相关联,相当于往/var/spool/squid 里面读写数据是往/dev/shm 里面读写:

mount --bind /dev/shm /var/spool/squid
  • 1.

RH442 - 性能调优学习笔记(八)_内存管理及调优_75

systemctl restart squid
cd /var/spool/squid
  • 1.
  • 2.

RH442 - 性能调优学习笔记(八)_内存管理及调优_76

RH442 - 性能调优学习笔记(八)_笔记_77

RH442 - 性能调优学习笔记(八)_笔记_78

如果我想把shm 目录的空间进行调整,下面这样操作:

RH442 - 性能调优学习笔记(八)_笔记_79

vim /etc/fstab
  • 1.

RH442 - 性能调优学习笔记(八)_内存管理及调优_80

mount -o remount /dev/shm
df -h
  • 1.
  • 2.

RH442 - 性能调优学习笔记(八)_内存管理及调优_81

RH442 - 性能调优学习笔记(八)_笔记_82

RH442 - 性能调优学习笔记(八)_笔记_83

PTE:记录虚拟内存 --- 物理内存映射关系

CPU MMU:内存管理单元负责映射

TLB:映射表提供缓存  hugepage 大页

系统为应用程序分配虚拟内存,实际在物理内存分配的时候要预留一部分空间,用于缓存和映射表之类的,物理内存到虚拟内存的映射是由cpu 的MMU(内存管理单元)实现的,当应用程序打开的时候,一个映射表就产生了,应用程序关闭,映射关系就解除了,下次打开这个应用程序又要重新生成映射,这会增加cpu 的计算开销,所以为了提升性能,我们可以把物理内存到虚拟内存的映射表缓存下来,这个技术叫做TLB

注意:内存有页、大页之分

page size:页大小 4KiB

hugepage size:大页大小 2MiB

cat /proc/meminfo
  • 1.

RH442 - 性能调优学习笔记(八)_笔记_84

系统默认没有分配大页。

大页必须是一片连续的地址空间,且不能被应用程序所申请。

sysctl -a | grep huge
  • 1.

RH442 - 性能调优学习笔记(八)_内存管理及调优_85

这个参数值是个数,默认0个,表示不分配大页。

RH442 - 性能调优学习笔记(八)_内存管理及调优_86

分配大页内存之前的状态。

echo vm.nr_hugepages >> /etc/sysctl.conf = 100
sysctl -
  • 1.
  • 2.

把它改为100,即分配100*2M = 200M 的大页内存。

RH442 - 性能调优学习笔记(八)_内存管理及调优_87

分配之后。

RH442 - 性能调优学习笔记(八)_笔记_88

bigmem 程序可以测试申请大页:

bigmem -h
  • 1.

RH442 - 性能调优学习笔记(八)_笔记_89

RH442 - 性能调优学习笔记(八)_笔记_90

RH442 - 性能调优学习笔记(八)_内存管理及调优_91

RH442 - 性能调优学习笔记(八)_内存管理及调优_92

申请了50M,分配了25个,所以剩余75 个。

RH442 - 性能调优学习笔记(八)_笔记_93

不是所有的应用程序都可以调用大页,需要代码支持。

RH442 - 性能调优学习笔记(八)_内存管理及调优_94

需要程序包含mmap 的系统调用,否则不支持大页。

RH442 - 性能调优学习笔记(八)_内存管理及调优_95

如果应用程序不支持大页怎么办?而且手动分配大页其实一开始的时候我们也不知道应该分配多少。从RHEL 6.2 的内核开始,Linux 支持透明大页。

RH442 - 性能调优学习笔记(八)_内存管理及调优_96

中括号里面的always 表示是启用了透明大页,如果是never 就是没有启用。

透明大页默认是启用的,某些场景可能出现内存使用异常。

出现内存使用异常的时候,就要考虑是不是透明大页导致的,上图是临时解决方法,如果想要永久生效,可以通过写tuned 配置文件实现。

RH442 - 性能调优学习笔记(八)_内存管理及调优_97

这个案例,要解决这个问题,需要在宿主机上开启”内存气泡“功能,也有叫“内存气球”的,自动回收内存空间,需要安装virio balloon 驱动,红帽的RHEV(企业版KVM 虚拟化)用的驱动其实就是开源社区ovirt 的驱动,可以访问ovirt 官网下载这个驱动,然后在KVM 虚拟机配置文件里面加入相关配置,重启该虚拟机后生效,具体不展开了。

 http://www.ovirt.org/

RH442 - 性能调优学习笔记(八)_笔记_98

RH442 - 性能调优学习笔记(八)_笔记_99

RH442 - 性能调优学习笔记(八)_内存管理及调优_100

swap 分区挂载的时候是可以指定优先级的

RH442 - 性能调优学习笔记(八)_笔记_101

现在系统中有两个swap 分区,挂载的时候加一个pri 优先级参数,都指定为2

RH442 - 性能调优学习笔记(八)_内存管理及调优_102

当优先级一样的时候,会怎么工作呢?

RH442 - 性能调优学习笔记(八)_内存管理及调优_103

现在使用都为0

RH442 - 性能调优学习笔记(八)_笔记_104

RH442 - 性能调优学习笔记(八)_笔记_105

等待一段时间后,swap 使用的空间几乎是平均的。

优先级设置的意义,一个场景是跨硬盘的swap 分区,避免数据分散在不同的硬盘上影响性能。

 swap 分区的优先级数字越大,优先级越高。

RH442 - 性能调优学习笔记(八)_笔记_106

swapoff 命令卸载swap 分区的时候,如果里面的数据是有用的,不会丢失,会回写到内存。


持续更新中...