引言:上个星期遇到了数据库启动问题。报错如下,当时一度以为是内存设置问题,但是内存还是很充足的。但是有紧急任务,所以就先关停了其他实例。现在再来仔细研究这个这个报错。
SQL> startup
ORA-27154: post/wait create failed
ORA-27300: OS system-dependent operation: semget failed with status: 28
ORA-27301: OS failure message: No space left on device
ORA-27302: failure occurred at: sskgpsemid2
ORA-27303: additional information: maxsems = 1004, verify_semcnt = 0后面经过测试,发现这个错误也有可能是以下这种,区别在于上面那个报错是因为一个组里面想申请1004个,都申请不下来了。 1004 一般是process 数+4,
以下报错是因为 总 process > min(SEMMNI * SEMMSL, SEMMNS)的同时,当前实例的process还大于SEMMSL。
SQL> startup nomount force
ORA-27154: post/wait create failed
ORA-27300: OS system dependent operation:semget failed with status: 28
ORA-27301: OS failure message: No space left on device
ORA-27302: failure occurred at: sskgpcreates对错误分析:
1,ORA-27154: post/wait create failed 是 Oracle 数据库中的一个错误,通常与操作系统资源限制或配置问题有关。这个错误表明 Oracle 在尝试创建用于进程间通信(IPC)的信号量或共享内存时失败了。
2,ORA-27300: OS system-dependent operation: semget failed with status: 28 是 Oracle 数据库中的一个错误,通常与操作系统信号量(semaphore)资源的分配失败有关。具体来说,这个错误表明 Oracle 在尝试通过 semget 系统调用创建或获取信号量时失败了,状态码是28,对应linux 的ENOSPS 错误,表示资源耗尽。
<< 所以在这里,我们就要定位到这是跟信号量相关了。 那如果是共享内存不够,应该是什么错误呢??
3,sskgpsemid2 是 Oracle 内部的一个函数,负责处理信号量的分配和管理。当该函数调用失败时,Oracle 会抛出 ORA-27302 错误。
4,ORA-27303: additional information: maxsems = 1004, verify_semcnt = 0
在该错误中:
maxsems = 1004:表示当前系统中单个信号量集的最大信号量数量限制为 1004。verify_semcnt = 0:表示 Oracle 在尝试验证信号量计数时发现计数值为 0,这可能意味着信号量资源分配失败或验证逻辑出现问题。
那么我们来看一下信号量设置:
[oracle@gzdba-jbox ~]$ ipcs -ls
--------- 信号量限制 -----------
最大数组数量 = 256 //SEMMNI
每个数组的最大信号量数目 = 1024 //SEMMSL
系统最大信号量数 = 4000 //SEMMNS
每次信号量调用最大操作数 = 1024 //SEMOP
信号量最大值 = 32767 第一列,表示每个信号集中的最大信号量数目。
第二列,表示系统范围内的最大信号量总数目。
第三列,表示每个信号发生时的最大系统操作数目。
第四列,表示系统范围内的最大信号集总数目。
经过测试,在我的机器上。关于信号量和process 有以下结论:
1,SEMMSL 应该跟(最大的oracle processes 数+4)相等甚至稍大一点,参考文档:, 否则我们会看到 process 的信号量被分散在不同的信号集中,会需要更多的信号量。比如当我SEMMSL=1024时,我的process 数在1500-1900 之间,process 数每增加1,信号量就要增加1.5。process 数量再往上,这个比例就会变小,比如变成1.2。 信号量的配置不是先放完一个集,再分配一个集的,感觉比较复杂,没有深究。同时,在一个信号集里面放太多的信号量,会不会有问题,有什么影响,暂时也还不清楚。需要仔细研究操作系统,并测试。BTW,我看默认值都很大的,应该不会有啥问题。
2. 信号量的SEMMNI * SEMMSL (即最大数组数量*每个数组的最大信号量数目),建议大于 process *1.5 加上其他实例,比如ASM,或者其他oracle 实例的process 的数量。如果说。SEMMSL大于process 数的话,则不用那么多,但是预 留多一点吧
3. 信号量 SEMMNS(即系统最大信号量数) 也要大于process*1.5 加上其他实例process数量。(这里的1.5 根以上同理), 这个可以尽量的设置大一些。 这个参数和SEMMNI * SEMMSL 共同决定了系统的最大可用信号数量min(SEMMNI * SEMMSL, SEMMNS)
同时查阅到信号量集的创建机制为:
当程序调用 semget(key, nsems, flags) 时,内核按以下顺序检查资源:
- 是否超过
SEMMNI:
若系统当前的信号量集数量已等于SEMMNI,拒绝创建新集合。 - 是否超过
SEMMSL:
若nsems(请求的单个集合中的信号量数)超过SEMMSL,直接失败。 - 是否超过
SEMMNS:
若当前所有信号量总数+ nsems超过SEMMNS,拒绝分配。
信号量集SEMMNI的优先级最高。
再来看另外一个问题:那如果是共享内存不够,应该是什么错误呢??
共享内存在linux 中的设置有以下几项shmmax,shmall,shmmni, 以及查看方法:
# 查看共享内存段的最大大小(单位:字节)
cat /proc/sys/kernel/shmmax
# 查看系统范围内共享内存总页数限制
cat /proc/sys/kernel/shmall
# 查看共享内存段的最大数量
cat /proc/sys/kernel/shmmni当前SGA大小为8G,把 shmmax 设置为 7516192768 (7G),会看到内存段分开了。7+1G=8G。因为shmall 的数量(kernel.shmall = 34359738367)很大。默认一页=4KB。
------------ 共享内存段 --------------
键 shmid 拥有者 权限 字节 nattch 状态
0x446268f8 65536 grid 600 24576 26
0x00000000 11796481 oracle 640 50331648 23
0x00000000 11829250 oracle 640 7516192768 23 <<7G
0x00000000 11862019 oracle 640 1023410176 23 <<978M
0xd94fc384 11894788 oracle 640 2097152 23 把kernel.shmall 设置成7G。7*1024*1024/4=1835008
报错为:
SQL> startup nomount pfile=pfileflyme.ora force
ORA-27102: out of memory
Linux-x86_64 Error: 28: No space left on device
Additional information: -1073741824。 << 表示还差多少,这里差了1G。
Additional information: 1把kernel.shmall 设置成8G。8*1024*1024/4=2097152
报错为:
SQL> startup nomount pfile=pfileflyme.ora
ORA-27102: out of memory
Linux-x86_64 Error: 28: No space left on device
Additional information: -50331648
Additional information: 1再增加50331648/1024/4=12288,成功启动。
SQL> startup nomount pfile=pfileflyme.ora
ORACLE instance started.
Total System Global Area 8551575552 bytes
Fixed Size 2270360 bytes
Variable Size 1660947304 bytes
Database Buffers 6878658560 bytes
Redo Buffers 9699328 bytes
SQL> 可以看到,相同键下面,有一个8G,和一个48M的共享内存段。比较迷。。。
[oracle@gzdba-jbox dbs]$ ipcs
--------- 消息队列 -----------
键 msqid 拥有者 权限 已用字节数 消息
------------ 共享内存段 --------------
键 shmid 拥有者 权限 字节 nattch 状态
0x446268f8 65536 grid 600 24576 23
0x00000000 1376257 oracle 640 50331648 23
0x00000000 1409026 oracle 640 8539602944 23
0xd94fc384 1441795 oracle 640 2097152 23 临时配置大页看看。8*1024/2=4096 ,同时把数据库参数use_large_pages 配置为ONLY
echo 4096 > /proc/sys/vm/nr_hugepages[oracle@gzdba-jbox ~]$ cat /proc/meminfo|grep -i huge
AnonHugePages: 409600 kB
HugePages_Total: 4096
HugePages_Free: 4096
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB无法启动。
SQL> startup nomount pfile=pfileflyme.ora
ORA-27137: unable to allocate large pages to create a shared memory segment
Linux-x86_64 Error: 12: Cannot allocate memory
Additional information: 2097152根据提示的话,还需要 2097152/1024=2048MB 的大页内存。(why?)先满足要求看看。 4096+1024=5120echo 5120 > /proc/sys/vm/nr_hugepages成功启动。
SQL> startup nomount pfile=pfileflyme.ora
ORACLE instance started.
Total System Global Area 8551575552 bytes
Fixed Size 2270360 bytes
Variable Size 1660947304 bytes
Database Buffers 6878658560 bytes
Redo Buffers 9699328 bytes
SQL> 现在再来调小kernel.shmall 为7G, 7*1024*1024/4=1835008
SQL> startup nomount pfile=pfileflyme.ora
ORA-27102: out of memory
Linux-x86_64 Error: 28: No space left on device
Additional information: -50331648
Additional information: 1再加点。
1835008+12288=1847296,还是不行的。需要kernel.shmall 也大于SGA。
但是大页的大小,跟普通页的,不应该是分开的吗?
暂且得出结论是,kernel.shmall 需要大于所有的SGA加起来的大小,配置大页以后也是。




