DBMS进程模型
关键定义
在讨论进程模型前,必须要了解下面几个重要定义:
- 操作系统进程:包含一个正在执行程序的活动单元以及专属的地址空间。其中一个进程需要维护的状态包括系统资源句柄和安全性上下文环境。
- 操作系统线程:操作系统程序执行单元,它没有私有的地址空间和上下文。在多线程系统中,每个线程都可以共享地访问所属进程的地址空间。
- 轻量级线程包(又称DBMS线程和简单线程):一个应用层次上的结构,支持单系统进程中的多线程。它不由操作系统内核调度线程,而是由应用级线程调度程序来负责调度。
轻量级线程的缺点:任何线程中断操作,比如I/O中断,都会打断进程中的其他线程。
如何避免?
- 只接受无中断的异步I/O操作;
- 不调用可以导致中断的系统操作。
- DBMS客户端:应用程序实现与数据库系统通信API的软件组件,JDBC、ODBC和OLE/DB等例。
- DBMS工作者:指DBMS中为客户端工作的线程。一个DBMS工作者处理一个来自DBMS客户端的SQL请求。DBMS客户端发送SQL请求给DBMS服务器。DBMS工作者处理每一条请求并将结果返回客户端(如下图)。
单处理机和轻量级线程
为简化介绍,先做两个简单的假设:
- 系统线程支持:即假设操作系统内核有效地支持线程,并且一个进程可以拥有很多线程。假设线程存储空间很小,所以在切换时不需要太多的代价。
- 单处理机:假设我们针对仅拥有一个CPU的一台机器。
DBMS拥有的三个天然的拥有三种进程模型性质。下面分别介绍这三种模型。
每个DBMS工作者拥有一个进程
这种模型,DBMS工作者直接映射到系统进程,这相对容易实现。但是,这种模型需要广泛使用共享内存,使得地址空间分离的优势被削弱了。
缺陷:因为进程相对线程而言,哦那个有更多的环境变量并且消耗更多的存储空间。进程切换需要切换安全的上下文环境、存储空间变量、文件和网络句柄列表以及其他一些进程上下文。而线程不需要。
IBM DB2、PostgreSQL和Oracle支持该模型。
每个DBMS工作者拥有一个线程
在此模型中,一个多线程进程负责所有的DBMS工作者的工作。一个调度线程监听新的DBMS客户端连接。每个连接都被分配一个新的线程。当每个客户端提交SQL请求时,都由对应的DBMS工作者线程执行。线程在DBMS进程中运行。
困难:操作系统对线程不提供溢出和指针的保护,调试困难。由于不同操作系统在线程接口和多线程扩展性方面的不同,使得软件可移植性较差。
IBM DB2、微软SQL Server、MySQL、Informix和Sybase支持这种模型。
进程池
进程池管理所有DBMS工作者。一个中央进程控制所有的DBMS客户端连接,每个从客户端来的SQL请求将被分配一个进程池中的进程。SQL请求处理完之后,结果返回客户端,进程回到缓冲池中准备分配给下一个请求。
优势:进程池拥有每个DBMS工作者拥有一个进程模型的所有优点,而且只需要少量的进程,其内存使用效率也很高。
缺陷:缓冲池的大小是一定的,且通常不可变。如果一个请求到来而没有进程空闲,那么新的请求必须等待进程。
共享数据和进程空间
缓冲区的作用:通过使用缓冲区,服务器处理SQL请求,数据被DBMS传送到客户端。
两种主要的缓冲区:磁盘I/O缓冲区和客户端通信缓冲区。
磁盘I/O缓冲区
工作者之间的数据依赖是读写共享的数据。它们之间存在两种不同的I/O中断。
- 数据库I/O中断请求:缓冲池。数据库提交的数据存放在数据库缓冲池中,缓冲池中的数据以堆结构的形式存放,它作为所有进程共享的空间。
- 日志I/O请求:日志尾部。日志条目在事务处理过程中产生,被暂时存储在内存队列中,周期性地按照FIFO顺序刷新至日志磁盘中。(在许多系统中,会有一个独立的进程或者线程负责刷新)
日志管理方式:
- 一个独立进程负责管理日志。日志记录通过共享内存或者其他有效的通信协议与日志管理器进行交互。
- 日志尾部像上文提到的缓冲池安阳分配给共享内存。
一种重要的日志刷新方法是提交事务刷新。一个事务在日志记录被刷新到日志存储器之前不能被成功提交。
客户端通信缓冲区
这是数据预提取的结果队列,想要尽可能地在客户端地SQL FETCH流前就准备好数据。
支持数据预提取功能的两种方法:
- DBMS工作者使用客户端通信套接字作为元组队列。
- 实现客户端游标缓存功能,并使用 DBMS 客户端存储近期即将被访问的结果,而不是依赖于操作系统通信缓冲区。
DBMS线程
为了应对那些没有好的内核线程的系统。一些DBMS开发了自己的搞笑轻量级线程包。它们选择使用DBMS轻量级线程包而不是系统线程。每个 DBMS线程都管理自己的变量,通过非中断的异步接口来编写中断操作,并通过调度器来调度任务。
优势和代价:提供了快速的任务切换和易移植性,但是需要在 DBMS 中重复实现许多操作系统逻辑。
现在数据库所支持的进程模型简单列举
每个DBMS工作者拥有一个进程
- DB2 在不支持线程的系统上,默认使用每个 DBMS 工作者拥有一个进程的模型,在支持线程的系统上,默认使用每个 DBMS工作者拥有一个线程的模型。
- Oracle 进程模型的默认设计。
- PostgreSQL 在所有的操作系统上都只运行每个 DBMS 工作者拥有一个进程模型。
每个DBMS工作者拥有一个线程
每个 DBMS 工作者拥有一个系统线程
- IBM DB2 运行在有良好系统线程支持的系统上时,默认使用该模型。
- MySQL 同样使用该模型。
每个 DBMS 工作者拥有一个DBMS线程
在这个模型中,DBMS 工作者的调度是通过系统进程或线程去调度轻量级线程来实现的。这个模型规避了系统调度的一些问题,但是,它开发代价较高,没有良好的开发工具,也需要运营商的长期维护。
两种子模型:
- 通过系统进程来调度 DBMS 线程:轻量级线程的调度是由一个或多个系统进程来完成的。
- Sybase 和 Informix 支持该模型。
- 通过系统线程来调度系统进程。
- 微软 SQL Sever 以可选择的方式支持这种模型(默认的模型为 DBMS 工作者多路复用线程池)。
- SQL Sever 中这个选项叫做 Fibers,被用做应对高频事务处理,但是很少被使用。
进程/线程池
- DBMS 工作者共用进程池
- Oracle 数据库的可选项,Oracle 建议在大量用户并发操作的情况下使用。
- DBMS 工作者共用线程池
- 微软 SQL Server 默认使用该模型,且超过 99%的 SQL Server产品使用该模型来运行。
- SQL Server 提供可选支持,允许系统线程调度 DBMS 线程。
准入控制
随着多用户系统负载不断升高,吞吐量将达到上限。任何好的多用户系统都有准入控制机制,在系统没有充足资源的情况下,新的任务不被接受。
好的准入器的作用:事务延迟将随着到达率的增加而适当增加,但吞吐量一直保持在峰值。
DBMS 的准入控制可以在两个层面上来实现:
- 一个简单的准入控制可以通过进程来确保客户端连接数处于一个临界值之下。
- 直接在 DBMS 内核关系查询处理器上实现。准入控制器在查询语句转换和优化完成后执行这一步操作。
对于第2种层面,准入控制具体控制:
- 是否要推迟执行一个查询?
- 是否要使用更少的资源来执行查询?
- 是否需要额外的限制条件来执行查询?
如何执行?准入控制器依靠查询优化器的信息来执行。
特殊情况下,优化器的查询计划可以:
- 确定查询所需要的磁盘设备以及对磁盘的 I/O 请求数;
- 根据查询中的操作以及要求的元组数目判断 CPU 负载;
- 评估查询数据结构的内存使用情况,包括在连接和其他操作期间的排序和哈希所消耗的内存。
DBMS 把内存使用情况和活跃的 DBMS 工作者的数量作为主要的准入控制标准。
DBMS工作者与请求的多对多关系
一个查询的工作由多个 DBMS 工作者来完成,一个 DBMS 工作者负责多个查询的同样任务。
优势:
- 允许一个工作者完成许多查询的任务(可能提高系统的整体吞吐量);
- 允许一个查询由多个工作者共同完成(可能减少查询操作的延时);
- 在处理器局部性方面显得更有优势,在硬件未命中的情况下,能更好地防止 CPU 空闲。