问题描述
第三方监控平台反馈业务库服务器(Oracle11.2.0.4 DG架构主节点)有虚拟内存超过警戒值80%,要求进行处理。


可以看到还有 1.1G 的空闲物理内存,但是系统已经开始使用 swap 了,初步判断是机器上面的程序内存需求比较大,但物理内存不够用所以开始使用 swap 来存储部分数据。
分析过程
数据库环境
操作系统:Centos7.6
数据库:Oracle 11.2.0.4
架构:DG架构
--操作系统版本
[root@opd ~]# cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)
--内存
[oracle@opd ~]$ free -g
total used free shared buff/cache available
Mem: 376 19 1.1G 176G 355G 178G
Swap: 15G 15G 516M
available 只是一个预估的值而已;有参考价值,不是硬指标
--cpu
80核
--数据库版本
[oracle@opd ~]$ sqlplus -v
SQL*Plus: Release 11.2.0.4.0 Productionsga+pga配置
sga+pga=256G+48G=304G 占用物理内存的80%,有些大了,以后要配置成占用物理内存50%至70%,避免出现swap利用率高的情况。
--sga+pga配置
SQL> show parameter sga
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
lock_sga boolean FALSE
pre_page_sga boolean FALSE
sga_max_size big integer 256G
sga_target big integer 256G
SQL> show parameter pga
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_target big integer 48G查看swap 的积极程度
查看swap配置
--查看swap配置
cat /etc/sysctl.conf | grep vm.swappiness
vm.swappiness = 10
[root@localhost ~]# cat /proc/sys/vm/swappiness
10
表示内存使用率超过100-10=90%时开始使用交换分区。
vm.dirty_ratio=20
vm.dirty_background_ratio=3
vm.dirty_writeback_centisecs=100
vm.dirty_expire_centisecs=500
vm.swappiness=10
vm.min_free_kbytes=524288查询占用了最多的swap
接下来要找出是哪些进程使用到了 swap。在 Linux 中,可以用 proc 文件系统来查看进程 swap 换出的虚拟内存大小,它保存在 /proc/pid/status 的 Vmswap 字段中。
但是一台服务器中有这么多进程,一个一个找太麻烦了,所以可以使用下面的命令来找出当前系统中 swap 占用最大的几个进程,并列出它们的进程号、进程名和 swap 大小。
--查询占用了最多的swap的前20个
[root@localhost ~]# for file in /proc/*/status ; do awk '/VmSwap|Name|^Pid/{printf $2 " " $3}END{ print ""}' $file; done | sort -k 3 -n -r | head -20
参数说明:
for file in /proc/*/status ; do ... done:这是一个 for 循环,它遍历了 /proc 目录下的所有子目录,每个子目录都包含一个名为 status 的文件,其中包含了该进程的一些状态信息。
awk '/VmSwap|Name|^Pid/{printf $2 " " $3}END{ print ""}' $file:对于每个 /proc/*/status 文件,awk 命令用于匹配 VmSwap、Name 或者 Pid 这几个关键字,并输出它们的值。这些关键字分别表示交换空间、进程名和进程号。
sort -k 3 -n -r:对输出的结果进行排序。-k 3 表示按第三列进行排序,即按照交换空间大小排序;-n 表示按照数字顺序排序;-r 表示逆序排序,即从大到小排序。
head -20 :输出排序后的前5行。输出如下:

从输出的结果可以看到,使用 swap 比较多的是oracle的归档进程,其他的3个为云平台监控软件。
查看使用swap最多的pid对应的进程

查看有30个正在运行的归档进程

top M : 按内存使用情况排序

top e

vmstat 查询

memory:
cache: 作为page cache的内存数量,一般作为文件系统的cache,如果cache较大,说明用到cache的文件较多;
IO:
bi 从块设备读入数据的总量(读磁盘)(每秒kb)
bo 块设备写入数据的总量(写磁盘)(每秒kb)
这里设置的bi+bo参考值为1000,如果超过1000,而且wa值较大应该考虑均衡磁盘负载,可以结合iostat输出来分析。
proc/meminfo

