大家好,这里是 Lucifer三思而后行,专注于提升数据库运维效率。
前言
作为一名 DBA,应该都玩过 Oracle 数据库,最熟悉的操作可能就是开关库:
-- 开库
SQL> startup
-- 关库
SQL> shutdown immediate
但是执行这两个命令,数据库到底做了什么?相信很多人都没有研究过,本系列打算详解一下 Oracle 数据库的启动和关闭过程,静心看完,相信一定可以帮助大家更加深入了解 Oracle 数据库。
介绍
Oracle 数据库启动分为三个阶段:
nomount:读取参数文件,启动实例,分配 SGA,启动部分进程。
mount:实例启动后读取控制文件,挂载数据库。
open:读取数据文件和日志文件,启动数据库。
本文先讲数据库的第一个启动阶段:nomount 阶段,演示环境是 11GR2 数据库。
nomount 阶段
nomount 阶段是数据库启动的第一个阶段,需要参数文件,会启动一个实例,在这个过程中会分配内存区域 SGA 以及启动一些后台进程。
参数文件
参数文件分为:
init<SID>.ora
spfile.ora
spfile<SID>.ora
单实例数据库存放在 $ORACLE_HOME/dbs
目录下,启动默认的查找顺序为:spfile<SID>.ora ---> spfile.ora ---> init<SID>.ora
。
可以发现当前数据库优先使用的是 spfile<SID>.ora
方式启动:
[oracle@rhel6:/home/oracle]$ cd $ORACLE_HOME/dbs
[oracle@rhel6:/u01/app/oracle/product/11.2.0/db/dbs]$ ll
-rw-rw----. 1 oracle oinstall 1544 Aug 26 22:57 hc_lucifer.dat
-rw-r--r-- 1 oracle oinstall 2084 Jul 26 22:20 initlucifer.ora
-rw-r--r--. 1 oracle oinstall 2851 May 15 2009 init.ora
-rw-r-----. 1 oracle oinstall 24 Jul 10 18:43 lkLUCIFER
-rw-r-----. 1 oracle oinstall 1536 Aug 19 21:50 orapwlucifer
-rw-r----- 1 oracle oinstall 9781248 Aug 23 02:00 snapcf_lucifer.f
-rw-r-----. 1 oracle oinstall 5632 Aug 26 13:27 spfilelucifer.ora
验证一下,启动数据库实例:
-- 不指定参数文件,启动到 mnount 状态
SQL> startup nomount
ORACLE instance started.
Total System Global Area 4275781632 bytes
Fixed Size 2260088 bytes
Variable Size 2801795976 bytes
Database Buffers 1459617792 bytes
Redo Buffers 12107776 bytes
-- 查看 spfile 参数
SQL> show parameter spfile
NAME TYPE VALUE
------------------------------------ --------------------------------- ------------------------------
spfile string /u01/app/oracle/product/11.2.0/db/dbs/spfilelucifer.ora
可以看到默认启动的参数文件是 spfilelucifer.ora,此时查看 alert 日志中参数文件相关的部分:
## 也可以看到是使用参数文件:/u01/app/oracle/product/11.2.0/db/dbs/spfilelucifer.ora,并且读取了参数文件中非系统默认的参数配置
Using parameter settings in server-side spfile /u01/app/oracle/product/11.2.0/db/dbs/spfilelucifer.ora
System parameters with non-default values:
processes = 2000
resource_limit = TRUE
event = "28401 trace name context forever,level 1"
event = "10949 trace name context forever,level 1"
sga_max_size = 4G
streams_pool_size = 1312M
resource_manager_plan = "force:"
sga_target = 4G
_memory_imm_mode_without_autosga= FALSE
control_files = "/oradata/lucifer/control01.ctl"
control_files = "/u01/app/oracle/fast_recovery_area/lucifer/control02.ctl"
control_file_record_keep_time= 31
db_block_size = 8192
compatible = "11.2.0.4.0"
log_archive_dest_1 = "location=/oradata/archivelog"
log_archive_format = "%t_%s_%r.dbf"
_use_adaptive_log_file_sync= "FALSE"
db_files = 5000
db_create_file_dest = "/oradata"
db_recovery_file_dest = "/u01/app/oracle/fast_recovery_area"
db_recovery_file_dest_size= 5532M
enable_goldengate_replication= TRUE
_datafile_write_errors_crash_instance= FALSE
_cleanup_rollback_entries= 2000
undo_tablespace = "UNDOTBS1"
_undo_autotune = FALSE
undo_retention = 10800
_partition_large_extents = "FALSE"
_index_partition_large_extents= "FALSE"
sec_case_sensitive_logon = FALSE
remote_login_passwordfile= "EXCLUSIVE"
db_domain = ""
dispatchers = "(PROTOCOL=TCP) (SERVICE=luciferXDB)"
session_cached_cursors = 300
parallel_max_servers = 64
_PX_use_large_pool = TRUE
audit_file_dest = "/u01/app/oracle/admin/lucifer/adump"
audit_trail = "NONE"
db_name = "lucifer"
open_cursors = 1000
_optimizer_null_aware_antijoin= FALSE
_b_tree_bitmap_plans = FALSE
_optimizer_extended_cursor_sharing= "NONE"
_optimizer_extended_cursor_sharing_rel= "NONE"
_optimizer_adaptive_cursor_sharing= FALSE
pga_aggregate_target = 1256M
deferred_segment_creation= FALSE
_optimizer_use_feedback = FALSE
enable_ddl_logging = TRUE
diagnostic_dest = "/u01/app/oracle"
所以,数据库实例启动的第一步就是找到参数文件,并且读取参数配置。
分配 SGA
通过第一步读取参数文件配置,可以获取到内存相关配置,包括 SGA 相关参数:
sga_max_size = 4G
streams_pool_size = 1312M
sga_target = 4G
在启动数据库实例过程中会输出以下信息:
Total System Global Area 4275781632 bytes
Fixed Size 2260088 bytes
Variable Size 2801795976 bytes
Database Buffers 1459617792 bytes
Redo Buffers 12107776 bytes
以上这些提示信息分别是什么意思呢?大家如果知道 SGA 有哪些组件,应该一下就能明白:
参考 11GR2 官方文档 Database Concepts:Memory Architecture[1]
下面就详解一下启动数据库实例时输出的每一行的意思:
-- 这个是可分配的总 SGA 大小
Total System Global Area 4275781632 bytes
-- 可以通过查询 select sum(value) from v$sga; 或者 select sum(bytes) from v$sgastat;
-- 注意:以上两个 SQL 在 11G 查询出来的结果值有出入,在 19C 查出来是一模一样
-- 11GR2
SQL> select sum(value) from v$sga;
SUM(VALUE)
----------
4275781632
SQL> select sum(bytes) from v$sgastat;
SUM(BYTES)
----------
4275780728
-- 19C
SQL> select sum(value) from v$sga;
SUM(VALUE)
----------
5318374384
SQL> select sum(bytes) from v$sgastat;
SUM(BYTES)
----------
5318374384
-- Fixed SGA Size 包含数据库和实例的状态信息等通用信息,后台进程需要访问这部分信息,用于进程之间传递信息,不存储用户数据,大小由 Oracle 数据库设置,无法手动更改,大小可能会因版本而异。
Fixed Size 2260088 bytes
-- 可以通过查询 select * from v$sgainfo where name = 'Fixed SGA Size';
SQL> select * from v$sgainfo where name = 'Fixed SGA Size';
NAME BYTES RESIZEABL
-------------------- ---------- ---------
Fixed SGA Size 2260088 No
-- Variable size 包括 Shared Pool Size、Java Pool Size、Large Pool Size 和 Streams Pool Size。
Variable Size 2801795976 bytes
-- 可以通过查询 select * from v$sgainfo where name in ('Shared Pool Size','Java Pool Size','Large Pool Size','Streams Pool Size');
SQL> select * from v$sgainfo where name in ('Shared Pool Size','Java Pool Size','Large Pool Size','Streams Pool Size');
NAME BYTES RESIZEABL
-------------------- ---------- ---------
Shared Pool Size 587202560 Yes
Large Pool Size 805306368 Yes
Java Pool Size 33554432 Yes
Streams Pool Size 1375731712 Yes
-- 注意:这个 SQL 总和在 11G 查询出来的结果跟 Variable Size 的值有出入,在 19C 查出来是一模一样
SQL> select sum(bytes) from v$sgainfo where name in ('Shared Pool Size','Java Pool Size','Large Pool Size','Streams Pool Size');
SUM(BYTES)
----------
2801795072
-- Buffer Cache Size,数据库缓冲区缓存,也称为缓冲区高速缓存,是存储从数据文件读取的数据块副本的内存区域。
Database Buffers 1459617792 bytes
-- 可以通过查询 select * from v$sgainfo where name = 'Buffer Cache Size';
SQL> select * from v$sgainfo where name = 'Buffer Cache Size';
NAME BYTES RESIZEABL
-------------------- ---------- ---------
Buffer Cache Size 1459617792 Yes
-- Redo Buffers,重做日志缓冲区是 SGA 中的一个循环缓冲区,用于存储数据库所做更改的重做记录。
Redo Buffers 12107776 bytes
-- 可以通过查询 select * from v$sgainfo where name = 'Redo Buffers';
SQL> select * from v$sgainfo where name = 'Redo Buffers';
NAME BYTES RESIZEABL
-------------------- ---------- ---------
Redo Buffers 12107776 No
以上 SGA 组件内存分配的相关信息可以从 v$sgainfo
中查看:
SQL> select * from v$sgainfo;
NAME BYTES RESIZEABL
---------------------------------------- ---------- ---------
Fixed SGA Size 2260088 No
Redo Buffers 12107776 No
Buffer Cache Size 1459617792 Yes
Shared Pool Size 587202560 Yes
Large Pool Size 805306368 Yes
Java Pool Size 33554432 Yes
Streams Pool Size 1375731712 Yes
Shared IO Pool Size 0 Yes
Granule Size 16777216 No
Maximum SGA Size 4275781632 No
Startup overhead in Shared Pool 498329672 No
Free SGA Memory Available 0
这部分内容无法从 alert 日志中获取相关信息,所以直接打印在 sqlplus 启动过程中,也可以通过 show sga
查看:
SQL> show sga
Total System Global Area 4275781632 bytes
Fixed Size 2260088 bytes
Variable Size 2801795976 bytes
Database Buffers 1459617792 bytes
Redo Buffers 12107776 bytes
上面是将数据库层面的 SGA 内存分配,其实在操作系统层面也可以看出个大概:
## 开启实例前
[oracle@rhel6:/home/oracle]$ ipcs -a
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 0 root 644 80 2
0x00000000 32769 root 644 16384 2
0x00000000 65538 root 644 280 2
## 可以看到,当数据库实例启动到 nomount 后,多了 3 个 oracle 用户的共享内存段
## nattch 表示当前附加到这个共享内存段的进程数
## oracle 用户 key 的值 0x00000000 的 bytes 之和为 4294967296,也就是 SGA 的大小为 4G,其中 33554432 代表的是 Java Pool Size,4261412864 是其他组件的总和。
[oracle@rhel6:/home/oracle]$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 0 root 644 80 2
0x00000000 32769 root 644 16384 2
0x00000000 65538 root 644 280 2
0x00000000 917507 oracle 640 33554432 17
0x00000000 950276 oracle 640 4261412864 17
0x467a6680 983045 oracle 640 2097152 17
注意:上面的输出中,关于共享内存段的列的意思如下:
key:共享内存段的键值,用于标识。
shmid:共享内存段的ID。
owner:共享内存段的所有者。
perms:共享内存段的权限,通常以4位八进制数表示。
bytes:共享内存段的大小,单位是字节。
nattch:当前附加到这个共享内存段的进程数。
status:共享内存段的状态,可能包含额外的信息或为空。
综上发现,数据库实例启动的第二步是分配 SGA 组件内存。
启动进程
查看进程启动情况:
-- 数据库实例启动前,没有 lucifer 实例相关的后台进程
SQL> ! env | grep ORACLE_SID
ORACLE_SID=lucifer
SQL> ! ps -ef|grep -v grep|grep lucifer
-- 数据库实例启动到 nomount 后,启动进程如下
SQL> ! ps -ef|grep -v grep|grep lucifer
-- 后台进程
oracle 57755 1 0 16:56 ? 00:00:00 ora_pmon_lucifer
oracle 57757 1 0 16:56 ? 00:00:00 ora_psp0_lucifer
oracle 57759 1 2 16:57 ? 00:00:40 ora_vktm_lucifer
oracle 57763 1 0 16:57 ? 00:00:00 ora_gen0_lucifer
oracle 57765 1 0 16:57 ? 00:00:00 ora_diag_lucifer
oracle 57767 1 0 16:57 ? 00:00:00 ora_dbrm_lucifer
oracle 57769 1 0 16:57 ? 00:00:06 ora_dia0_lucifer
oracle 57771 1 0 16:57 ? 00:00:00 ora_mman_lucifer
oracle 57773 1 0 16:57 ? 00:00:00 ora_dbw0_lucifer
oracle 57775 1 0 16:57 ? 00:00:00 ora_lgwr_lucifer
oracle 57777 1 0 16:57 ? 00:00:00 ora_ckpt_lucifer
oracle 57779 1 0 16:57 ? 00:00:00 ora_smon_lucifer
oracle 57781 1 0 16:57 ? 00:00:00 ora_reco_lucifer
oracle 57783 1 0 16:57 ? 00:00:00 ora_mmon_lucifer
oracle 57785 1 0 16:57 ? 00:00:03 ora_mmnl_lucifer
oracle 57787 1 0 16:57 ? 00:00:00 ora_d000_lucifer
oracle 57789 1 0 16:57 ? 00:00:00 ora_s000_lucifer
-- 前台进程,也就是当前连接的会话
oracle 61552 61551 0 17:29 ? 00:00:00 oraclelucifer (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
-- 这里可以看到 ora_ 后台进程数为 17 个,与 ipcs -m 看到的 nattch 的数量相符
SQL> ! ps -ef|grep -v grep|grep ora_|wc -l
17
可以看到当 Oracle 启动到 nomount 状态后,有以下后台进程被启动:
pmon(Process Monitor):监视其他后台进程,并在服务器或调度程序进程异常终止时执行进程恢复。
psp0(Process Spawner Process):初始实例启动后生成 Oracle 后台进程。
vktm(Virtual Keeper of Time Process):提供一个秒级更新的数据库时钟,减少数据库和操作系统的交互。
gen0(General Task Execution Process):为数据库提供了一个执行通用任务的进程,进程的主要目标是分担进程中某些可能造成阻塞的处理过程,并将他们放在后台完成。
diag(Diagnostic Capture Process):数据库诊断进程,负责维护管理各种用于诊断的转储文件,并执行 oradebug 命令。
dbrm(Database Resource Manager Process):数据库资源管理进程,负责设置资源计划和其他的资源管理的工作。
dia0(Diagnostic Process):数据库诊断进程,负责检测 Oracle 数据库中的挂起(hang)和死锁的处理。
mman(Memory Manager Process):实现共享内存自动管理。
dbw0(Database Writer Process):数据库写入程序,主要职责是将数据块写入磁盘,还负责处理检查点、文件打开同步以及块写入记录的日志记录。
lgwr(Log Writer Process):日志写入程序,将重做日志条目按顺序写入重做日志文件。
ckpt(Checkpoint Process):在检查点处发出 DBWn 信号并更新数据库的所有数据文件和控制文件以指示最近的检查点。
smon(System Monitor Process):执行关键任务(如实例恢复和死事务恢复)以及维护任务(如临时空间回收、数据字典清理和撤消表空间管理)。
reco(Recoverer Process):解决由于分布式数据库中的网络或系统故障而挂起的分布式事务。
mmon(Manageability Monitor Process):MMON 执行许多与可管理性相关的任务,包括获取自动工作负载存储库快照和执行自动数据库诊断监视器分析。
mmnl(Manageability Monitor Lite Process):是 AWR 新增的进程,主要作用是将 AWR 数据从内存中刷新到表中。
d000(Dispatcher Process):允许用户进程共享有限的服务器进程(SERVER PROCESS)。
s000(Shared Server Process):负责与用户进程通信,并与 Oracle 交互,以代表相关的用户进程执行任务。
注意:以上后台进程具体可参考官方文档:Background Processes[2]
查看数据库 alert 日志中与进程启动相关的信息:
## 启动后台进程,一共 17个
Mon Aug 26 16:56:59 2024
PMON started with pid=2, OS id=57755
Mon Aug 26 16:56:59 2024
PSP0 started with pid=3, OS id=57757
Mon Aug 26 16:57:00 2024
VKTM started with pid=4, OS id=57759 at elevated priority
VKTM running at (1)millisec precision with DBRM quantum (100)ms
Mon Aug 26 16:57:00 2024
GEN0 started with pid=5, OS id=57763
Mon Aug 26 16:57:00 2024
DIAG started with pid=6, OS id=57765
Mon Aug 26 16:57:00 2024
DBRM started with pid=7, OS id=57767
Mon Aug 26 16:57:00 2024
DIA0 started with pid=8, OS id=57769
Mon Aug 26 16:57:00 2024
MMAN started with pid=9, OS id=57771
Mon Aug 26 16:57:00 2024
DBW0 started with pid=10, OS id=57773
Mon Aug 26 16:57:00 2024
LGWR started with pid=11, OS id=57775
Mon Aug 26 16:57:00 2024
CKPT started with pid=12, OS id=57777
Mon Aug 26 16:57:00 2024
SMON started with pid=13, OS id=57779
Mon Aug 26 16:57:00 2024
RECO started with pid=14, OS id=57781
Mon Aug 26 16:57:00 2024
MMON started with pid=15, OS id=57783
Mon Aug 26 16:57:00 2024
MMNL started with pid=16, OS id=57785
可以发现,数据库实例启动的第三步是启动进程。
总结
综上所述,可以总结出 nomount 阶段的启动过程大致如下:
查找参数文件,搜索顺序为:
spfile<SID>.ora ---> spfile.ora ---> init<SID>.ora
读取参数文件,并启动数据库实例
分配 SGA 内存段
启动后台进程和前台进程
在这个阶段,不涉及控制文件以及数据文件,只需要参数文件即可,通常用于数据库创建、控制文件重建、特定的备份恢复等。
感谢您的阅读,这里是 Lucifer三思而后行,欢迎点赞+关注,我会持续分享数据库知识、运维技巧。
https://docs.oracle.com/cd/E11882_01/server.112/e40540/memory.htm#i12483 ↩
https://docs.oracle.com/cd/E11882_01/server.112/e40402/bgprocesses.htm#REFRN104 ↩