联动Oracle:设计思想、架构实现与AWR报告
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.4 Oracle的进程结构

除了1.3节介绍的基本分类之外,Oracle进程在RAC环境中也引入了更多与集群相关的进程及agent(代理)进程,以确保系统的横向可扩展性和高可靠性。为此,本节将对Oracle中的常用进程进行简要介绍。这些进程的分类及作用看似简单,但我们在深入理解进程的含义和作用之后,再回头来看这些进程的说明,会将自己对Oracle原理的认知提升到一个新的水平。

1.4.1 Oracle常见进程及简介

启动Oracle数据库时,从Oracle数据库的警告日志(alert_<SID>.log,其中SID为Oracle数据库实例的名称)中,可以看到进程的启动顺序如下。

从“PMON started with pid=2,OS id=5903”可以看出,当Oracle数据库启动时,一系列进程开始启动。除了操作系统进程编号(OS id=5903)外,Oracle内部也会有自己的进程命名规则(PMON started with pid=2)。Oracle提供了查看V$process视图的功能,里面涵盖了当前所有的Oracle进程(包括后台进程和服务器进程)。查看V$process视图的命令如下:

其中,background字段值为1表示后台进程,其余都是服务器进程。

后台进程为多个服务器进程提供服务,并保证系统正常运行,而服务器进程则为用户进程提供服务。Oracle中常见的进程结构如图1-12所示。

图1-12 Oracle中常见的进程结构

从图1-12中可以看出,在集群环境下,Oracle进程也可以分为用户进程、服务器进程、后台进程、监听进程和集群栈相关进程这五大类。其中,集群栈相关进程在RAC环境中才存在,在单实例环境中一般只包含前四类。接下来对Oracle的常用进程做简要回顾和说明。

1.用户进程

数据库有两类用户,一类是客户端程序,比如SQL Plus、SQL Developer等终端用户,另一类是第三方开发的应用程序。当Oracle用户通过终端或应用程序登录数据库时会生成用户进程。该用户进程可通过监听进程转接到合适的服务器进程。

这里需要注意的是,用户进程都有一个用户工作区(User Global Area,UGA)。用户工作区是用户进程与服务器进程交换数据的场所,在Oracle专用服务器模式下,用户工作区在PGA中。用户只能处理用户工作区中的数据,其数据是Oracle根据用户请求存入的。服务器进程在读取到用户进程所需的数据后,会在用户工作区通过进程间通信将数据转给用户进程,最终用户才能得到数据。

用户工作区的缓冲区中有个用户会话数据区,其大小与会话数据单元参数的设置有关,如果系统的网络传输比较频繁,该参数就会对性能产生一定的影响,详细内容将在第9章讲解。

2.服务器进程

服务器进程用于接收客户端发来的用户进程请求(查询、修改等),并代理用户进程监护这类请求在服务器端的执行,比如读取缓冲区中的数据,向客户端(用户进程)返回查询结果,就像是一个代替用户进程完成数据读取任务的代理。

那么,用户进程与服务器进程之间的通信(即进程间通信)是怎么进行的呢?当用户进程与服务器进程在不同的主机上时,一般都是通过TCP传输层的Socket通信来建立连接的,具体步骤如下。

1)用户进程向监听器发起连接请求。

2)监听器接收到连接请求后验证用户的合法性。(用户名和密码是建立会话的必备参数。)

3)服务器端产生一个服务器进程与用户进程建立连接和会话,并在PGA为这个服务器进程分配一段私有内存区域作为工作区。

4)服务器进程根据用户进程请求从磁盘(或SGA)得到数据后,将数据放到PGA的用户工作区中。

5)用户进程通过进程间通信,从用户工作区中读取数据并返回给最终用户。需要注意的是,所有操作都是在用户工作区中进行的。以修改操作为例,首先应把要修改的记录读到用户工作区,用户程序在用户工作区中对其进行修改后,向数据库管理系统发出写记录命令。

3.后台进程

维护实例的正常运转需要靠后台进程和内存空间,共享内存中的数据向磁盘的写入要靠后台进程。作为Oracle中实例的组成和稳定运行的主体,后台进程非常重要,下面就来介绍几种常见的Oracle后台进程。

(1)数据写入进程(DBWR)