查看numa
说明现场没有关闭numa
[oracle@opd ~]$ cat /etc/default/grub
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto rhgb quiet"
GRUB_DISABLE_RECOVERY="true"
[oracle@opd ~]$ dmesg|grep -i numa
[ 0.000000] NUMA: Initialized distance table, cnt=1
[ 0.000000] NUMA: Node 0 [mem 0x00000000-0x7fffffff] + [mem 0x100000000-0x87fffffff] -> [mem 0x00000000-0x87fffffff]
[ 0.616122] pci_bus 0000:00: on NUMA node 0
[oracle@opd ~]$ cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-3.10.0-1160.el7.x86_64 root=UUID=7016924f-9a06-47c8-832a-7c438ccad342 ro crashkernel=auto rhgb quiet LANG=zh_CN.UTF-8查看透明页
发现现场没有关闭透明页
--查看透明页 always说明未关闭透明页
[oracle@opd ~]$ cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never
[oracle@opd ~]$ cat /sys/kernel/mm/transparent_hugepage/defrag
[always] madvise never检查hugepage配置


说明未配置大页。
检查用户shell limits相关配置文件

查看awr报告

会话数也不多


SGA使用了不到233G,按理说内存是应该够用的。因为没有使用HUGEPAGE,导致了大量的内存被PAGETABLE使用,所以导致了内存耗尽。同时这个系统的VM参数swapinessP配置是10,因此CACHE/BUFFER会占用部分内存。因此要优化这个系统的思路还是很清晰的,调整下面的参数,启用HUGEPAGE就可以了。

重启后系统一切恢复正常。通过检查meminfo文件:
解决办法
系统参数调整
关闭透明页
--关闭透明页
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
--加入开机自启动
echo '
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag' >> /etc/rc.local
chmod +x /etc/rc.local关闭numa
--修改 grub.conf
vi /boot/grub2/grub.cfg
--更改numa配置文件
[root@opd ~]# vi /etc/default/grub 添加numa=off
--重新生成配置文件/etc/grub2.cfg
grub2-mkconfig -o /boot/grub2/grub.cfg 用更改的文件重新生成 /boot/grub2/grub.cfg,重启生效
--重启操作系统
reboot更改 /etc/sysctl.conf
--增加如下参数
vi /etc/sysctl.conf
vm.swappiness=10
vm.min_free_kbytes=524288
vm.dirty_ratio=20
vm.dirty_background_ratio=3
vm.dirty_writeback_centisecs=100
vm.dirty_expire_centisecs=500
kernel.numa_balancing=0 
swap配置
--更改swap参数值
vi /etc/sysctl.conf
vm.swappiness = 1
--生效
sysctl -p
--查看
[root@localhost ~]# cat /proc/sys/vm/swappiness
1
表示内存使用率超过100-1=99%时开始使用交换分区。sga+pga配置
以后要配置成占用物理内存50%至70%,避免出现swap利用率高的情况。
关闭swap(不建议慎重)
关闭数据库
--一致性关库,保证数据都已写入磁盘上的文件里
sqlplus / as sysdba
shutdown immediate建议是在数据库一致性关库后再进行swap关闭操作。
在定位到是哪些进程使用 swap 比较高之后,找到对应的开发同事进行讨论,最后**决定把 swap 关掉。**通常来讲,降低 swap 的使用,可以提高系统的整体性能。
一方面是因为频繁地进行 swap 操作,会导致大量的磁盘读写操作,降低系统的响应速度和整体性能。
另一方面是因为频繁地将数据从内存交换到 swap 空间,并在需要时再次交换回来时,会增加 CPU 和内存的负担。
临时关掉 swap
只是临时关闭,如果机器重启是会重新开启 swap 的。网上有博主推荐使用该方法,我没敢采用,正在运行的正式业务库,担心缓存未同步到磁盘上导致数据丢失,不建议使用该办法。
--关闭当前正在使用的交换空间
[root@localhost ~]# swapoff -a
--看下 swap 空间是否已经关闭,如果输出为空则表示 swap 成功关闭。
[root@localhost ~]# cat /proc/swaps
永久关闭swap
编辑 /etc/fstab 文件,将其中关于 swap 的配置注释掉或者删除掉。如果机器后面要是重启了,swap 依旧是关闭状态。
# 找到以 swap 标识的行,然后注释
[root@localhost ~]# vim /etc/fstab
# /dev/mapper/centos-swap swap swap更改swap配置
--查看swap配置
[root@localhost ~]# cat /etc/sysctl.conf | grep vm.swappiness
vm.swappiness = 0
--生效
[root@localhost ~]# sysctl -p
--查看
[root@localhost ~]# cat /proc/sys/vm/swappiness
0
表示禁止使用交换分区————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/s_alted/article/details/136688163
对内核参数进行调整,将swappiness参数从默认的60改为0,告诉操作系统,尽量不要使用交换分区
参考链接:
http://www.linuxvox.com/2009/10/what-is-the-linux-kernel-parameter-vm-swappiness/
http://blog.yannickjaquier.com/linux/linux-hugepages-and-virtual-memory-vm-tuning.html
https://developer.aliyun.com/article/408214
https://blog.csdn.net/andyguan01_2/article/details/89315345
后续跟踪:
修改后观察一段时间,交换分区使用率低且并无大幅度增长情况出现!
补充
交换分区知识拓展
什么是 swap
swap 顾名思义指的是 Linux 上的交换分区,有点像 Windows 的虚拟内存,说白了就是把一块磁盘空间或者一个本地文件当成内存来使用。
在早期内存价格昂贵的时代,swap 的出现解决了物理内存不足导致无法运行程序的问题。
swap 包含换出和换入两个过程:
- 换出:把进程暂时不用的内存数据存储到磁盘中,并释放这些数据占用的内存。
- 换入:进程再次访问这些内存数据时,把它们从磁盘读到内存来。
那现在随着内存越来越便宜,服务器上面的内存也越来越大,swap 是不是就没啥作用了呢?
不是的,对于程序来说,内存再大也有不够用的时候。比如说内存不足的时候,有些程序不希望被 OOM 杀死,而是希望等待一段时间让人工来处理,或者等系统自动释放其他进程的内存之后再分配给它。
又比如常见的笔记本电脑的休眠和快速开机的功能确实是基于 swap 的。在休眠时,操作系统会将当前内存的状态保存到交换空间或者称为休眠文件中,然后关闭计算机。当再次开机时,系统可以直接从休眠文件中恢复内存状态,而不需要重新加载应用程序和初始化系统,从而实现了快速开机的功能。
在 Linux 中,/proc/sys/vm/swappiness 用来调整使用 swap 的积极程度。swappiness 的范围是 0-100,数值越大,越积极使用 swap。一般来讲默认值是 60 。
需要注意的是:这个范围是 swap 积极程度的权重,即使设置成 0,在某些情况下(例如进程可用内存耗尽了)还是会使用 swap 的。
交换分区的作用
系统管理和DBA都知道,在Linux和UNIX系统上都有一个SWAP分区,该分区,例似于于Windows系统上的虚拟内存。
当系统的物理内存不够用的时候,就需要将物理内存中的一部分空间释放出来,临时转移到SWAP上,供当前运行的程序提供物理内存空间,当程序需要再访问被转移到了SWAP空间上的数据时,再从SWAP中恢复到物理内存中。从此工作原理不难看出来,SWAP要有,但是尽量不要使用,使用了就会发生内存交换,必然影响系统性能。
swap设置问题
有经验的系统管理员和DBA,往往会给系统建设一个适中大小的SWAP大小,但实际生产系统中,也经常发现有一些,因为SWAP设置过小的原因,而导致物理内存、SWAP全部耗尽,导致DOWN机的情况;也有发现一因为SWAP设置太大太大而浪费必要的存储空间的情况,SWAP到底该设置多大,可以参考一下ORACLE官方的建议。
ORACLE官方建议swap设置标准
对于运行ORACLE数据库的操作系统,ORACLE官方是有设置大小建议的,在此以从ORACLE 12C R1官方文档中提取的建议大小为例:

