全部博文(389)
分类: Oracle
2014-12-06 17:37:52
从OS角度观察ORACLE实例进程的启动
Oracle整个实例是由多个后台进程通过共享内存和信号量来协作共同对外
提供服务的,那么这些相关的进程是怎么去启动的呢?
我们首先来看一下通过sqlplus来进行启动的情况,sqlplus 只是一个工具,和oracle
实例启动没有什么必然的联系,和通过其他的工具来启动oracle过程也是一样的.
[oracle@localhost ~]$ sqlplus /nolog
SQL*Plus: Release 12.1.0.2.0 Production on Sat Dec 6 07:35:28 2014
Copyright (c) 1982, 2014, Oracle. All rights reserved.
SQL>
启动sqlplus ,这个时候只是启动了工具,没有干任何事,oracle实例现在也是没有启来的.我们通过
启动另一个会话,使用strace工具来对sqlplus的调用进行跟踪
[root@localhost ~]# ps -eaf | grep sqlplus
oracle 31569 6621 0 07:35 pts/4 00:00:00 sqlplus
root 31625 31583 0 07:36 pts/6 00:00:00 grep sqlplus
[root@localhost ~]# strace -p 31569
Process 31569 attached - interrupt to quit
read(0,
此时可以看到sqlplus没有任何活动,第一会话停在SQL> 处等待用户的输入
一般的情况下,我们此时会输入 conn / as dba命令.
[oracle@localhost ~]$ sqlplus /nolog
SQL*Plus: Release 12.1.0.2.0 Production on Sat Dec 6 07:35:28 2014
Copyright (c) 1982, 2014, Oracle. All rights reserved.
SQL> conn / as sysdba;
Connected to an idle instance.
SQL>
通过strace的输出,我们可以发现,输入这个命令后,最重要的就是生成一个连接进程,有时候也称为服务器进程
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x2ad3116dc210) = 31685
31685是生成该进程的进程号.
[oracle@localhost 2014_12_05]$ ps -eaf | grep 31569
oracle 31569 6621 0 07:35 pts/4 00:00:00 sqlplus
oracle 31685 31569 0 07:39 ? 00:00:00 oraclet2 (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
可以看到通过conn / as sysdba后,sqlplus生了一个服务器进程,这个进程是通过beq协议连接的.同时会把ORACLE_SID和
ORACLE_HOME两个变量传给该进程.
现在sqlplus等待用户进一步发布命令,又是在read处等待.
brk(0x1ce0c000) = 0x1ce0c000
stat("/u01/app/oracle/product/12.1.0.2/db_1/sqlplus/admin/glogin.sql", {st_mode=S_IFREG|0644, st_size=342, ...}) = 0
access("/u01/app/oracle/product/12.1.0.2/db_1/sqlplus/admin/glogin.sql", F_OK) = 0
statfs("/u01/app/oracle/product/12.1.0.2/db_1/sqlplus/admin/glogin.sql", {f_type="EXT2_SUPER_MAGIC", f_bsize=4096, f_blocks=12398557, f_bfree=2740169, f_bavail=2100180, f_files=12812288, f_ffree=12544727, f_fsid={0, 0}, f_namelen=255, f_frsize=4096}) = 0
open("/u01/app/oracle/product/12.1.0.2/db_1/sqlplus/admin/glogin.sql", O_RDONLY) = 10
read(10, "--\n-- Copyright (c) 1988, 2005, "..., 57344) = 342
read(10, "", 57344) = 0
close(10) = 0
write(1, "SQL> ", 5) = 5
read(0,
这个时候我们需要-f参数来跟踪oracle后台进程的启动。从输出的文件我们可以看到以下过程
首先通过shmget调用检查共享内段是否存以,以判定oracle实例是否启动了.可以看到现在不存在,说明
实例没有启动
shmget(0x9bee458c, 0, 0) = -1 ENOENT (No such file or directory)
670
shmget(0x9bee458d, 0, 0) = -1 ENOENT (No such file or directory)
670
shmget(0x9bee458e, 0, 0) = -1 ENOENT (No such file or directory)
670
shmget(0x9bee458f, 0, 0) = -1 ENOENT (No such file or directory)
接下来会自己申请一系列的shmget,shmat,shmctl的调用,向os申请共享内存段.
共享内存段成功后,读取服务器参数文件.
stat("/u01/app/oracle/product/12.1.0.2/db_1/dbs/spfilet2.ora", {st_mode=S_IFREG|0640, st_size=3584, ...}) = 0
生成另一个服务器进程来接替之前的31685的工作
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x2b537048f7f0) = 723
而之前的 31685进程会打开/dev/shm里面的内存段,然后做一些截断工作,可以看到刚好是16M
open("/dev/shm/ora_t2_2082963461_107", O_RDWR|O_CREAT|O_SYNC, 0640) = 18
670
ftruncate(18, 16777216)
经过一大堆的调用后,开始启动oracle的后台进程了
31685 write(21, "Starting background process PMON"..., 33) = 33
670 close(21)
= 0
670 times(NULL) = 517052821
670 times(NULL)
= 517052821
670
access("/u01/app/oracle/product/12.1.0.2/db_1/bin/oracle", X_OK) = 0
670 pipe([21, 22]) = 0
670
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x2b537048f7f0) = 727
727 close(21
670 close(22
727 <... close resumed> ) = 0
670
<... close resumed> ) = 0
727 clone(
670 read(21,
727
<... clone resumed> child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x2b537048f7f0) = 728
727 close(22) = 0
728
open("/proc/728/stat", O_RDONLY
727 exit_group(0)
先会在alert.log中输出Starting background process PMON,接下来访问$ORACLE_HOME/bin/oracle这个二进制文件,然后进行
进程clone,返回一个服务器进程 727,727再去生成真正的pmon进程 728,728启动完成 后,727就会被退出.所以oracle后台进程第一个
启动的总是pmon进程.
diagnostic_dest = "/u01/app/oracle"
enable_pluggable_database= TRUE
NOTE: remote asm mode is local (mode 0x1; from cluster type)
Starting background process PMON
Starting background process PSP0
Sat Dec 06 08:03:41 2014
这是alert.log中的信息可以证实这一点.
接下来启其他的后台进程,和pmon启动的过程致
31685 write(21, "Starting background process PSP0"..., 33) = 33
31685 access("/u01/app/oracle/product/12.1.0.2/db_1/bin/oracle", X_OK
31685 <... clone resumed> child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x2b537048f7f0) = 729
再去由729真正的启动psp后台进程
729 <... clone resumed> child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x2b537048f7f0) = 730
730 execve("/u01/app/oracle/product/12.1.0.2/db_1/bin/oracle", ["ora_psp0_t2"], [/* 34 vars */]
返回psp的进程号为730
[root@localhost ~]# ps -eaf | grep 730
oracle 730 1 0 08:03 ? 00:00:00 ora_psp0_t2
而后续的部分进程竟然是由psp进程来clone的,这一点有点意料之外
730 access("/u01/app/oracle/product/12.1.0.2/db_1/bin/oracle", X_OK) = 0
730 pipe([7, 8]) = 0
730
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x2aba8aab77f0) = 731
731 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x2aba8aab77f0) = 732
可以看到由731去clone 732进程,732是一个vktm进程
[root@localhost ~]# ps -eaf | grep 732
oracle 732 1 0 08:03 ? 00:00:00 ora_vktm_t2
然后由732再去启动733(中间进程),由于733再去启动 734号进程,734号进程是dism进程.734进程启动成功后,733退出.
所以在这里可以解释一个以前一直困扰我的问题,为什么oracle后台进程号之间总是隔着一个数.比如2,4,6之类的
如此顺序启动了所有的oracle的后台进程,实例启动完成.
而原来的31685进程也会退出,对应为之前的sqlplus服务的进程也退出来了,重新生成了另一个服务进程来接替之前的31685号进程的工作.
[root@localhost ~]# ps -eaf | grep LOCAL
oracle 784 31569 0 08:03 ? 00:00:01 oraclet2 (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
总结:
1,顺序
sqlplus=> 发布conn / as sysdba,生成一个服务器进程=>发布startup命令,服务器进程生成一个中间进程,启动pmon和psp
=>psp进程再clone其他的进程,一个接一个这样的顺序,而不是psp充当其他进程的祖先=>最初的服务器进程退出,生成一个新的
服务器进程.
2,所有的oracle后台进程和前台进程,实质都是一个二进制文件$ORACLE_HOME/bin/oracle.
3,oracle后台进程号之间总是隔着一个数.