此进程会将数据缓冲区(data buffer cache)中的脏块(即更改过的数据块)写回到数据文件中,并释放数据缓冲区空间(如图1-13所示)。参数DB_WRITER_PROCESSES可用于控制进程数量,数据写入进程的数量与CPU数量有关,CPU不足时,不建议将其值设置得过大。通常,在Oracle 10g中可以有20个进程,在Oracle 11g中可以有36个进程。因为数据块是从哪里加载的,就要写回到哪里,所以进程可以有多个。发生以下几种情况之一时,数据写入进程将执行写操作。

❑没有可用的数据缓冲区。

❑服务进程在扫描了buffer个数阈值(由隐藏参数:_db_block_max_scan_pct)后还没找到一块未用的缓存时。

❑每隔2s写一次数据(由检查点进程按照每3s一次的频率写入控制文件引起)。

❑遇到检查点,还有表空间备份、改为离线、改为只读,以及表被删除或截断等条件也会引起写入。

图1-13 数据写入进程示意图

(2)日志写入进程(LGWR)

日志写入进程负责将日志缓冲区中的日志条目写入日志文件(如图1-14所示)。有多个日志文件时,该进程以循环的方式将数据依次写入各个文件。发生以下几种情况之一时,日志写入进程将执行写操作。

图1-14 日志写入进程示意图

❑日志每次提交(commit)时。

❑重做日志缓冲区(redo log buffer)写满1/3时。

❑在数据写入进程执行写操作之前先写(即先记日志后写脏块,保证未提交的数据都能回滚)。

❑每隔2s写一次日志(由数据写入进程的3s传导而来)。

(3)检查点进程(CKPT)

当数据写入进程将最早“脏”的缓冲区写入磁盘时,检查点进程负责将此刻的SCN(System Change Number,系统改变号)同步到控制文件中和数据文件头上(如图1-15所示)。每超过3s就启动一次,在将SCN写到控制文件中时,会记录最早的那条未写盘的脏块的日志位置,此记录将作为实例恢复时扫描日志的起点。

图1-15 检查点进程示意图

遇到检查点时,Oracle数据库必须更新所有数据文件及控制文件的头,以记录该检查点的详细信息,这是由检查点进程完成的工作。注意,检查点进程不会将脏块写入磁盘,该工作始终由数据写入进程执行。文件头中记录的SCN可保证在该SCN之前对数据块进行的所有更改都已写入磁盘。

(4)系统监控进程(SMON)

实例崩溃后,如果数据库缓冲区高速缓存中的脏块没有写入磁盘,那么下次启动后需要用UNDO数据文件中的数据块(历史版本)和重做日志进行恢复。这个过程称为实例恢复,由系统监控进程完成(如图1-16所示)。若内存中的临时段长时间没有使用,也由系统监控进程负责清理。系统监控进程还负责清除不再使用的临时段。

图1-16 系统监控进程示意图

(5)进程监控进程(PMON)

一个会话意外断开后,其会话信息会残留在系统中成为“垃圾”。进程监控进程会在用户进程失败时执行进程恢复操作,并清除缓冲区高速缓存和释放该用户进程占用的资源(如图1-17所示)。例如,进程监控进程会重置活动事务处理表的状态,释放锁,并从活动进程列表中删除该失败进程ID。

进程监控进程还负责向监听程序告知当前实例的信息(即进程监控进程和监听程序进程之间的通信),此过程即动态注册。当实例启动以及相关参数变更,或者每1min一次的条件达成时,动态注册会被触发并向监听程序告知当前实例的信息。监听程序只有在知道实例存在的情况下,才能为用户进程建立连接。

图1-17 进程监控进程示意图