(1)ORACLE官方要求最小1GB的RAM,建议2GB或更大
(2)SWAP与RAM的大小配置关系
- RAM为1-2GB时,SWAP大小建议为RAM大小的1.5倍
- RAM为2-16GB时,SWAP大小建议与RAM大小相等
- RAM大于16GB时,SWAP大小建议为16GB
影响swap利用率的参数说明
vm.swappiness参数说明
内核参数vm.swappiness控制换出运行时内存的相对权重,参数值大小对如何使用swap分区有很大联系。值越大,表示越积极使用swap分区,越小表示越积极使用物理内存。默认值swappiness=60,表示内存使用率超过100-60=40%时开始使用交换分区。swappiness=0的时候表示最大限度使用物理内存,然后才是 swap空间;swappiness=100的时候表示积极使用swap分区,并把内存上的数据及时搬运到swap空间。(网上有的说,对于3.5以后的内核和RedHat 2.6.32之后的内核,设置为0会禁止使用swap,从而引发out of memory,这种情况可以设置为1。)
需要根据服务器运行的程序类型,来设置不同的参数值。例如,对于Oracle一般设置为10;对于MySQL一般设置为1,尽可能不用swap分区。
调整vm.swappiness的方法
--查看参数值
cat /proc/sys/vm/swappiness
--临时调整
sysctl vm.swappiness = 10
cat /proc/sys/vm/swappiness
--永久调整
vi /etc/sysctl.conf
修改vm.swappiness=10
--加载参数
sysctl -p




