1.2.3 数据库实例
达梦数据库实例一般由一个正在运行的DM后台进程(包含多个线程)及一个大型的共享内存组成。简单来说,实例就是操作达梦数据库的一种手段,是用来访问数据库的内存结构及后台进程的集合。
达梦数据库存储在服务器的磁盘上,而达梦数据库实例存储在服务器的内存中。通过运行达梦数据库实例,可以操作达梦数据库中的内容。在任何时候,一个实例只能与一个数据库进行关联(装载、打开或挂起数据库)。在大多数情况下,一个数据库也只有一个实例对其进行操作。但是,在达梦数据库提供的高性能集群中,多个达梦数据库实例可以同时装载并打开一个数据库(位于一组由多台服务器共享的物理磁盘上),此时,可以同时从多台计算机上访问这个数据库。
1.DM后台进程
DM服务器使用“对称服务器构架”的单进程、多线程结构。这种“对称服务器构架”在有效地利用系统资源的同时,提供了较高的可伸缩性能,这里的线程即操作系统的线程。服务器在运行时由各种内存数据结构和一系列线程组成,线程分为多种类型,不同类型的线程完成不同的任务。线程通过一定的同步机制对数据结构进行并发访问和处理,以完成用户提交的各种任务。达梦数据库服务器是共享的服务器,允许多个用户连接到同一个服务器上,服务器进程称为共享服务器进程。DM后台进程中主要包括监听线程、工作线程、输入输出(I/O)线程、调度线程、日志线程等。
1)监听线程
监听线程的主要任务是在服务器端口上进行循环监听,一旦有来自客户的连接请求,监听线程被唤醒并生成一个会话申请任务,加入工作线程的任务队列,等待工作线程进行处理。监听线程在系统启动完成后才启动,在系统关闭时首先被关闭。为了保证在处理大量客户连接时系统具有较短的响应时间,监听线程比普通线程优先级更高。
2)工作线程
工作线程是DM服务器的核心线程,它从任务队列中取出任务,并根据任务的类型进行相应的处理,负责所有实际数据的相关操作。DM8的初始工作线程个数由配置文件指定,随着会话连接的增加,工作线程也会同步增加,以保持每个会话都有专门的工作线程处理请求。为了保证用户的所有请求及时响应,一个会话上的任务全部由同一个工作线程完成,这样减少了线程切换的代价,提高了系统效率。当会话连接超过预设的阈值时,工作线程数量不再增加,转而由会话轮询线程接收所有用户请求,并加入任务队列,等工作线程空闲时,从任务队列中依次摘取请求任务处理。
3)输入输出(I/O)线程
在数据库活动中,I/O 操作历来都是最耗时的操作之一。当事务需要的数据页不在缓冲区中时,如果在工作线程中直接对那些数据页进行读写,会使系统性能变得非常糟糕,而把I/O操作从工作线程中分离出来是非常明智的做法。I/O线程的职责就是处理这些I/O操作。在通常情况下,DM Server需要进行I/O操作的时机主要有以下3种。
(1)需要处理的数据页不在缓冲区中,此时需要将相关数据页读入缓冲区。
(2)当缓冲区满或系统关闭时,需要将部分脏数据页写入磁盘。
(3)当检查点到来时,需要将所有脏数据页写入磁盘。
I/O 线程在启动后,通常处于睡眠状态,当系统需要进行 I/O 操作时,只需要发出一个I/O请求,I/O线程就会被唤醒以处理该请求,并在完成该I/O操作后继续进入睡眠状态。
I/O线程的个数是可配置的,可以通过设置dm.ini文件中的IO_THR_GROUPS参数来设置,在默认情况下,I/O线程的个数是两个。同时,I/O线程处理I/O请求的策略根据操作系统平台的不同会有很大差别,在一般情况下,I/O线程使用异步的I/O操作将数据页写入磁盘,此时,系统将所有的I/O请求直接递交给操作系统,操作系统在完成这些请求后才通知I/O线程,这种异步I/O的方式使得I/O线程需要直接处理的任务很简单,即完成I/O操作后的一些收尾处理并发出 I/O 操作完成通知;如果操作系统不支持异步 I/O 操作,此时I/O线程需要完成实际的I/O操作。
4)调度线程
调度线程用于接管系统中所有需要定时调度的任务。调度线程每秒轮询一次,负责的任务如下。
(1)检查系统级的时间触发器,若满足触发条件则生成任务加到工作线程的任务队列中由工作线程执行。
(2)清理SQL缓存、计划缓存中失效的缓存项,或者超出缓存限制后淘汰不常用的缓存项。
(3)检查数据重演捕获持续时间是否到期,若到期则自动停止捕获。
(4)执行动态缓冲区检查,根据需要动态扩展或动态收缩系统缓冲池。
(5)自动执行检查点。为了保证日志的及时刷盘,缩短系统发生故障时需要的恢复时间,根据INI参数设置的自动检查点执行间隔定期执行检查点操作。
(6)会话超时检测。若用户连接设置了连接超时,则定期检测连接是否超时,如果超时则自动断开连接。
(7)在必要时执行数据更新页刷盘。
(8)唤醒等待的工作线程。
5)日志刷新(FLUSH)线程
任何数据库的修改,都会产生重做(REDO)日志,为了保证数据故障恢复的一致性,REDO日志的刷盘必须在数据更新页刷盘之前进行。事务在运行时,会把生成的REDO日志保留在日志缓冲区中,当事务提交或执行检查点时,会通知日志 FLUSH 线程进行日志刷盘。由于日志具备顺序写入的特点,比数据页分散I/O写入效率更高,因此,日志FLUSH线程和I/O线程分开,能获得更快的响应速度,保证整体的性能。DM8的日志FLUSH线程进行了优化,在刷盘之前,对不同缓冲区内的日志进行合并,减少了I/O次数,进一步提高了系统性能。如果系统配置了实时归档,则在日志 FLUSH 线程刷盘前,会直接将日志通过网络发送到实时备机。如果系统配置了本地归档或远程同步归档,则生成归档任务,通过日志归档线程完成。
6)日志归档线程
日志归档线程包含同步归档线程和异步归档线程,前者负责本地归档和远程同步归档任务,后者负责远程异步归档任务。如果系统配置了非实时归档,则由日志 FLUSH线程产生的任务会分别加入日志归档线程,日志归档线程负责从任务队列中取出任务,按照归档类型进行相应归档处理。将日志FLUSH线程和日志归档线程分开的目的是减少不必要的效率损失,除远程实时归档外,本地归档、远程同步归档、远程异步归档都可以脱离日志FLUSH线程进行,如果放在日志FLUSH线程中一起进行,则会严重影响系统性能。
7)日志重做线程
为了提高故障恢复效率,达梦数据库在故障恢复时采用了并行机制重做日志,日志重做线程就用于日志的并行恢复。通过INI参数LOG_REDO_THREAD_NUM可配置日志重做线程数,默认是2个线程。
8)日志应用(APPLY)线程
在配置了数据守护的系统中,创建了一个日志 APPLY 线程。当服务器作为备机时,每次接收到主机的物理 REDO 日志都生成一个日志 APPLY 任务加入任务队列中,日志APPLY线程从任务队列中取出一个任务在备机上重做日志,并生成自己的日志,以保持和主机数据的同步或一致,作为主机的一个镜像。备机数据对用户只读,可承担报表、查询等任务,以均衡主机的负载。
9)定时器线程
在数据库的各种活动中,用户常常需要数据库在某个时间点开始进行某种操作,如备份,或者在某个时间段内反复进行某种操作等。定时器线程就是为这种需求设计的。在通常情况下,DM服务器需要进行定时操作的事件主要有以下几种。
(1)逻辑日志异步归档。
(2)异步归档日志发送(只在PRIMARY模式下,且在OPEN状态下发送)。
(3)作业调度。
定时器线程启动之后,每秒检测一次定时器链表,查看当前的定时器是否满足触发条件,如果满足,则把执行权交给设置好的任务,如逻辑日志异步归档等。在默认情况下,DM服务器启动的时候,定时器线程是不启动的。用户可以将dm.ini中的TIMER_INI参数设置为1来设置定时器线程在系统启动时启动。
10)逻辑日志归档线程
逻辑日志归档用于 DM8 的数据复制,目的是加快异地访问的响应速度。逻辑日志归档线程包含本地逻辑日志归档线程和远程逻辑日志归档线程。在系统配置了数据复制后,系统才会创建这两个线程。
(1)本地逻辑日志归档线程:本地逻辑日志归档线程从本地归档任务队列中取出一个归档任务,生成到逻辑日志,并将逻辑日志写入逻辑日志文件中。如果当前逻辑日志的远程归档类型是同步异地归档,并且当前的刷盘机制是强制刷盘,那么就生成一个异地归档任务加入临时任务队列中。
(2)远程逻辑日志归档线程:远程逻辑日志归档线程从远程归档任务队列中取出一个归档任务,并根据任务的类型进行相应的处理。任务的类型包括同步发送任务和异步发送任务。
11)数据守护相关线程
在配置了数据守护的观察器上,会创建观察器的实时检测线程、同步检测线程,实现主机和备机之间的故障检测、故障切换及故障恢复。在配置了数据守护进程的数据守护方案中,数据库实例还会创建 UDP 消息的广播和接收线程,负责数据库实例和守护进程之间的通信,实现数据守护功能。
12)MAL系统相关线程
MAL(Mail)系统是达梦数据库内部的高速通信系统,基于 TCP/IP 协议实现。DM服务器的很多重要功能都是通过 MAL 系统实现通信的,如数据守护、数据复制、大规模并行处理(MPP)、远程日志归档等。MAL系统内部包含一系列线程,有MAL监听线程、MAL发送工作线程、MAL接收工作线程等。
13)其他线程
达梦数据库系统中不止包括以上线程,在一些特定的功能中会有不同的线程,如回滚段清理线程、审计写文件线程、重演捕获写文件线程等,这里不再一一列出。
2.内存结构
数据库管理系统是一种对内存申请和释放操作频率很高的软件,如果每次对内存的使用都通过操作系统函数来申请和释放,则系统效率会比较低,因此加入自己的内存管理系统是达梦数据库系统管理必需的。通常,内存管理系统会带来以下好处:
(1)申请、释放内存效率更高;
(2)能够有效地了解内存的使用情况;
(3)易于发现内存泄露和内存写越界的问题。
达梦数据库管理系统的内存结构主要包括内存池、缓冲区、排序缓冲区、哈希缓冲区等。根据系统中子模块的不同功能,达梦数据库管理系统对内存进行了上述划分,并采用了不同的管理模式。
1)内存池
DM服务器的内存池指的是共享内存池,根据内存使用情况的不同,共享内存池的使用有两种工作方式:HEAP和VPOOL。共享内存池用于解决DM服务器对于小片内存的申请与释放问题。系统在运行过程中,经常会申请与释放小片内存,而向操作系统申请和释放内存时需要发出系统调用,此时可能会引起线程切换,降低系统运行效率。采用共享内存池可一次向操作系统申请一片较大内存,即内存池。当系统在运行过程中需要申请内存时,在共享内存池内进行申请;当用完该内存后,再释放,即归还给共享内存池。当系统采用较好的策略管理共享内存池时,小片内存的申请与释放不会对系统造成太大影响。这种方式还有一个优点,可以比较容易地检测系统是否存在内存泄露。达梦数据库系统管理员可以通过 DM 服务器的配置文件(dm.ini)来对共享内存池的大小进行设置,共享内存池的参数为MEMORY_POOL,该配置默认为40MB。而HEAP和VPOOL使用的是共享内存池中的内存,所以在一般情况下,HEAP和VPOOL两种工作方式申请的内存大小不会超过MEMORY_POOL的值。
(1)HEAP:HEAP 的工作方式采用了堆的思想,即每次在申请内存时,都是从堆顶上申请的,如果内存不够,则继续向共享内存池申请内存页,然后加入HEAP中,继续供系统申请使用,这样HEAP的长度可以无限增长下去;在释放HEAP时,可以释放堆顶上的内存页,也可以释放整个HEAP。使用内存堆来管理小片内存的申请有一个特点,每次在申请小片内存后,不能单独对这片内存进行释放,也就是不用关心这片内存何时释放,而是在堆释放时统一释放,这样就能有效防止内存泄露的发生。
(2)VPOOL:VPOOL工作方式主要采用了“伙伴系统”的思想进行管理。申请的VPOOL内存分为私有VPOOL和公有VPOOL两种。私有VPOOL只提供给某个单独功能模块使用,公有VPOOL则提供给那些需要共享同一资源而申请的模块,所以需要对公有VPOOL进行保护,而私有VPOOL则不需要保护。
VPOOL和HEAP的区别在于,VPOOL申请的每片内存都可以单独进行释放。
2)缓冲区
(1)数据缓冲区。
数据缓冲区是DM服务器在将数据页写入磁盘之前,以及从磁盘上读取数据页之后,数据页存储的地方。数据缓冲区是DM服务器至关重要的内存区域之一,将其设定得太小,会导致缓冲页命中率低,磁盘 I/O 操作频繁;将其设定得太大,又会导致操作系统内存本身不够用。系统在启动时,首先根据配置的数据缓冲区大小向操作系统申请一片连续内存,并将其按数据页大小进行格式化,置入自由链中。数据缓冲区存在 3 条链来管理被缓冲的数据页:一条是自由链,用于存放目前尚未使用的内存数据页;一条是LRU链,用于存放已被使用的内存数据页(包括未修改的和已修改的);还有一条是脏链,用于存放已被修改的内存数据页。LRU链对系统当前使用的数据页按最近是否被使用的顺序进行排序。这样,当数据缓冲区中的自由链被用完时,从LRU链中淘汰部分最近未使用的数据页,能够最大限度地保证被淘汰的数据页最近不会被用到,以减少I/O操作。在系统运行过程中,通常存在一部分“非常热”(反复被访问)的数据页,将它们一直留在缓冲区中,对系统性能会有好处。数据缓冲区开辟了一个特定的区域用于存放这部分数据页,以保证这部分数据页不参与一般的淘汰机制,可以一直留在数据缓冲区中。
① 类别:DM服务器中有4种类型的数据缓冲区,分别是NORMAL缓冲区、KEEP缓冲区、FAST缓冲区和RECYCLE缓冲区。其中,用户在创建表空间或修改表空间时,可以指定表空间属于NORMAL缓冲区,还是属于KEEP缓冲区。RECYCLE缓冲区供TEMP表空间使用,FAST 缓冲区根据用户指定的 FAST_POOL_PAGES 和 FAST_ROLL_PAGES大小由系统自动进行管理,用户不能指定使用RECYCLE缓冲区和FAST缓冲区中的表或表空间。NORMAL 缓冲区主要提供给系统处理的一些数据页,在没有特定的指定缓冲区的情况下,默认缓冲区为 NORMAL 缓冲区;KEEP 缓冲区的特性是很少或几乎不怎么对缓冲区中的数据页进行淘汰,主要针对用户的应用是否需要经常处在内存当中,如果是,则可以指定缓冲区为KEEP缓冲区。DM服务器提供了可以更改这些缓冲区大小的参数,用户可以根据自己的应用需求情况,指定dm.ini文件中BUFFER(80MB)、KEEP(8MB)、RECYCLE(64MB)、FAST_POOL_PAGES(0)和 FAST_ROLL_PAGES(0)的值(括号中为默认值),这些值分别对应NORMAL缓冲区的大小、KEEP缓冲区的大小、RECYCLE缓冲区的大小、FAST缓冲区的页面数和FAST缓冲区的回滚页面数。
② 读多页:在需要进行大量I/O操作的应用中,达梦数据库之前版本的策略是每次只读取 1 个数据页。如果知道用户需要读取表的大量数据,当读取到第一页时,可以猜测用户可能需要读取这一页的下一页,在这种情况下,一次性读取多个数据页就可以减少I/O操作次数,从而提高数据的查询、修改效率。DM服务器提供了可以读取多个数据页的参数,用户可以指定这些参数来调整数据库运行效率的最佳状态。在DM服务器的配置文件dm.ini中,可以指定参数MULTI_PAGE_GET_NUM的大小(默认值为16页),以控制每次读取的数据页数。如果用户没有设置较适合的参数MULTI_PAGE_GET_NUM的大小,有时可能会给用户带来更差的运行效果。如果 MULTI_PAGE_GET_NUM 的值太大,每次读取的数据页可能大多不是以后所用到的数据页,这样不仅会增加 I/O 的操作次数,而且每次都会做一些无用的 I/O 操作,所以系统管理员需要衡量好自己的应用需求,给出最佳方案。
(2)日志缓冲区。
日志缓冲区是用于存放重做日志的内存缓冲区。为了避免由于直接的磁盘I/O操作而使系统性能受到影响,系统在运行过程中产生的日志并不会立即被写入磁盘,而是和数据页一样,先被存放到日志缓冲区中。那么,为何不在数据缓冲区中存放重做日志,而要单独设立日志缓冲区呢?其主要原因如下。
① 重做日志的格式同数据页完全不一样,无法进行统一管理。
② 重做日志具备连续写的特点。
③ 在逻辑上,写重做日志比数据页I/O操作优先级更高。
DM服务器提供了参数LOG_BUF_SIZE,以对日志缓冲区大小进行控制,日志缓冲区所占用的内存是从共享内存池中申请的,单位为页,并且大小必须为2N页,否则采用系统默认大小256页。
(3)字典缓冲区。
字典缓冲区主要存储一些数据字典信息,如模式信息、表信息、列信息、触发器信息等。每次对数据库的操作都会涉及数据字典信息,访问数据字典信息的效率直接影响到相应的操作效率。例如,进行查询操作,就需要相应的表信息、列信息等,这些数据字典信息如果都在缓冲区中,则直接从缓冲区中获取即可,否则,需要I/O操作才能读取这些信息。DM8采用将部分数据字典信息加载到缓冲区中,并基于LRU算法进行数据字典信息的控制。缓冲区如果设置得太大,会浪费宝贵的内存空间;如果设置得太小,可能会频繁地进行数据页淘汰,该缓冲区配置的参数为DICT_BUF_SIZE,默认的配置大小为5MB。DM8采用缓冲部分数据字典对象的方式,这会影响系统效率吗?数据字典信息访问存在热点现象,并不是所有的数据字典信息都会被频繁访问,所以按需加载数据字典信息并不会影响系统实际的运行效率。但是,如果在实际应用中涉及对分区数量较多的水平分区表的访问,如上千个分区,就需要适当调大DICT_BUF_SIZE参数的值。
(4)SQL缓冲区。
SQL缓冲区提供在执行SQL语句过程中所需要的内存,包括执行计划、SQL语句和结果集存放。在很多应用中都存在反复执行相同SQL 语句的情况,此时可以使用缓冲区保存这些SQL语句和它们的执行计划,这就是计划重用。这样做带来的好处是加快了SQL语句的执行效率,但同时给内存增加了压力。DM服务器的配置文件dm.ini中提供了参数来支持是否需要计划重用,参数为USE_PLN_POOL,当该参数指定为1时,启动计划重用;否则,禁止计划重用。达梦数据库还提供了参数 CACHE_POOL_SIZE(单位为 MB)来改变SQL缓冲区的大小,系统管理员可以设置该参数值以满足应用需求,默认值为10MB。
3)排序缓冲区
排序缓冲区提供数据排序所需要的内存空间。用户在执行SQL语句时,通常需要进行排序,所使用的内存就是排序缓冲区提供的。在每次排序过程中,系统都先申请内存,在排序结束后再释放内存。DM 服务器提供了参数来指定排序缓冲区的大小,参数SORT_BUF_SIZE在DM服务器的配置文件dm.ini中,系统管理员可以设置其大小以满足需求。由于该参数值是由系统内部的排序算法和排序数据结构决定的,因此建议使用默认值2MB。
4)哈希缓冲区
DM8提供了为哈希连接而设定的缓冲区,不过该缓冲区是虚拟缓冲区。之所以说是虚拟缓冲区,是因为系统没有真正创建特定的属于哈希缓冲区的内存,而是在进行哈希连接时,对排序的数据量进行了计算。如果计算得出的数据量超过了哈希缓冲区的大小,则使用 DM8 创新外存哈希方式;如果计算得出的数据量没有超过哈希缓冲区的大小,实际上使用的还是VPOOL内存池进行的哈希操作。DM服务器在配置文件dm.ini中提供了参数HJ_BUF_SIZE来进行控制,由于该参数值的大小可能会限制哈希连接的效率,所以建议保持默认值,或者设置为更大的值。
除提供 HJ_BUF_SIZE 参数外,DM 服务器还提供了创建哈希表个数的初始化参数,其中,HAGR_HASH_SIZE 表示在处理聚集函数时创建哈希表的个数,建议保持默认值100000个。
5)SSD缓冲区
固态硬盘(SSD)采用闪存作为存储介质,因没有机械磁头的寻道时间,其读写效率比机械磁盘更有优势。内存、SSD、机械磁盘均符合存储分级的条件。为提高系统执行效率,DM服务器将SSD文件作为内存缓存与普通磁盘缓存之间的缓冲层,称为SSD缓冲。DM服务器在dm.ini中提供参数SSD_BUF_SIZE和SSD_FILE_PATH来配置SSD缓冲区,SSD_BUF_SIZE用于指定SSD缓冲区的大小,单位是MB,DM服务器根据该参数创建相应大小的文件作为缓冲区使用;SSD_FILE_PATH指定SSD文件所在的文件夹路径,管理员需要保证设置的路径位于固态磁盘上。
默认SSD缓冲区是关闭的,即SSD_BUF_SIZE为0。若要配置SSD缓冲区,则将其设置为大于 0 的数,并指定 SSD_FILE_PATH 即可。根据存储分级的概念,建议将SSD_BUF_SIZE的值配置为BUFFER_SIZE值的2倍左右。