(6)归档日志进程(ARCn

归档模式下发生日志切换时,需要把当前日志组中的内容写入归档日志中作为历史备份日志。仅当数据库处于ARCHIVELOG(归档日志)模式且已启用自动归档时,才会存在归档日志进程。如果预计归档的工作负荷很重(例如在成批加载数据期间进行归档),则可以适当增加最大归档进程数。

4.集群栈相关进程

在Oracle RAC集群环境下,除了以上介绍的几种数据库进程(含监听进程)以外,我们还需要了解更多Oracle GI进程相关的内容。Oracle集群相关的进程将在第11章介绍,此处不再赘述。

1.4.2 Oracle进程的启动顺序

在Oracle集群环境下,启动脚本存放在操作系统的/etc/inittab文件中。该脚本主要负责设置环境变量,以确保每次启动计算机时能在相应的运行级别启动集群守护程序和相关进程。UNIX系统的/etc/inittab文件格式如下。

由于该脚本是使用respawn操作启动的,因此终止后,它会重新启动。在这些守护程序启动以后,有些会在root用户身份下运行,而另一些会在grid所有者身份下以用户模式运行。这些进程的启动顺序如图1-18所示。

在集群环境下,各集群节点的共享配置信息存储在表决磁盘和OCR(Oracle Cluster Registry,Oracle集群注册表)中。在Oracle 11g R2之前,表决磁盘和OCR的配置信息是存储在裸设备上的,因此各节点的OHASd进程初始化完后需要先读取这些信息,接着启动ASM实例,最后再启动数据库,这个启动顺序比较容易理解。在Oracle 11g R2及之后的版本中,ASM作为Oracle的战略存储架构,GI和ASM的位置发生了互换,ASM包含表决磁盘和OCR的信息。因此启动顺序看起来就不那么好理解了,ASM明明在GI之下,但是它又作为一个被管理对象被GI管理着。ASM没有启动时,集群怎么读取ASM磁盘文件呢?为此,Oracle引入了gnpn服务来解决此问题。另外,ASM磁盘组自解释性很强,甚至不启动ASM实例也能根据磁盘组的信息读取其内容。Oracle进程启动的详细步骤将在11.2节进一步说明。

图1-18 Oracle进程的启动顺序

1.4.3 进程、连接、会话的区别

关于进程、连接、会话三者的区别,可以参考MOS(My Oracle Support)上的一篇文章(文档ID为165659.1)。本节将结合上述基础知识对这三者进行进一步解释说明。进程是程序读取到内存中执行后所形成的动态的样子,每个进程在内存中都会占用一定的空间,CPU借助进程来执行任务。两个进程之间为实现相互通信而形成的逻辑通道称为连接,至少需要两个进程才能组成一个连接或会话。

为了描述连接,这里需要先介绍Socket的概念。Socket实际上就是IP地址和端口的组合。两台主机要通信需要知道彼此的IP地址,但一台主机上可以运行多个程序,即多个进程,两台主机之间不同的程序需要通信时彼此之间怎么区分呢?为此,我们在TCP/IP的传输层引入了端口的概念,并对每个程序分配特定的端口号,比如,We b应用端口号默认为80,ssh连接端口号默认为22,FTP的控制通道端口号默认为21,等等。有了端口的区分之后,多个程序在两个主机之间就能够通过IP地址加端口的方式进行独立的信息交换了。

所谓连接,实际上就是两个进程基于Socket形成的逻辑通道。从图1-19也能看出,连接就是用户进程和服务器进程之间基于Socket所形成的逻辑通道。因为IP地址(32位)和端口长度(16位)加起来一般在48位以下,所以这时形成连接的进程所需的内存也很小。

图1-19 会话和连接的区别

那什么叫会话呢?简单地说,会话就是连接、用户名和密码的组合。因此,连接代表逻辑通道,而会话是在通道上传输SQL语句及其数据的子通道。建立连接不需要用户名和密码,但建立会话必须提供用户名和密码。当用户认证通过并形成会话时,Oracle会为每个会话分配一个会话编号,即SID。

用户进程和数据库服务器进程之间也是采用端口号来区分不同的连接的,可通过用户名和密码(或者说会话编号)区分不同的会话。但是,如果同一个用户名和密码建立了多个会话又该怎么区分呢?它们到底是代表一个会话还是多个会话呢?答案是多个会话。Oracle为了区分此类情况,引入了序列号(serial#)的概念,并为多个会话分配了不同的序列号,因此当我们需要杀掉某个会话时,可以通过serial#来区分不同的会话。杀掉会话的命令如下。

当会话的状态是active的时候,alter system kill session命令只是将会话标识为killed状态,并不会释放该会话所持有的资源,所以在执行完alter system kill session命令后,会话还是一直存在的,需要等待PMON进程回收资源和释放锁等。(特殊情况下,若PMON进程无法完成回收,就需要使用操作系统命令来完成杀掉会话的操作。)

可以说,会话是一种传输SQL代码及其数据的带有状态特性的载体,它携带着多条SQL代码及相应的数据信息,因此相对于仅仅代表连接状态的进程(还未形成会话连接的进程),会话信息需要存储在更大的内存空间中。