最近收到报警,某一个服务器的swap空间有些紧张,查看这台服务器上有两个备库数据库实例,当然负载还是很低的。但是目前来看,内存已经所剩无几,所以自然而然会用到swap,而且swap也看起来紧张了,从设计的角度来看,这种方式还是有很大的隐患,一旦需要切换,这台服务器还是很有可能出现oom-killer的情况,也就意味着宕机。所以从小从大来看这个报警都不能掉以轻心。
使用top查看的情况如下,可以看到swap已经很紧张了,剩余内存不到300M了。
top - 13:46:44 up 973 days, 3:00, 1 user, load average: 0.23, 0.16, 0.10
Tasks: 884 total, 1 running, 880 sleeping, 0 stopped, 3 zombie
Cpu(s): 0.9%us, 0.6%sy, 0.0%ni, 98.5%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 65923168k total, 65624684k used, 298484k free, 1256944k buffers
Swap: 33554424k total, 23177916k used, 10376508k free, 60284668k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
6821 oracle 20 0 16.2g 57m 53m S 9.9 0.1 3618:47 ora_rsm0_megdb
4768 oracle 20 0 40.9g 109m 94m S 1.3 0.2 18619:36 ora_dia0_tebdb2
查看当前服务器的数据库实例情况,如下,可以结合上面的情况可以看到SGA应该一个是40G,一个是16G.
[oracle@stepay2 ~]$ ps -ef|grep smon
oracle 4784 1 0 2013 ? 00:24:15 ora_smon_tebdb2
oracle 6738 1 0 2014 ? 00:13:26 ora_smon_megdb
oracle 20793 20706 0 13:47 pts/2 00:00:00 grep smon
进一步查看进行验证,tebdb2的SGA看似没有启用SGA的自动管理。
SQL> show parameter sga
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
lock_sga boolean FALSE
pre_page_sga boolean FALSE
sga_max_size big integer 41472M
sga_target big integer 0
查看megdb的SGA的情况,是使用了SGA的自动管理的。
SQL> show parameter sga
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
lock_sga boolean FALSE
pre_page_sga boolean FALSE
sga_max_size big integer 16G
sga_target big integer 16G
当然PGA也会消耗一些内存,但是这些消耗应该不会成为瓶颈,但是swap的消耗却很高。
为什么SGA+PGA的设置都在范围之内,但是swap却总是不够用呢。
这个时候查看共享内存段的情况,发现其中一个数据库实例40G的SGA貌似没有体现出来。
[oracle@stepay2 trace]$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 294912 oracle 640 4096 0
0x00000000 327681 oracle 640 4096 0
0x4ab8364c 360450 oracle 640 4096 0
0x00000000 1769475 oracle 640 100663296 67
0x00000000 1802244 oracle 640 17079205888 67
0xf6d1ab84 1835013 oracle 640 2097152 67
所以对于这种情况,一种改善思路就是开大页,从目前经历的绝大多数Linux系统来说,大页的设置应该是一个标配.当然Oracle官方也提供了相应的脚本。
我简单来说一下,脚本的思路首先是根据内核版本,目前支持2.4,2.6
[oracle@stepay2 trace]$ uname -r | awk -F. '{ printf("%d.%d\n",$1,$2); }'
2.6
然后得到一个page size的大小,也可以使用root权限通过getconf PAGESIZE来得到。
[oracle@stepay2 trace]$ grep Hugepagesize /proc/meminfo | awk {'print $2'}
2048
然后通过ipcs –m得到共享内存段的情况,然后根据共享内存段的数据来计算需要设置的大页内核参数设置。
[oracle@stepay2 trace]$ ipcs -m | awk {'print $5'} | grep "[0-9][0-9]*"
4096
4096
4096
100663296
17079205888
2097152
因为我们的环境是多实例,我们可以设定一个统一的值,比如我们需要设置50G左右的大页,就可以使用下面的公式进行计算。
MIN_PG=`echo "51200000000/(2048*1024)" | bc -q`
通过上面的公式就会输出最终建议的大页设置
[oracle@stepay2 trace]$ echo "51200000000/(2048*1024)" | bc -q
24414
对应的内核参数在内核2.6就是 vm.nr_hugepages=24414
简单的环境设置交代完毕,然后准备重启备库数据库实例,同时考虑到资源的使用情况,把原来40G的SGA调整为32G,然后把两个实例都停了之后,swap的使用率一下子降下来了。
Tasks: 821 total, 1 running, 817 sleeping, 0 stopped, 3 zombie
Cpu(s): 0.9%us, 0.4%sy, 0.0%ni, 98.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 65923168k total, 53194676k used, 12728492k free, 63904k buffers
Swap: 33554424k total, 32812k used, 33521612k free, 1694992k cached
然后我们重启,这个时候发现有一个数据库实例怎么都启动不了。
SQL> startup nomount
ORA-27102: out of memory
Linux-x86_64 Error: 28: No space left on device
一般根据经验这个错误主要都是因为内核参数设置的过小导致。
但是查看了下面的配置,没有发现问题。
kernel.shmmax = 68719476736
kernel.shmall=16777216
fs.aio-max-nr = 1048576
fs.file-max = 6815744
vm.nr_hugepages= 24414
对于这个问题着实感到奇怪,同时查看alert日志也没有看到任何大页开启的信息。为什么大页没有开启呢,而且数据库实例还启动不了。
这个可以从共享内存段的设置情况来做一个简单的佐证。
[oracle@stepay2 ~]$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 2260995 oracle 640 201326592 0
0x00000000 2293764 oracle 640 32010928128 0
发现其中一个设置为32G的共享内存空间已经被使用了,而且更加奇怪的是切换profile使用sqlplus还连接不到这个实例,可见这部分内存空间还没有通过ORACLE_SID和SGA建立映射关系。那么对于这部分缓存空间,可以手工进行清理。
[oracle@stepay2 ~]$ ipcrm -m 2293764
而为什么大页没有开启呢,这个时候反复验证,发现是启用了自动内存管理,明白了这点再来看这个问题一下子就有些恍然大悟了。把这台服务器上相关的服务都停了,然后手工清空了剩余的共享内存段。
[oracle@stepay2 ~]$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 2260995 oracle 640 201326592 0
[oracle@stepay2 ~]$ ipcrm -m 2260995
当然如果条件允许,最好重启一下,如果不能重启还是使用sysctl –p来设置内核参数生效。
然后再次重启就没有任何问题了。
[oracle@stepay2 trace]$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 3506176 oracle 640 100663296 67
0x00000000 3538945 oracle 640 16005464064 67
0xf6d1ab84 3571714 oracle 640 2097152 67
0x00000000 3637251 oracle 640 201326592 66
0x00000000 3670020 oracle 640 32010928128 66
0x4ab8364c 3702789 oracle 640 2097152 66
通过这个细小的案例,我们可以看到其实有些看似细小的警告,如果不加以重视,会逐渐演变为一个大问题。需要提前预警,提前处理。