informix运行原理机制系列

               前言
 为 了方便大家对informix的原理机制学习进行一个系统的理解,花费了一段时间整理了一篇对informix系统运行机制系统介绍的文章,但是由于目前 informix相关技术文档比较零散,也没有真正系统对其原理描述的相关资料,所以文章中一部分会有自己根据其他数据库的一些原理机制对 informix部分过程进行描述,这样可能不会很准确,欢迎大家对文中出现的错误进行指正,以便于积极改进完善,欢迎大家交流学习
(copyright by marvelyu)
 一   informix多线程及虚拟处理器概念

首先我们了解下 informix 的多线索结构,我们知道 informix 区别于其他 RDBMS 结构的是一种基于动态可伸缩,即 DSA 的架构的服务器,而动态可伸缩体系结构的核心组成部分是被称为“虚拟处理器”的服务器进程,在 UNIX 上我们通常看到的 oninit 进程,所谓的虚拟处理器就像一个 CPU 运行多个进程来为用户服务一样,一个 online 虚拟处理器运行多个线索来为多个 Sql 客户应用服务。

多线索是一种方法,使用这种方法,可以为不同的用户同时执行同一进程而不必再操作系统级形成多个进程。前面我们提到组成数据库服务器的进程称之为虚拟处理器,每个 VP 都属于一个虚拟处理器类,一个 VP 类是一组以线索形式完成指定工作的进程的集合,诸如写磁盘逻辑日志,或从磁盘读数据。这意味着属于某一特定的 VP 只可能运行同类的线索,每个 VP 类可以包含一个或多个 VP ,大多数情况下,其个数可以由管理员配置

当然在某一时刻,一个虚拟处理器实际上只能运行一个线索,正如操作系统靠进程间的切换来运行多个进程一样,一个虚拟处理器通过多个线索间的切换来同时为多个线索服务。通过连续在线索间切换,虚拟处理器保持 CPU 连续出了,由于处理发生的速度很快,效果上看起来是虚拟处理器同时处理多个任务。运行过个并发线索需要调度和协调以防止一个线索受到另一个线索的干扰,主要采用了控制结构、上下文切换、栈、队列、互斥五种结构和方法来协调和处理多个线索并行执行。
二 线程会话监听轮询机制

