问题现象以及初步分析
•AIX环境下,/etc/security/limits关于stack的限制有两个参数,分别是:
* stack - soft stack segment size in blocks
* stack_hard - hard stack segment size in blocks
•其中stack是软限制(当前限制值),而stack_hard是硬限制(最高可设置的软限制值)。stack_hard取值一般直接采用系统默认值。
•本案例中,客户误将stack_hard设置为-1,造成sqlplus进程启动时,系统CPU消耗显著上升,系统整体性能受到了影响。从如下truss截图可以看到,执行sqlplus历时近41毫秒:
![2cbc6b6fe6d91fdf8e0164deeb5a4fb3.png](https://i-blog.csdnimg.cn/blog_migrate/6f2d79f56b7b6e64deaf677df45ea225.jpeg)
详细分析
•在stack的硬限制为-1的情况下,如果64位进程把stack的软限制先通过setrlimit系统接口API先改小,再改成-1/RLIM_INFINITY,就会触发系统分配大量stack segments(4096个)以满足stack size limit扩充的需求。
•如果stack软限制始终保持为默认的-1,则不会触发(系统默认初始分配16个stack segments,用完再分配新的segments)。
•从trace跟踪看,oracle 11gR2 sqlplus会调用setrlimit先改小stack size(把soft limit设置成32MB),再改大stack size(此次size参数取值为当前环境ulimit -s的实际值,在案例的环境中为-1),正好符合了上述模式。因此触发了大量stack segments分配。
•这样依赖,启动、退出sqlplus的过程耗时将会显著增加(fork时分配segments,exit时销毁segments)。如果正好有大量sqlplus进程创建、退出,可能造成极高的sys CPU消耗,影响系统效率。
系统工具truss追踪示例
•如下是一个truss 输出片段(第二个参数是指针,使用dbx跟踪可以观察到指针指向的具体值,有兴趣可以自行尝试):
$ truss -t appgetrlimit,appsetrlimit sqlplus "/as sysdba"
appgetrlimit(3, 0x0FFFFFFFFFFFE830) = 0
appgetrlimit(3, 0x0FFFFFFFFFFFE5D0) = 0
appsetrlimit(3, 0x0FFFFFFFFFFFE5D0) = 0 //参考/usr/include/sys/resource.h, 第一个参数值3代表RLIMIT_STACK,也即设置stack size.
appgetrlimit(3, 0x0FFFFFFFFFFFE830) = 0
appgetrlimit(3, 0x0FFFFFFFFFFFE820) = 0
appsetrlimit(3, 0x0FFFFFFFFFFFE820) = 0
SQL*Plus: Release 11.2.0.4.0 Production on Wed Jul 12 11:54:39 2017
Copyright (c) 1982, 2013, Oracle. All rights reserved.
解决方法
•系统配置参数stack_hard不应当设置为-1。通常我们只要求对oracle用户设置stack为-1(软限制),而stack_hard硬限制默认为8388608 blocks,也就是4GB,即16个stack segments (每个segment大小为256MB)。
•Stack segments 主要存储调用栈信息以及临时变量等等。16个segments对于stack来说已经绰绰有余,即使是负载很重的64位进程,一般也最多只用到几个stack段。因为通常主要的内存数据都集中在共享内存段、数据段、以及文本段。比如Oracle环境下,内存数据主要集中在shared memory segments (比如SGA)、data segments (比如PGA)、和client segments(比如访问的文件)。
•完成修改后,可以看到执行sqlplus的时间从41毫秒缩短为2毫秒。
![e8635e47508bad6ee383244227cc57a8.png](https://i-blog.csdnimg.cn/blog_migrate/54fe6cd0976f69a2f69c97e6bfe43161.jpeg)
配置检查建议
•Oracle 安装手册说明了只建议stack=-1 (Soft Limit),并没有要求设置stack_hard为-1 (Hard Limit).
•建议检查/etc/security/limits里,是否误添加了“stack_hard=-1”的设置,如果存在,删除即可,后续用户重新登录时即可生效。
•特别说明
−如果是32位程序,按地址分布规则,最多只能有一个stack segment,因此不存在上述问题。
−Oracle 11gR2 sqlplus会先把stack size limit改小成32MB,然后再改回环境实际的ulimit -s值。这个行为应当与Oracle bug 12547243的修复方法有关。