May 15

[原]Oracle的SGA与系统vm.nr_hugepages不匹配导致的故障 雷阵雨

linuxing , 04:18 , 基础知识 » 故障处理 , 评论(0) , 引用(0) , 阅读(28310) , Via 本站原创 | |
    某项目,使用红旗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中,然后重启系统:
引用
vm.nr_hugepages=15067

该值必须重启系统才能生效。

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等存在以下关系:
点击在新窗口中浏览此图片
更详细的信息,请参考:这里

2、/proc/sys/vm/vfs_cache_pressure
该值用于决定虚拟内存directory和i-node缓冲回收的倾向,这个值越大,回收的倾向越严重。默认值是100:
引用
# cat /proc/sys/vm/vfs_cache_pressure
100

提高该值,可以让系统更快的回收缓存,释放更多的物理内存。

3、/proc/sys/vm/swappiness
该值用于决定核心使用swap空间的频率。默认值为60:
引用
# cat /proc/sys/vm/swappiness
60

该值越大,将越早使用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以后更新算法后,可再次设置,这时,只有一个参数,代表百分比。详细请见:这里

5、 /proc/sys/vm/drop_caches
默认值为0,可以使用下面的命令强制清空cache:

# echo 3 > /proc/sys/vm/drop_caches

用free可看到效果,而剩余的cached值是有程序正在占用的内存,除非进程退出,否则无法删除该部分的内容。当然,该动作清空缓存后,会影响部分性能。另外,若多次执行该动作后,cached仍在不断的增长,说明有程序在不断的消耗内存,并且没有释放出来,也可作为一个判断内存使用情况的依据。(该参数在DC 5.0 SP3以后才能使用,详细可见:这里
正常情况下,除非应用对内存的使用有问题,否则是不需要手动执行该动作的。
※ 注意:
虽然以上核心参数都很重要,当初我也受DBA日记 修订版kswapd0 hangs the system 等文章的影响,修改了这些参数。但是测试结果告诉我们,原因并不在这里,加入这些参数或许可以缓解宕机的时间,但是并不能彻底解决问题。因为故障的根源在于Oracle不断的申请内存,但又没有释放,直到可用内存被消耗完。所以,判断类似问题的办法,仍必须靠top、ps aux、free等监控手段,逐步分析,寻找故障根源。

五、参考资料
H Very Large Memory on Linux
Tuning and Optimizing Red Hat Enterprise Linux for Oracle 9i and 10g Databases
Hugepage、VLM、SGA和Share memory
在CentOS Linux 5中为oracle配置hugepage的方法
DBA日记 修订版
发表评论
表情
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
打开HTML
打开UBB
打开表情
隐藏
记住我
昵称   密码   游客无需密码
网址   电邮   [注册]