现代数据库在体系构架上基本上都是由一组进程或线程、共享内存和存储三部分组成的。
进程/线程与共享内存共同作用完成数据库的运算等处理过程和对自身进行维护管理操作;数据库内核中部分进程/线程会对存储直接操作,把保存在存储系统中的数据读入共享内存或把共享内存中的数据写入到存储系统;共享内存和存储系统之间则是数据的通道。
图2是 Oralce 11g 的体系架构简图,图中展示了 Oracle 11g 的主要内部进程、共享内存主要组成部分和主要的存储分类,同时展示了 RMAN 及其在整体体系中的位置和作用关系。
图3是 Informix 12.10 的体系架构简图,图中展示了 Informix 12.10 的主要内部进程、关键线程、共享内存主要组成部分和主要的存储分类,同时展示了 ON-BAR(作用基本等同于Oracle 的 RMAN)及其在整体体系中的位置和作用关系。
数据库管理系统是通过进程/线程来执行数据库引擎内的所有运算和管理任务的,运算任务包括查询(同时也包括了 Join、分组、排序、函数计算等)、数据操作、事务管理和一些定时任务,而管理任务则主要包括内部线程调度、内存管理、事务控制、存储管理、状态信息收集与利用等。
现代数据库管理系统通常都会使用多进程或多线程或多进程+多线程的设计方案。
数据库引擎中包含多个同名进程,这些进程在数据库引擎中作用不同。
数据库在启动时会启动一个主进程,主进程成功启动后会派生出多个同名进程用于负责数据引擎中不同类型的工作。比如 Oracle 数据库,在 oracle 主进程启动后,会派生出 PMON、 DIAO、DBW(通用有多个)、CKPT、LGWR 等进程,用于处理内部状态信息收集、线程协调、I/O 等不同任务。
在有新的外部连接请求到达时,数据库主进程也会派生出新的进程来进行响应。
这类数据库的典型代表有 PostgreSQL、Oracle(专用服务器模式)。
数据库引擎在整个生命周期中始终只有一个服务进程,这个进程根据需要创建多个线程完成内部操作和对外部请求进行响应。
这类数据库的典型代表是 MySQL、SQL Server。
和多进程方案的数据库引擎一样,多进程+多线程方案的数据库引擎在启动时只启动主进程,主进程启动后会根据需要派生出多个进程来负责不同类型的工作,同时,这些派生出来的进程很多都会以多线程方式进行工作。
多进程+多线程方案的数据库引擎往往会有一个或几个进程专门用于接受外部请求,接受到请求后会以线程方式对请求进行响应。
这类数据库的典型代表是 Informix、Oracle(共享服务器模式)。
现代数据库引擎使用多进程/多线程的实现方案,主要是为了提升数据库的整体性能。多进程/多线程方案可以充分利用现代计算机的多处理器的计算能力,同时在设计上进行优化后的多进程方案在某种程度上可以提升数据库管理系统的稳定性和健壮性。
多进程/多线程方案可以提升数据库管理系统整体性能的另外一个原因是可以基于这种方案在数据库内部实现并行作业(Parallel)和流水线作业(Pipeline)。
例如如下 SQL 查询:
SELECT cust_name, order_no, order_date
FROM customers a, orders b
WHERE a.cust_id=b.cust_id
ORDER BY a.cust_name,b.order_date;
在单线程的传统方式下,其执行过程会类似于图4所示的串行方式:
而在多进程/多线程方式下,上述SQL语句中的多个步骤是可以并行执行的,且其中部分步骤之间还可以以流水线的方式进行执行,图5是这种执行方式的示意图。
共享内存技术是进程间通信的常用技术,被广泛使用于现代数据库的架构设计中。
在数据库中,共享内存通常会按内容或作用进行分块管理,通常会分为如下几块:
数据库引擎进程对共享内存的使用往往会表现为 “生产者-消费者” 模式,不同进程/线程只处理与自己相关的信息,处理完成的信息放入共享内存中临时创建的缓存队列,供其它进程/线程使用。
数据库管理系统的存储组件负责持久化保存数据,包括数据库系统的运行信息数据和用户数据,主要可以分为以下几类:
存储的具体表现通常为文件系统,有些数据库系统也支持裸设备或专用文件系统。
传统的关系型事务数据库在存储上通常是按块/页存储,且在存储上通常都是分层设计的,通常的存储层次可以分为以下几种: