达梦数据库集群
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.1.1 数据守护的基本概念

为了更好地理解和掌握达梦数据库的数据守护功能,本节将对有关概念进行介绍,只有充分理解这些概念,才能更加深入地理解数据守护。

1. 数据库

数据库(Database)是一个文件集合(包括数据文件、临时文件、重做日志文件和控制文件),保存在物理磁盘或文件系统中。

在达梦数据库系统中,无论是单实例数据库还是DMDSC(达梦数据库数据共享集群),数据守护都是以数据库为单位进行管理的。单实例数据库好理解,对于DMDSC来说,则需要将其所有实例作为一个整体库来考虑,库的状态、模式等需要综合考虑集群内所有实例及DMDSC本身的状态。

2. DMDSC状态

DMDSC状态和数据库的状态不同,标识的是DMDSC的节点状态,包括Startup、Open、Crash_recv和Err_ep_add共4种。

(1)Startup(节点启动状态):需要通过DMCSS工具交互,确定主从节点,执行重做日志等相关步骤,进入Open状态。

(2)Open(实例正常工作状态):当集群内发生节点故障或启动节点重加入步骤时,可以进入Crash_recv或Err_ep_add状态,处理完成后会再回到Open状态。

(3)Crash_recv(节点故障处理状态)。

(4)Err_ep_add(故障节点重加入状态)。

3. 数据库模式

达梦数据库支持3种数据库模式:Normal模式、Primary模式和Standby模式。

1)Normal模式

在Normal模式下,数据库提供正常的服务,对操作没有限制。正常生成本地归档日志,但不发送实时(Realtime)、即时(Timely)和异步(Async)归档日志。

2)Primary模式

在Primary模式下,数据库提供正常的数据库服务,对操作有极少限制,部分功能受限,包括:不支持修改表空间文件名、不支持修改arch_ini参数;正常生成本地归档日志,支持实时归档、即时归档和异步归档;对临时表空间以外的所有数据库对象的修改操作都强制生成REDO日志。

3)Standby模式

在Standby模式下,可以执行数据库备份、查询等只读数据库操作;可以正常生成本地归档日志、正常发送异步归档REDO日志,但不能发送实时归档日志和即时归档日志;时间触发器、事件触发器等失效。

达梦数据库的3种数据库模式可以通过SQL语句进行切换,单实例数据库必须在Mount状态下执行,DMDSC模式必须在所有实例都处于Mount状态下才能进行,只需要在一个节点上执行SQL语句即可。

达梦数据库模式切换的SQL语句如表2-1所示。

表2-1 达梦数据库模式切换的SQL语句

4. 数据库状态

达梦数据库的状态包括Startup、After Redo、Open、Mount、Suspend、Shutdown共6种。

1)Startup状态

Startup状态是指达梦数据库系统刚启动时的状态。

2)After Redo状态

After Redo状态是指在达梦数据库系统启动过程中,在联机日志重做完成后回滚活动事务执行前的状态。非Standby模式的实例在执行“alter database open”操作前,也会将系统设置为After Redo状态。

3)Open状态

Open状态是指达梦数据库处于正常提供服务的状态。达梦数据库在Open状态下不能进行归档配置等操作。

4)Mount状态

达梦数据库在Mount状态下,会限制REDO日志刷盘,不能修改数据,不能访问表、视图等数据库对象,但可以执行修改归档配置、控制文件和修改数据库模式等操作,也可以执行一些不修改数据库内容的操作,如查询动态视图或进行一些只读的系统过程。

系统从Open状态切换为Mount状态时,需要回滚所有活动事务,但不会断开用户连接,也不会强制Buffer中的脏页刷盘。

5)Suspend状态

达梦数据库在Suspend状态下,会限制REDO日志刷盘,可以访问数据库对象,甚至可以修改数据,但是一旦执行Commit等操作触发REDO日志写盘时,当前操作就会被挂起。

相比从Open状态到Mount状态的切换,从Open状态到Suspend状态的切换更加简单、高效,不会回滚任何活动事务,在状态切换完成后,所有事务可以继续执行。

通常,在修改归档状态之前需要将系统切换为Suspend状态,如备库故障恢复后,在历史数据(归档日志)同步完成后,需要重新启用实时归档功能,具体包括4个步骤。

(1)将系统切换为Suspend状态,限制REDO日志写入联机REDO日志文件。

(2)修改归档状态为Valid。

(3)重新将数据库切换为Open状态,恢复REDO日志写入功能。

(4)备库与主库重新进入实时同步状态。

另外,当实时归档失败时(如网络故障导致),Primary实例将试图切换成Suspend状态,防止后续的日志写入。因为一旦写入,当主备库切换时,备库就有可能没有收到最后那次的RLOG_BUF,导致主库上多一段日志,很容易造成主备库数据不一致。当实例成功切换为Suspend状态时,可直接退出,强制丢弃多余的日志,避免主备库数据不一致。

对于DMDSC,当修改DMDSC库的状态为Suspend时,库内所有实例都不能处于Mount状态,只需要在一个节点上执行“alter database suspend”语句即可。

6)Shutdown状态

Shutdown状态是指达梦数据库实例正常退出时的状态。

达梦数据库的6种状态之间可以切换,但不能随意切换。例如,Open状态与Mount状态可以相互切换;Open状态与Suspend状态可以相互切换;Mount状态和Suspend状态不能直接转换。

达梦数据库的状态切换关系如图2-1所示。

图2-1 达梦数据库的状态切换关系

达梦数据库状态切换的SQL语句如表2-2所示。

表2-2 达梦数据库状态切换的SQL语句

【注意】由于达梦数据库监视器会将数据库模式、状态等信息作为故障处理、故障恢复的依据,因此建议在配置数据守护的过程中,修改dm.ini配置文件中ALTER_MODE_STATUS参数为0,限制用户直接通过SQL语句修改数据库模式和状态,以避免数据守护做出错误的决策。

5. LSN

LSN(Log Sequence Number)是由系统自动维护的BIGINT类型数值,具有自动递增、全局唯一特性,每个LSN都代表达梦数据库系统内部产生的一个物理事务。物理事务(Physical Transaction,PTX)是数据库内部一系列修改物理数据页操作的集合,与数据库管理系统中事务(Transaction)概念相对应,具有原子性、有序性、无法撤销等特性。

达梦数据库中与LSN相关的信息,可以通过查询V$RLOG表来获取。达梦数据库中主要有以下几种类型的LSN。

(1)CUR_LSN是系统已经分配的最大LSN。当物理事务被提交时,系统会为其分配一个唯一的LSN,大小等于CUR_LSN + 1,然后再修改CUR_LSN=CUR_LSN + 1。

(2)FILE_LSN是已经写入联机REDO日志文件的最大LSN。每次将REDO日志缓冲区RLOG_BUF写入联机REDO日志文件后,都要修改FILE_LSN值。

(3)FLUSH_LSN是已经发起日志刷盘请求,但还没有真正写入联机REDO日志文件的最大LSN值。

(4)CKPT_LSN是检查点LSN,所有LSN<=CKPT_LSN的物理事务修改的数据页,都已经从Buffer缓冲区写入磁盘,CKPT_LSN由检查点线程负责调整。

与达梦数据库数据守护相关的LSN信息如下。

(1)CLSN与CUR_LSN保持一致,是数据库已经分配的最大LSN。

(2)FLSN与FILE_LSN保持一致,是已写入联机日志文件的LSN。

(3)SLSN是Standby LSN的缩写,是备库收到的最后一个RLOG_BUF的最大LSN,与主库的FLUSH_LSN保持一致。

(4)SSLSN是Second Standby LSN的缩写,是实时主备或MPP主备中备库收到的倒数第二个RLOG_BUF的最大LSN。在读写分离集群中SLSN == SSLSN。

(5)APPLY_LSN:备库故障重启,主库重新同步历史数据时,需要知道主库实例中哪些日志已经在备库重做了,备库记录DMDSC主库各个节点日志重做情况的LSN称为APPLY_LSN,它是备库重演过的最大LSN。当主库是单节点时,备库的APPLY_LSN等同于备库的CUR_LSN。

6. REDO日志

REDO日志包含了所有物理数据页的修改内容,INSERT、DELETE、UPDATE等DML操作,以及CREATE TABLE等DDL操作,最终都会转化为对物理数据页的修改,这些修改都会反映到REDO日志中。

一般说来,一条SQL语句在系统内部会转化为多个相互独立的物理事务来完成,物理事务提交时会将产生的REDO日志写入缓冲区RLOG_BUF中。一个物理事务包含一条或多条REDO记录,每条REDO记录(RREC)都对应一个修改物理数据页的动作。

根据记录内容的不同,RREC可以分为两类:物理RREC和逻辑RREC。物理RREC记录的是数据页的变化情况,内容包括操作类型、修改数据页地址、页内偏移、数据页上的修改内容,如果是变长类型的REDO记录,在RREC的记录头之后还会有一个两字节的长度信息。逻辑RREC记录的是一些数据库逻辑操作步骤,主要包括事务启动、事务提交、事务回滚、字典封锁、事务封锁、B树封锁、字典淘汰等。逻辑RREC是专门为数据守护增加的记录类型,用来解决备库重演REDO日志与用户访问备库之间的并发冲突,以及主库执行DDL后导致的主备数据库字典缓存不一致问题。备库解析到逻辑RREC时,根据记录内容,生成相应的事务,封锁对应的数据库对象,并从数据库字典缓存中淘汰过期的字典对象。

物理事务(PTX)和REDO记录(RREC)的结构如图2-2所示。

图2-2 PTX和RREC的结构

7. REDO日志缓冲区

REDO日志缓冲区RLOG_BUF是达梦数据库内部的一个数据结构,用来优化、提升REDO日志刷盘效率。在物理事务提交时将REDO日志写入RLOG_BUF中,在数据库事务提交或RLOG_BUF缓冲区被写满时触发日志刷盘动作。日志刷盘线程负责将RLOG_BUF中的REDO日志写入联机日志文件,如果配置了REDO日志归档,日志刷盘线程还将负责触发归档动作。在数据守护系统中,主库以RLOG_BUF缓冲区为最小单位,发送REDO日志到备库。

RLOG_BUF由一系列的RLOG_PAGE组成,其结构如图2-3所示,RLOG_PAGE是物理事务的保存载体,一个RLOG_PAGE可以保存一个或多个物理事务信息,一个物理事务,甚至一条REDO记录也可能需要存放到多个RLOG_PAGE中。

图2-3 达梦数据库RLOG_BUF的结构

8. KEEP_BUF

达梦数据库在将主库的RLOG_BUF日志通过实时归档机制发送到备库后,备库将最新收到的RLOG_BUF保存在内存中,不马上启动重演,这个RLOG_BUF称为KEEP_BUF。

引入KEEP_BUF的主要目的是,避免在某些场景中主库故障重启后发生不必要的主备库切换,以减少用户干预。例如,如表2-3所示的场景将会带来必要的用户干预。

表2-3 实时主备或MPP主备场景

引入KEEP_BUF后,备库B收到主库A发送的RLOG_BUF,并不会马上启动日志重演,主库A重启后,守护进程A检测到备库B存在KEEP_BUF,通知备库B丢弃KEEP_BUF后,直接Open主库A,就可以继续提供数据库服务。另外,这些操作是由守护进程自动完成的,不需要用户干预。

如果备库自动接管或用户发起备库接管命令,那么备库的KEEP_BUF将会启动重演,不管主库是否已经将KEEP_BUF对应的REDO日志写入联机日志文件中,备库接管时APPLY_LSN一定大于或等于主库的FILE_LSN。故障主库在重启后,仍然可以作为备库,并自动重新加入数据守护系统。

备库KEEP_BUF日志重演的时机包括以下几种。

1)收到主库的重演命令且备库的SLSN满足重演条件

主库会定时(每5秒)将FILE_LSN等信息发送到备库,当主库FILE_LSN等于备库SLSN时,表明主库已经将KEEP_BUF对应的REDO日志写入联机日志文件中,此时备库会启动KEEP_BUF的日志重演。

2)备库收到新的RLOG_BUF

当备库收到新的RLOG_BUF时,会将当前保存的KEEP_BUF日志重演,并将新收到的RLOG_BUF再次放入KEEP_BUF中。

3)备库切换为新主库

在监视器执行Switchover或Takeover命令,或者确认监视器通知备库自动接管时,备库会在切换为Primary模式之前,启动KEEP_BUF的日志重演。

【注意】即时归档日志在RLOG_BUF写入主库联机REDO日志文件后,再发送RLOG_BUF到备库,因此即时备库没有KEEP_BUF。

9. 联机REDO日志文件

达梦数据库默认包含两个联机REDO日志文件(如DAMENG01.log、DAMENG02.log,在系统内部分别称为0号文件、1号文件),用来保存REDO日志,RLOG_BUF顺序写入联机REDO日志文件中,在一个日志文件写满后,自动切换到另一个REDO日志文件。其中,0号文件是REDO日志主文件,在日志主文件头中保存了如CKPT_LSN、CKPT_FILE、CKPT_OFFSET、FILE_LSN等信息。数据库系统故障重启时,从[CKPT_FILE, CKPT_OFFSET]位置开始读取REDO日志,解析RREC,并重新修改对应数据页内容,确保将数据恢复到数据库系统故障前的状态。

随着检查点(Checkpoint)的推进,对应产生REDO日志的数据页从数据缓冲区(Data Buffer)写入磁盘后,联机REDO日志文件可以覆盖重用、循环使用,确保REDO日志文件不会随着日志量的增加而增长。

【注意】任何数据页从Buffer缓冲区写入磁盘之前,都必须确保修改数据页产生的REDO日志已经写入联机REDO日志文件中。

在联机日志文件中,可以覆盖写入REDO日志的文件长度为可用日志空间;不能被覆盖且数据库系统故障重启需要重做部分为有效REDO日志,有效REDO日志的LSN取值范围是(CKPT_LSN, FILE_LSN];已经被发起日志刷盘请求,但还没有真正写入联机REDO日志文件的区间为(FILE_LSN, FLUSH_LSN],称为待写入日志空间。

图2-4说明了联机日志文件、日志缓冲区RLOG_BUF及相关LSN之间的关系。

图2-4 联机日志文件、日志缓冲区RLOG_BUF及相关LSN之间的关系

10. MAL系统

MAL系统是基于TCP协议实现的一种内部通信机制,具有可靠、灵活、高效的特性。达梦数据库通过MAL系统实现REDO日志传输,以及其他一些实例间的消息通信。

11. OGUID

OGUID是数据守护的唯一标识码,在配置数据守护时,需要由用户指定OGUID值。其中,数据库的OGUID值在Mount状态下由系统函数SP_SET_OGUID设置,守护进程和监视器的OGUID值在配置文件中设定。

同一个守护进程组中的所有数据库、守护进程和监视器,都必须配置相同的OGUID值,其取值范围为0~2147483647。

OGUID的查询方式如下:

12. 守护进程组

配置了相同OGUID值的两个或多个守护进程,构成一个守护进程组。为方便管理,对每个守护进程组进行命名,守护进程组中所有的守护进程和监视器必须配置相同的组名。

13. 组分裂

在同一个守护进程组中,不同数据库实例的数据出现不一致,并且无法通过重演REDO日志重新同步数据,被称为组分裂。

引发组分裂的主要原因如下。

(1)在即时归档日志中,主库在将REDO日志写入本地联机REDO日志文件之后,发送REDO日志到备库之前出现故障,导致主备库数据不一致,为了继续提供服务,执行备库强制接管。此时,在故障主库重启后,就会引发组分裂。

(2)在故障备库重新完成数据同步之前,主库硬件故障,并且长时间无法恢复;在用户接收丢失部分数据的情况下,为了尽快恢复数据库服务,执行备库强制接管,将备库切换为主库。此时,如果故障主库重启,就会造成组分裂。

在检测到组分裂后,守护进程会修改控制文件为分裂状态,被分裂出去的数据库需要通过备份还原等技术手段重新恢复,或者按照分裂库修复步骤重新将数据恢复到一致状态。

14. 脑裂

脑裂是指在同一个守护进程组中,同时出现两个或多个活动主库,并且这些主库都接收用户请求,提供完整数据库服务。一旦发生脑裂,将无法保证数据一致性,对数据安全会造成严重威胁。

达梦数据库数据守护系统为预防脑裂做了大量工作,如故障自动切换模式数据守护,必须配置确认监视器。确认监视器在启动故障切换之前,会进行严格的条件检查,避免脑裂发生。守护进程一旦检测到脑裂发生,就会马上强制退出主库,等待用户干预,避免数据差异进一步扩大。

通常造成脑裂的主要原因有两个:一是网络不稳定;二是错误的人工干预。为避免出现脑裂,可采取以下措施。

(1)在dm.ini配置文件中设置参数ALTER_MODE_STATUS=0,限制用户直接通过SQL修改数据库模式和状态。

(2)提供稳定、可靠的网络环境。

(3)当配置自动切换数据守护时,将确认监视器部署在独立的第三方机器上,不要与某一个数据库实例部署在一起,避免由于网络问题触发自动故障切换,导致脑裂发生。

(4)通过人工干预,在将备库切换为主库之前,一定要确认主库已经发生故障,避免在主库活动的情况下,备库强制接管,人为造成脑裂。