Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2796646
  • 博文数量: 389
  • 博客积分: 4177
  • 博客等级: 上校
  • 技术积分: 4773
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-16 23:29
文章分类

全部博文(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后台进程号之间总是隔着一个数.

 

阅读(2782) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~