今天在QQ技术群中,一个朋友介绍了一种快速停库重启的方法。笔者感觉有必要研究重演一下,供来日不时之需。
1、问题简介
事情的起源是这样,一个朋友需要修改processes参数,重新启动数据库。但是因为各种原因,不能登陆入sqlplus。他希望能有解决问题的方法。于是,QQ群中另一个朋友提出一种快速重新停止库的方法。
简单的说,在Linux/Unix环境下,将$ORACLE_HOME/dbs目录下的lk<sid>文件更名删除。之后就可以重新启动。
2、原理分析
这个lk文件是什么呢?在笔者虚拟机环境下,也找到了相应的文件。
[oracle@oracle11gdbs]$ cd $ORACLE_HOME/dbs
[oracle@oracle11gdbs]$ pwd
/u01/oracle/dbs
[oracle@oracle11gdbs]$ ls
hc_DBUA0.dat init.ora lkWILSON peshm_DBUA0_0
snapcf_wilson.f
hc_wilson.dat initwilson.ora orapwwilson
peshm_wilson_0 spfilewilson.ora
强制打开文件,可以看到如下提示。
oracle@oracle11gdbs]$ cat lkWILSON
DO NOT DELETE THIS FILE![oracle@oracle11gdbs]$
在MOS中,我们找到了一些关于lk文件的信息。
大部分和lk文件相关的信息都是和启动数据库时候独占文件有关的。出现最多的问题就是在启动过程中遭遇到ORA-01102错误。
[oracle@oracle11g~]$ oerr ora 01102
01102, 00000, "cannot mount database
in EXCLUSIVE mode"
// *Cause: Some other instance has the
database mounted exclusive or shared.
// *Action: Shutdown other instance
or mount in a compatible mode.
数据库在启动的时候,默认是要以EXCLUSIVE独占的方式进行。我们在一台数据库服务器上,一般也就安装一个实例。如果在启动过程报错ORA-01102,通常的问题可能不是启动模式,而是上次关闭系统时,一些资源对象没有正确释放掉。例如:
- 早期的Oracle 7/8中,在$ORACLE_HOME/dbs目录下的sgadef<sid>.dbf文件不能释放删除;
- Oracle后台活动进程,如pmon, smon, lgwr和dbwr没有释放掉;
- 虽然数据库关闭,但是操作系统层面的共享内存和信号量没有释放;
- 在Oracle 8之后版本中,$ORACLE_HOME/dbs目录下的lk<sid>文件没有释放;
其中,谈到了sgadef和lk文件。这两个文件在Oracle中的作用是用于锁定shared
memory。如果该文件存在,那么即使没有内存被分配,Oracle依然认为此时有内存空间被锁定。
解决01102错误的方法其实也比较简单,就是在OS层面删除掉sgadef和lk文件。这样Oracle就不会认为说此时有内存被分配出。
3、Oracle NFS Lock
对NFS设备,Oracle每个版本都存在一个兼容性列表。只有通过兼容性列表测试(Oracle
Storage Compatibility Test)的设备,Oracle才承诺进行NFS支持。
在Oracle启动的过程中,NFS相关问题主要在Lock锁定方面:
当数据库启动的时候,Oracle会对文件设置OS级别的锁定。在数据库停止的时候,Oracle会释放OS级别的锁定。这个锁操作,不同的数据库版本具有不同的方式。在Oracle7、8时代,这个文件名称为$ORACLE_HOME/dbs/sgadef<sid>。而之后的版本中,这个文件名称为$ORACLE_HOME/dbs/lk<sid>。
为了在OS层面上实现对文件的锁定,Oracle必须调用NFS锁定守护进程。在大部分的Unix系统中,这两个守护进程的名称为:rpc.lockd和rpc.statd。
在实际启动过程中,如果遇到mount数据文件的问题,很可能就是daemon进程终止造成的。所以可以尝试启动该进程。
4、强制关库实验
下面我们实验一下那个朋友的方法,以及如何处理。
--当前wilson实例存活
[oracle@oracle11g~]$ ps -ef | grep pmon
oracle 5644 1 0 14:44 ? 00:00:00 ora_pmon_wilson
oracle 5779 5744 0 14:46 pts/0 00:00:00
grep pmon
进入lk文件所在目录。
[oracle@oracle11g~]$ cd $ORACLE_HOME/dbs
[oracle@oracle11gdbs]$ pwd
/u01/oracle/dbs
[oracle@oracle11gdbs]$ ls
hc_DBUA0.dat init.ora lkWILSON peshm_DBUA0_0
snapcf_wilson.f
hc_wilson.dat initwilson.ora orapwwilson
peshm_wilson_0 spfilewilson.ora
更名该文件。
[oracle@oracle11gdbs]$mv lkWILSON lkWILSON_bak
[oracle@oracle11gdbs]$ ls
hc_DBUA0.dat init.ora lkWILSON_bak peshm_DBUA0_0
snapcf_wilson.f
hc_wilson.dat initwilson.ora orapwwilson
peshm_wilson_0 spfilewilson.ora
注意,此时我们依然可以登录,pmon核心进程依然存在。
[oracle@oracle11gdbs]$ ps -ef | grep
pmon
oracle 5644 1 0 14:44 ? 00:00:00 ora_pmon_wilson
oracle 5799 5744 0 14:48 pts/0 00:00:00
grep pmon
SQL> conn / as sysdba
Connected.
SQL> startup force
ORACLE instance started.
Total System Global Area 414298112 bytes
Fixed Size 1336904 bytes
Variable Size 327158200 bytes
Database Buffers 79691776 bytes
Redo Buffers 6111232 bytes
Database mounted.
Database opened.
SQL>
此时,数据库实例没有如同想象的那样被立即停止。而是依然存在,可以登录入系统。重新启动系统之后,依然可以看到lk<sid>文件重新创建成功。
[oracle@oracle11gdbs]$ ls
hc_DBUA0.dat initwilson.ora orapwwilson
snapcf_wilson.f
hc_wilson.dat lkWILSON peshm_DBUA0_0
spfilewilson.ora
init.ora lkWILSON_bak peshm_wilson_0
证明:直接删除该文件似乎是不能起到立即终止实例运行的作用。
5、结论
过去在一些文章中介绍过一种快速关闭实例的方法。就是在os层面使用kill方法将oracle实例全部删除,在强制释放共享内存和信号量。
|