当一个客户需要连接 informix server ,可以通过共享内存或网络连接,网络连接的客户可以是远程的。也可以是本地的。在配置文件 $ONCONFIG 中的 DBSERVERNAME DBSERVERALIASES 参数定义了数据库服务器名( DBSERVERNAME , $INFORMIXDIR/etc/sqlhosts 文件中有与之相联系的项。每个数据库服务器名在 sqlhosts 文件中都有一个 nettype 项, nettype 项指定了一个接口和协议组合。 informix 更加配置文件中的 NETTYPE 配置参数为每个唯一的 nettype 项运行一个或多个轮询线索( poll thread ),配置参数也指定了轮询查询线索的虚拟处理器( CPU NET 类)。

informix 启动时, oninit 进程为每一个配置文件中 DBSERVERNAME DBSERVERALIASES 参数指定的数据库服务器名启动一个叫监听线索( listen thread )的内部线索。管理员通过在 sq;hosts 文件中为每一个服务器名分配一个唯一的主机名与服务名的组合来为数据库服务器名指定一个监听端口。因此,在 sqlhosts 文件中的每一行指定了数据库服务名,接口/协议组合和监听端口。

每个数据库服务器名的监听线索打开相应的监听端口,并且请求一个接口 / 协议组合所指定的轮询线索,用于监听该端口上的客户请求、当轮询线索接受到一个客户的连接后,将此请求传递给该端口上的监听线索,监听线索对用户进行鉴定,然后建立与 online 的链接,为用户设置一个称为会话控制块的数据结构,该结构包括一个会话标识号,唯一标识该应用,此外,监听线索还为代表该用户运行的线索 (sqlexec) 设置一个称为线索控制块( tcb )的结构,线索控制块包含该线索的上下文,最后 online 为该会话启动 sqlexec 会话线索,由会话线索对客户的请求做主要处理。

连接建立之后,轮询线索负责从客户读取数据, sqlexec 线索负责请求处理并向客户发送数据 - 轮询线索等待客户的请求,收到后把客户请求放在共享内存中, sqlexec 线索处理共享内存中的这些请求,并把结果直接送给客户,对于一个共享内存连接,轮询线索将客户的请求信息放在共享内存的通讯部分;而对于网络连接,轮询线索将请求信息放在共享内存公用缓冲池中的队列中。轮询线索可以内联在 CPU 虚拟处理器中运行,或者根据连接类型在相应的网络虚拟处理器中运行。CPU 类的虚拟处理器中的sqlexec 线索( 客户的主线索) 将分析并优化SELECT 语句,它将读取缓冲区中符合查询条件的页。

如果sqlexec 线索在缓冲区中找不到合适的页,它将把从磁盘读页的请求放进AIO VP 队列。然后,sqlexec 线索将控制转到就绪队列中另外一个线索,并将自己放到睡眠队列,等待AIO 虚拟处理器处理磁盘请求。AIO 虚拟处理器从磁盘读数据页并放进缓冲区,当操作完成后。它唤醒Sqlexce 线索使之重新回到就绪队列,由此可以继续Select 语句的执行。 OnLine 系统中每个CHUNK 都有一个AIO 请求队列。核心异步I/O 是另外一种需要操作系统协调的I/O 方法。核心异步I/O 的请求由kio 线索处理。当OnLine 管理的第一个原始设备打开后启动kio 线索。 当一个会话发出读写请求后,该请求被放进AIO 请求队列。随后,kio 线索将发送一个请求到操作系统要求完成读写操作。kio 线索并不需要等待该操作完成。对每一个CPU 类虚拟处理器,都有一个AIO 请求队列和一个kio 线索。kio 线索探询核心以确认I/O 请求是否完成。当读写操作完成后,kio 线索将读进的页放到缓冲区并唤醒Sqlexec 线索。

三  会话SQL语句分析执行及数据的获取过程

前面已经描述了informix数据库所独有的监听轮询机制过程,那么对于一个客户端应用连接请求建立过后sqlexec线索会做些什么操作来获取所需要的数据呢?

根 据前面我们讲述的监听轮询机制来看,这些过程在监听线程在接到轮询线索请求后建立连接阶段就进行了用户权限鉴定,确定会话连接请求建立的用户不存在问题, 同时会对sql中的语法进行检测,如果发现语法或者权限的错误就会返回相关提示信息,如果不存在问题后才会建立到数据库服务器的连接,就会生成一个会话的 控制数据结构并且还会生成一个线程控制块,因为大家知道,informix 是基于虚拟处理器共享进程处理的方式, 所以每个线程必须分配对应的堆栈段来保存自己会话的私有数据,这个线程的初始化堆栈分配大小由stacksize 参数控制,其中在语法分析这个过程 主要通过在数据字典查找是否存在相应的对象信息确定sql 不存在问题,如我们设置了数据字典高速缓存中的存储书DD_HASHSIZE, 数据库服务器可以 存储在每个存储区中的表数DDHASHMAX 。当数据库服务器第一次为用户执行那个Sql 语句时。当数据库启用了SQL 语句高速缓存配置时,也就是SMIT_CACHE 配置参数值设置启用,那么数据库服务器将检查完全一样的SQL 语句是否在SQL 语句高速缓存中,如果锁执行的SQL 已经存在时,数据库服务器在SQL 语句高速缓存中查找该语句而不需要进行优化该语句。如果不在高速缓存中,那么数据库服务器分析该语句、确定最优的查询计划并执行该语句,这时数据库服务器会从磁盘上的sysdistrib 系统目录表检索统计信息,一旦数据库服务器访问了分布统计信息,他们将该信息放在内存中的数据分布高速缓存中,数据库服务器使用散列算法在数据分布高速缓存内存储和查找信息。DS_POOLSIZE 控制数据分布高速缓存的大型,并且可以指定在数据分布高速缓存中 存储的列分布总数,要修改数据字典高速缓存中的存储区数,使用DS_HASHSIZE 配置参数。上面的过程均在共享内存中虚拟内存部分完成,确定了sql会话的执行计划后,就需要执行sql会话语句,以响应用户请求,返回相应的执行结果,这这个过程在共享内存中数据缓冲池中进行,那么这些数据的获取过程又会是怎样的呢?

一个 informix 线索对一个缓冲区页的获取过程时这样的:

1.   必须通过物理页号也就是rowid来确定确定请求数据的位置。如果不知道rowid就必须通过顺序扫描或者全表扫描数据页来得到,用户线索请求一个特定的数据行, informix 从磁盘上搜索包含该行的页。

2.   确定线索对请求缓冲区需要上锁的级别,锁的级别或者是共享的,或者是独占的

3.   试图在共享内存中定位所需要的页

线索首先在共享内存中寻找需要的磁盘页 - 首先在缓冲区表的杂凑表中获得一个 mutex ,然后搜索杂凑表看是否有与所请求的页相匹配的一项;如果有,则线索释放原杂凑表中的 mutex, 然后试图获得缓冲区表中该缓冲区页项的 mutex. 线索测试共享内存中此页的锁级别,如果与将要上的锁级别相容,则线索奖获得访问权并对缓冲区上锁;如果锁级别不相容,则该线索将自己置于次缓冲区的等待队列中。我们知道在 informix 中对于顺序的表或者索引扫描,可以配置 informix 在处理当前已读入内存的页的同时,继续读入多个页到缓冲区中,预读可以减少应用程序等待磁盘 I/O 的时间使其运行更快。其中 $ONCONFIG 中的 RA_PAGES 参数规定了 online 预读时从磁盘上读入的页数,而 RA_THREADHOLD 参数规定了使 informix 在做一次预读时缓冲区中未处理的页数 - 即当缓冲区中只有 RA_THREADHOLD 规定的页数需要处理时, informix 从磁盘上预读 RA_PAGES 规定数目的磁盘页,当 informix 每当测试到顺序读数据或索引时,都将执行一个预读操作。

4 . 如果共享内存中没有需要的页,从 FLRU 队列中分配一个缓冲区并从磁盘上读入该页

informix 随机的选择一个 LRU 队列,其中 LRU 队列的个数我们在 $ONCOFNIG 配置文件中设置,每个 LRU 可以管理的 buffers 个数,并试图获得与这个 LRU 队列相联系的 mutex. 如果此 mutex 可以获得,将使用 FLRU 队列的“近期最少使用”一端的一缓冲区。如果不能获得,该线程在试图获得另一个 FLRU 队列的 mutex, 如果使用了预读, informix 从磁盘读入 RA_PAGES 配置参数规定的数目的页。

5.   如果需要,给缓冲区上锁

FLRU 队列中找到一个未使用的缓冲区后,该缓冲区被临时从 FLRU 队列中删除。将数据从磁盘读入缓冲区的同时,线索在共享内存缓冲区表中建立一项,相应的对缓冲区上锁。

6.   用完缓冲区后,将锁释放

7.    如果有其他线索在等待上面使用的缓冲区,唤醒具有相容锁访问级别的线索。

线索对缓冲区的释放过程根据缓冲区是否修改有所不同。 如果缓冲区没有修改,释放的步骤如下:

a. 释放线索获取缓冲区表上的相应 mutex , 使其能修改缓冲区表中的该缓冲区项。然后,释放线索检查等待该缓冲区的睡眠线索,如果有线索等待该缓冲区,唤醒队列中第一个具有相容锁类型的线索。如果等 待队列中没有一个线索具有相容的锁访问类型,则唤醒队列中的任何一个线索。如果没有等待该缓冲区的线索,释放线索尽量将该缓冲区释放到原来的 FLRU 队列中,而如果原来的 FLRU 队列上的 mutex 不能获得,释放线索则随机的选择一个 FLRU 队列并试图获得其上的 mutex 。获得 mutex 之后,未修改的缓冲区被放在 FLRU 队列的“近期最多使用”的一端。线索释放缓冲区到 FLRU 队列或唤醒下一个等待该缓冲区的线索后,释放线索从该缓冲区的用户表中将自己删除,并将共享用户数减 1.

b. 如果缓冲区已经修改,情况是这样的:

线索在修改缓冲区前,首先获得这个缓冲区的 mutex ,并把这个缓冲区的锁访问类型设置成独占方式。通常,为使数据一致,该页的前镜像必须首先记录到物理日志或物理缓冲区中,数据页修改之后,如果事务修改记录日志,这些修改还要记录到逻辑日志缓冲区中。

缓冲区的 mutex 释放后,线索将该缓冲区释放:

首先获得缓冲区表中的 mutex ,使其能修改该缓冲区项。释放线索修改缓冲区头中的时间戳,这样使得缓冲区页上的时间戳与缓冲区头上的时间戳一致;锁的释放同上面一样,但缓冲区被附加到与原 FLRU 配对的 MLRU 队列中“最近最多使用”的一端。

当缓冲区修改后标记为脏( dirty , 只有将这些修改过的缓冲区写入磁盘也就是缓冲区被刷新后,这些缓冲区才能被允许重新使用。缓冲区刷新分为常规缓冲区的刷新、物理日志缓冲区的刷新和逻辑日志缓冲区的涮洗,所有的刷新都是由页刷新线索管理的。 informix 总是至少允许一个页刷新线索,这个参数通过 $ONCONFIG 配置文中的 CLEARS 参数设定。为保证数据一致性, informix 总是按照一定的规则刷新缓冲区,使用刷新已修改页之前,必须先刷新他们的“前印象”页。

以上即完成了一个整个用户会话请求并获取数据的过程,然后sqlexec会将得到结果传送费相应的监听线程连接请求,又监听线程通过网络协议将数据返回给客户端。这就是一个完整的会话过程

四 检查点及检查点过程

前面我们提到到了一个用户会话连接数据库服务器,并且详细了解了相关会话如何在共享内存中执行的问题,接下来我们关注下在这个过程中另一个重要事件,也是每个RDBMS中非常关键的步骤,那就是检查点事件发生,首先我们先了解下检查点的概念。

数据库检查点的作用是使共享内存缓冲 区中的数据同磁盘上的数据保持同步。检查点使数据库服务器系统处于物理上的一致状态。一旦事务完成后立即强制将每个事务清仓到磁盘,数据库服务器还将事务 写入到逻辑日志中,如果出现故障数据库服务器将重放日志以重做和恢复事务,将数据库返回至与发生故障时数据库系统的状态一致的状态。通常数据库检查点可以 由以下方式执行:

经过了一个检查点间隔。检查点时间间隔的长短由 CKPTINTVL 配置参数规定 .    磁盘上物理日志文件的 75 %已经写满。数据库服务器 系统管理员通过 onmonitor 菜单选项或在命令行使用 onmode 命令来强制执行检查点操作。特定的管理任务,例如备份、增加一个 chunk 或增加一个 dbspace 。同时通过配置AUTO_CKPTS参数还会启用自动检查点,以根据数据库事务运行的负荷情况将缓冲区中数据清仓到磁盘。

那么informix数据库的检查点的发生过程会是怎么样呢?

数据库服务器 系统启动一个检查点请求后,不再允许用户线索进入代码的临界区,如果这时用户线索已进入临界区,则该线索被允许执行到临界区结束。    

数据库服务器 系统中规定的代码临界区主要包括必须作为整体来执行的一组磁盘修改代码 ( 或者全部执行,或者一条也不执行 ) 。规定临界区是为了保证物理一致性。在临界区的用户线索持有共享内存资源,且需要修改这些资源中的数据。在检查点过程中,检查点进程需要访问这些资源以完成共享内存资源与磁盘的同步。

当不再有用户线索处于代码临界区中时,检查点活动可以继续。清页线索将共享内存中的物理日志缓冲区刷新到磁盘上的物理日志。

清页线索将共享内存缓冲池中已修改的缓冲区刷新到磁盘上。从加入到 数据库服务器 系统中的第一个 chunk 开始,系统为每个 chunk 分配有一个清页线索,接着第二个、第三个等。清页线索读取缓冲区头信息,寻找与它们的 chunk 相关的页。

最后,清页线索将所有页按页码排成磁盘序列,并将此序列写到磁盘,这就是排序写,它大大减少了检查点过程中的磁盘寻道时间。在检查点期间由清页线索执行的写操作叫做 chunk 写。

对于 数据库服务器 系统中配置的每 100 个缓冲区,在共享内存的虚拟部分上创建有一个大小为 8 页的大缓冲区。大缓冲区通过执行大规模的读写操作从而提高了系统的性能。每当有多个页写到磁盘上,并且这些页在磁盘上是连续的时,则使用大缓冲区在一次 I/O 操作中写入 8 页。

接着,清页线索将一个检查点记录写入逻辑日志缓冲区。这为系统发生故障提供了一个恢复点。此外,清页线索还将更新记录检查点活动的系统保留页 (PAGE_1CKPT PAGE_2CKPT) ,同时,一个检查点结束的记录写入 OnLine 消息日志文件。

在写入检查点结束记录后,磁盘上的物理日志在逻辑上被清空。这并不是将物理日志的内容移走,因为这是件很费时的操作,而是将物理日志文件的当前位置标志为新的逻辑起点,新的记录以该点为起点。

如果物理日志已用尽,新的页写到物理日志文件的开始。你可以把物理日志文件想象成一个环,没有头也没有尾。因此,每当发生一个检查点后,物理日志文件的选择起点都要发生变化。

检查点活动的最后一步是将逻辑日志缓冲区刷新到磁盘上的逻辑日志。

 

检查点对于 数据库服务器 系统中的快速恢复处理非常重要。如果快速恢复被启动,数据库服务器 系统将被置成物理上的一致状态,该状态同上一次检查点结束记录写入逻辑日志时的系统状态一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值