[原]Oracle的SGA与系统vm.nr_hugepages不匹配导致的故障
2021年8月25日 13:40
•
linux专区
某项目,使用红旗DC Server 5.0 for x86_64 SP2,运行Oracle RAC 10.2.0.4。而应用服务器上的应用通过Oracle客户端来连接,为常连接的方式。当进行应用的压力测试时,发现数据库服务器在运行一段时间(约3个小时后),系统会失去响应。当做了大量的系统状态及内存使用情况的分析后,发现系统失去响应的原因是,Oracle不断的申请内存,直到内存消耗完所导致的。深究其原因,是由于系统的核心参数vm.nr_hugepages与SGA的大小不匹配,Oracle并没有使用HugePages来分配SGA,而是在不断的消耗系统其它内存。
一、故障现象 系统环境为:
引用
硬件: 4 x IBM x3950 M2 (两台堆叠 8 x Xeon E7420四核(共32个) 64G内存) 操作系统: 红旗 DC Server 5.0 for x86_64 SP2 应用: Oracle RAC 10.2.0.4
当进行应用压力测试时,发现系统可用内存不断减少,这是一个逐步表现的过程,可通过下面的ps命令间隔一段时间,观察Oracle的某进程对内存的占用是否不断增加:
引用
# ps aux|grep -w 3244 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND oracle 3244 0.2 1.2 30865100 792376 ? Ss May12 0:21 oraclepostdbs1 (LOCAL=NO) oracle 3244 0.2 1.2 30865100 838360 ? Ss May12 0:23 oraclepostdbs1 (LOCAL=NO) oracle 3244 0.2 1.3 30865100 902184 ? Ss May12 0:25 oraclepostdbs1 (LOCAL=NO)
系统快失去响应前,内存状态为:
引用
# free -m total used free shared buffers cached Mem: 63839 63415 423 0 1 16387 -/+ buffers/cache: 47026 16812 Swap: 16002 971 15030 #vmstat -k 2 procs ———–memory———- —swap– —–io—- –system– —-cpu—- r b swpd free buff cache si so bi bo in cs us sy id wa 25 0 991516 431400 788 16775636 54 0 59 1269 11004 21412 11 61 28 0 18 0 991444 431976 780 16775648 74 0 85 1551 13373 24064 10 49 42 0 10 0 991388 432848 780 16775200 50 0 117 2374 9521 23511 13 39 48 0
以上面的free显示为例,这里在核心中设置了核心的保留内存为400m:
引用
vm.min_free_kbytes=409600
可见,这时的系统可用内存已几乎消耗殆尽(上面设置的400m为核心保留,其它应用不能使用),并且,从vmstat可知,因物理内存不足,正在不断的进行页面交换,使用swap空间。由于正在进行压力测试,对系统的内存消耗压力很大,因此,从top状态,也会看到kswapd进程会一直占用CPU,以进行页面交换:
引用
May 9 08:02:19 gdracdb1 kernel: Node 0 HighMem per-cpu: empty May 9 08:02:19 gdracdb1 kernel: May 9 08:02:19 gdracdb1 kernel: Free pages: 18728kB (0kB HighMem) May 9 08:02:19 gdracdb1 kernel: Active:5925372 inactive:2669 dirty:62 writeback:0 unstable:0 free:4682 slab:60603 mapped:5925032 pagetables:6178345 May 9 08:02:19 gdracdb1 kernel: Node 0 DMA free:10472kB min:0kB low:0kB high:0kB active:0kB inactive:0kB present:16384kB pages_scanned:19479 all_unreclaimable? yes May 9 08:02:19 gdracdb1 kernel: protections[]: 0 0 0 May 9 08:02:19 gdracdb1 kernel: Node 0 Normal free:8256kB min:8280kB low:16560kB high:24840kB active:23701520kB inactive:10676kB present:68665344kB pages_scanned:0 all_unreclaimable? no May 9 08:02:19 gdracdb1 kernel: protections[]: 0 0 0 May 9 08:02:19 gdracdb1 kernel: Node 0 HighMem free:0kB min:128kB low:256kB high:384kB active:0kB inactive:0kB present:0kB pages_scanned:0 all_unreclaimable? no May 9 08:02:19 gdracdb1 kernel: protections[]: 0 0 0 May 9 08:02:19 gdracdb1 kernel: Node 0 DMA: 0*4kB 1*8kB 0*16kB 1*32kB 1*64kB 3*128kB 1*256kB 1*512kB 1*1024kB 0*2048kB 2*4096kB = 10472kB May 9 08:02:22 gdracdb1 kernel: Node 0 Normal: 20*4kB 4*8kB 5*16kB 2*32kB 27*64kB 1*128kB 0*256kB 0*512kB 0*1024kB 1*2048kB 1*4096kB = 8256kB May 9 08:02:22 gdracdb1 kernel: Node 0 HighMem: empty May 9 08:02:22 gdracdb1 kernel: Swap cache: add 87984, delete 87977, find 13381/15259, race 0+0 May 9 08:02:22 gdracdb1 kernel: Free swap: 16143224kB May 9 08:02:22 gdracdb1 kernel: 17170432 pages of RAM May 9 08:02:22 gdracdb1 kernel: 827519 reserved pages May 9 08:02:22 gdracdb1 kernel: 253602825 pages shared May 9 08:02:23 gdracdb1 kernel: 7 pages swap cached
若应用压力仍不停止,系统将没有内存供Oracle继续使用,系统失去响应的原因有两个:
引用
1、因物理内存不足,系统需由kswapd交换页面以腾出更多的可用物理内存,但swap使用的是磁盘,会给本来压力就大的CPU,增加更多的I/O负载,CPU idle几乎为0,无法响应; 2、因主要问题是供Oracle申请的物理内存不足,即使用swapoff取消swap,仍会因可用内存不足,系统无法响应情况。
二、问题分析 经过多次的测试和分析(可参考附录),最后发现,问题原因与Oracle上设置的SGA大小、系统的vm.nr_hugepages有关。 这里,Oracle的SGA值为30000M:
引用
SQL> show parameter sga;
NAME TYPE VALUE ———————————— ———– —————————— lock_sga boolean FALSE pre_page_sga boolean FALSE sga_max_size big integer 30000M sga_target big integer 30000M
从系统top命令发现,oracle的申请的虚拟内存是29.4G(接近30000M),而Oracle启动后,多个oracle进程的常驻内存在不断的增加,故怀疑其使用的并不是SGA申请的内存:
引用
# top
top – 17:47:48 up 1 day, 3:35, 5 users, load average: 0.27, 0.25, 0.16 Tasks: 444 total, 1 running, 443 sleeping, 0 stopped, 0 zombie Cpu(s): 0.3% us, 0.2% sy, 0.0% ni, 99.3% id, 0.0% wa, 0.0% hi, 0.1% si Mem: 65371656k total, 5973772k used, 59397884k free, 213504k buffers Swap: 16386292k total, 0k used, 16386292k free, 4542984k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 8424 oracle -2 0 29.4g 326m 311m S 2 0.5 0:59.87 oracle 8428 oracle -2 0 29.4g 329m 314m S 2 0.5 1:00.30 oracle 8432 oracle -2 0 29.4g 328m 313m S 1 0.5 1:00.32 oracle 8436 oracle -2 0 29.4g 326m 311m S 1 0.5 1:00.85 oracle 8440 oracle -2 0 29.4g 323m 308m S 1 0.5 1:00.50 oracle 1419 root 16 0 522m 28m 9748 S 1 0.0 0:48.14 crsd.bin 8416 oracle -2 0 29.4g 321m 306m S 1 0.5 0:59.69 oracle 8420 oracle -2 0 29.4g 329m 314m S 1 0.5 0:59.47 oracle 8444 oracle -2 0 29.4g 320m 305m S 1 0.5 0:59.96 oracle 23551 oracle 16 0 6412 1288 772 R 1 0.0 0:00.08 top 1453 oracle RT 0 238m 224m 23m S 0 0.4 0:47.41 ocssd.bin 8476 oracle 16 0 29.4g 64m 60m S 0 0.1 0:02.12 oracle 8860 oracle 16 0 29.4g 64m 58m S 0 0.1 0:01.47 oracle 1 root 16 0 4752 552 460 S 0 0.0 0:03.19 init
根据这份Oracle 11g的资料:H Very Large Memory on Linux,在如此大内存的环境中(64G),系统核心参数vm.nr_hugepages 的大小与Oracle 上设置的SGA是相关的。 而默认情况下,vm.nr_hugepages 是没有设置的,其大小为0。
引用
# cat /proc/meminfo |grep Huge HugePages_Total: 0 HugePages_Free: Hugepagesize: 2048 kB
三、解决问题 1、配置合适的vm.nr_hugepages 值 参考H Very Large Memory on Linux提供的一个vm.nr_hugepages 建议值计算脚本。 本地下载:
下载文件
点击这里下载文件
在已设置好SGA大小及相关参数的情况下,先启动Oracle,然后运行脚本:
引用
# ./hugepages_settings.sh Recommended setting: vm.nr_hugepages = 15067
※ 注意: 使用该脚本时,必须先设置好SGA,并启动Oracle,待内存申请稳定后才运行。否则,其中用到的ipcs -m所获取的值并不准确。
把该参数加入/etc/sysctl.conf中,然后重启系统:
该值必须重启系统才能生效。
2、配置oracle用户的memlock 修改/etc/security/limits.conf文件,加入:
引用
# cat /etc/security/limits.conf|grep lock # – memlock – max locked-in-memory address space (KB) # – locks – max number of file locks the user can hold oracle soft memlock 30857216 oracle hard memlock 30857216
计算公式为:>=HugePages_Total×1024,这里设置了2倍:15067*1024*2 = 30857216。 重新登录到oracle用户,用ulimit -l 可看到该值。
最后,重新运行Oracle:
# srvctl stop instance -d postdbs -i postdbs1 # srvctl start instance -d postdbs -i postdbs1
从top观察,可看到oracle运行后,会启动一个oracle进程逐步申请内存,直到SGA的大小:
引用
# top
top – 18:12:50 up 12 min, 1 user, load average: 0.21, 0.47, 0.43 Tasks: 406 total, 1 running, 405 sleeping, 0 stopped, 0 zombie Cpu(s): 0.2% us, 0.1% sy, 0.0% ni, 99.6% id, 0.0% wa, 0.0% hi, 0.1% si Mem: 65371656k total, 34944692k used, 30426964k free, 127376k buffers Swap: 16386292k total, 0k used, 16386292k free, 350956k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 22100 oracle -2 0 29.4g 29g 29g S 2 47.0 0:06.28 oracle 22116 oracle -2 0 29.4g 29g 29g S 1 47.0 0:06.36 oracle 22090 oracle -2 0 29.4g 29g 29g S 1 47.0 0:05.99 oracle 22096 oracle -2 0 29.4g 29g 29g S 1 47.0 0:06.20 oracle 22104 oracle -2 0 29.4g 29g 29g S 1 47.0 0:06.23 oracle 22108 oracle -2 0 29.4g 29g 29g S 1 47.0 0:06.23 oracle 22112 oracle -2 0 29.4g 29g 29g S 1 47.0 0:06.30 oracle 22120 oracle -2 0 29.4g 29g 29g S 1 47.0 0:06.24 oracle
从/proc/meminfo也可观察到已经在使用HugePages:
引用
# cat /proc/meminfo |grep Huge HugePages_Total: 15067 HugePages_Free: 3 Hugepagesize: 2048 kB
oracle使用的HugePages大小为:(15067-3)*2048 = 30851072 KB 。 再经压力测试,从top、ps aux、free等可看到Oracle的进程使用的内存是固定的(从SGA中申请),在没有额外操作的情况下,系统可用内存处于一个稳定值(这里使用ASM文件系统,故对ASM的磁盘I/O也会由SGA分配,系统cached值不大,free值较大),问题解决。
三、注意事项 1、SGA与vm.nr_hugepages的关系 设置vm.nr_hugepages 时必须注意,该值不能比SGA小 ,否则仍会发生上述的故障问题。我曾经参考这个链接:点击,根据其中的公式:
引用
nr_hugepages>=sga(mb)/Hugepagesize(mb)
把vm.nr_hugepages 设置为:30*1024/2 = 15360 ,但是后来启动Oracle后,发现仍存在故障。最后,发现原来是设置SGA时,把SGA设置为了30G(不是30000M):
引用
SQL> alter system set sga_target=30G scope=spfile sid=’postdbs1′; SQL> alter system set sga_max_size=30G scope=spfile sid=’postdbs1′;
SGA的大小(对比前面的值):
引用
SQL> show parameter sga
NAME TYPE VALUE ———————————— ———– —————————— lock_sga boolean FALSE pre_page_sga boolean FALSE sga_max_size big integer 30G sga_target big integer 30G
可见,这里的vm.nr_hugepages 刚好等于SGA的大小,但是,vm.nr_hugepages还用于如ASM实例等,每个ASM实例约需100M左右的空间。所以,vm.nr_hugepages =15360 是不够的,故障仍会出现。
◎ 在SGA为30G时,vm.nr_hugepages应该设置为:
引用
# ./hugepages_settings.sh Recommended setting: vm.nr_hugepages = 15428
在上面“解决问题”部分,我们设置的SGA大小是30000M,那么(30000+100)/2 = 15050 < 15067,所以“解决问题”中是成功的。※ 注意:vm.nr_hugepages 的设置是否正确,可从HugePages的使用量来观察。 下面是分配不足的情况:
引用
# cat /proc/meminfo |grep Huge HugePages_Total: 15067 HugePages_Free: 15004 Hugepagesize: 2048 kB
Oracle 启动后,仅因ASM实例的原因,使用了很少一部分的HugePages(由/etc/init.d/init.crs服务占用),对内存的使用不正常。 但是,因为使用HugePages部分的共享内存不能被swap,也不能被其他进程使用,所以,如果该值比Oracle需要的值大了,所多出来的部分就是浪费。因此,HugePages 应该选择一个最佳值,以让HugePages_Free接近或等于0。(可参考上面提供的脚本)
2、vm.nr_hugepages 的调整 调整vm.nr_hugepages 的大小后,必须重启系统才能生效。
3、Oracle RAC启动方式 当用alert调整SGA的大小后,不能单纯的用shutdown immediate关闭数据库实例,而必须用srvctl 重启节点的方式才能生效。
四、附录 开始,因从top上观察到,最后时刻是kswapd在进行页面交换,占用大量的CPU资源。所以,首先想到的是swap的问题,故曾对系统核心参数进行了不少的调整工作,特把一些较重要的参数记录下来:1、/proc/sys/vm/min_free_kbytes 该值设定的是系统保留给核心自己使用的内存大小,其他应用程序不能使用这部分的内容,包括系统cache也不可以。即free命令首行free部分的保留值。默认情况下,系统在启动时会根据物理内存的大小自动计算出该值。单位是(KB):
引用
# cat /proc/sys/vm/min_free_kbytes 8286
该值不应该太大,太大了,其他应用可用的内存就会减少,提高kswapd交换的频率;也不应该太小,太小了,供核心调度的内存范围将不足,可能会因内存不够,发生OOM。该值与kswapd等存在以下关系:
引用
# cat /proc/sys/vm/vfs_cache_pressure 100
该值越大,将越早使用kswapd进行页面交换,即使用swap空间;该值越小,越不希望使用swap空间。但该值<10时,除非可用内存(物理内存-核心保留的内存)真的已几乎耗尽,将会尽量不使用swap空间。注意,若该值设定太低(<10)时,一旦在cached较大,而发生突发的大内存申请时,可能会导致kswapd不断的进行页面交换,占用大量的CPU资源,最后导致机器响应不过来(hang住了)。4、/proc/sys/vm/pagecache 该值决定核心回收内存钱,将会把内存用于pagecahe的最大百分比。默认值为100,即所有的系统内存都可以用于pagecache 。该值在2.4核心的时候曾经提供过,但后来被取消了,直到DC 5.0 SP3或Asianux 3.0 SP1以后更新算法后,可再次设置,这时,只有一个参数,代表百分比。详细请见:这里。
用free可看到效果,而剩余的cached值是有程序正在占用的内存,除非进程退出,否则无法删除该部分的内容。当然,该动作清空缓存后,会影响部分性能。另外,若多次执行该动作后,cached仍在不断的增长,说明有程序在不断的消耗内存,并且没有释放出来,也可作为一个判断内存使用情况的依据。(该参数在DC 5.0 SP3以后才能使用,详细可见:这里) 正常情况下,除非应用对内存的使用有问题,否则是不需要手动执行该动作的。※ 注意: 虽然以上核心参数都很重要,当初我也受DBA日记 修订版、kswapd0 hangs the system 等文章的影响,修改了这些参数。但是测试结果告诉我们,原因并不在这里,加入这些参数或许可以缓解宕机的时间,但是并不能彻底解决问题。因为故障的根源在于Oracle不断的申请内存,但又没有释放,直到可用内存被消耗完。所以,判断类似问题的办法,仍必须靠top、ps aux、free等监控手段,逐步分析,寻找故障根源。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/104527.html