达梦主备集群顾名思义就是一主一备(也可以一主多备)是一种集成化的高可靠性解决方案,同时满足用户对数据安全性和高可用性的要求。解决由于硬件故障、自然灾害等原因导致的数据库服务长时间中断问题,满足用户不间断提供数据库服务的要求,即实现系统的双机热备功能。在使用的过程中,如果是实时同步模式的话,主机和备机的数据保持完全一致。主机产生一条新的记录时,在记录写入数据库文件之前,会把新产生的redo日志文件发送到备机,由备机重新执行接收到的redo日志,来保证主备集群数据的一致性。
如果主机发生故障,则备机会自动切换为主机,代替原主机的职能。以此保证服务的连续性。在原主机故障恢复之后,重新加入集群之后,则变为备机,由新主机继续执行相关的任务,并同步数据到备机。
一、达梦主备相关概念
1、主库
Primary 模式,提供完整数据库服务的实例,一般来说主库是用来直接支撑应用系统的生产库。
2、备库
Standby 模式,提供只读数据库服务的实例。备库除了用于容灾,还可以提供备份、查询等只读功能,并且备库还支持临时表的 Insert/Delete/Update 操作。
3、MAL 系统
MAL 系统是基于 TCP 协议实现的一种内部通信机制,具有可靠、灵活、高效的特性。DM 通过 MAL 系统实现 Redo 日志传输,以及其他一些实例间的消息通讯。
4、Redo 日志
Redo 日志包含了所有物理数据页的修改内容,Insert/delete/update 等 DML 操作、Create Table 等 DDL 操作,最终都会转化为对物理数据页的修改,这些修改都会反映到 Redo 日志中。
5、Redo 日志包(RLOG_PKG)
Redo 日志包(RLOG_PKG)是 DM 数据库批量保存物理事务产生的 Redo 日志的数据单元,以物理事务 PTX 为单位保存日志,一个日志包内可连续保存一个或多个 PTX。日志包具有自描述的特性,日志包大小不固定,采用固定包头和可变包头结合的方式,包头记录日志的控制信息,包括类型、长度、包序号、LSN 信息、产生日志的节点号、加密压缩信息、日志并行数等内容。
日志包生成时按照序号连续递增,相邻日志包的 LSN 顺序是总体递增的,但是在多节点集群的 DSC 环境下不一定连续。如果未开启并行日志,RLOG_PKG 包内日志的 LSN 是递增的。如果开启并行日志,一个 RLOG_PKG 包内包含多路并行产生的日志,每一路并行日志的 LSN 是递增的,但是各路之间并不能保证 LSN 有序,因此并行日志包内 LSN 具有局部有序,整体无序的特点。
物理事务提交时将 Redo 日志写入到日志包中,在数据库事务提交或日志包被写满时触发日志刷盘动作。日志刷盘线程负责将日志包中的 Redo 日志写入联机日志文件,如果配置了 Redo 日志归档,日志刷盘线程还将负责触发归档动作。DM 数据守护系统中,主库以RLOG_PKG 为最小单位发送 Redo 日志到备库。RLOG_PKG 具有自描述、自校验特征,数据的组织形式更加灵活、高效,支持 HUGE 表操作产生 Redo 日志,并且支持以 RLOG_PKG 为单位进行日志加密和压缩。
6、Redo 日志传输
主备库之间的 Redo 日志传输,以日志包 RLOG_PKG 为单位,主库通过 MAL 系统发送Redo 日志到备库。各种不同数据守护类型的区别,就在于主库日志包 RLOG_PKG 的发送时机,以及备库收到 Redo 日志后的处理策略,这个后边章节会介绍(主备同步方式)。
7、KEEP_PKG 介绍
主库的RLOG_PKG日志通过实时归档机制发送到备库后,备库将最新收到的RLOG_PKG通过重演服务保存在内存中,不马上启动重演,这个 RLOG_PKG 我们称之为 KEEP_PKG。
8、Redo 日志重演
Redo 日志重演的过程,就是备库收到主库发送的 Redo 日志后,在物理数据页上,重新修改数据的过程。Redo 日志重演由专门的 Redo 日志重演服务完成,重演服务严格按照Redo 日志产生的先后顺序,解析 Redo 日志、修改相应的物理数据页,并且重演过程中备库会生成自身的 Redo 日志写入联机日志文件。
9、本地归档
本地归档(Local),就是将 Redo 日志写入到本地归档日志文件的过程。本地归档在 REDO 日志写入联机日志文件后触发,由归档线程完成本地归档动作;与联机 Redo 日志文件可以被覆盖重用不同,本地归档日志文件不能被覆盖,写入其中的 Redo 日志信息会一直保留,直到用户主动删除;如果配置了归档日志空间上限,系统会自动删除最早生成的归档 Redo 日志文件,腾出空间,(即archive max size参数设置)。
配置本地归档情况下,Normal/Primary 模式库在 Redo 日志写入联机 Redo 日志文件后,将对应的 RLOG_PKG 由专门的归档线程写入本地归档日志文件中。Standby 模式库收到主库产生的 Redo 日志后,直接进行本地归档,写入本地归档日志文件中,同时启动 Redo 日志重演。
Normal/Primary 模式库归档日志文件保存的是当前节点产生的 Redo 日志,归档日志文件内容与联机日志内容保持一致。Standby 模式库重演日志重新产生的 Redo 日志只写入联机日志文件,归档日志文件保存主库产生的 Redo 日志,因此备库联机日志文件内容和归档日志文件内容是不完全一致的。采用这种归档实现方式后,可以确保数据守护系统中所有节点的归档日志文件内容是完全一致的。
10、实时归档
与本地归档写入保存在磁盘中的日志文件不同,实时归档(Realtime)将主库产生的Redo 日志通过 MAL 系统传递到备库,实时归档是实时主备和 MPP 主备的实现基础。实时归档只在主库生效,一个主库可以配置 1~8 个实时备库。
二、达梦主备守护集群组件及原理
达梦主备原理图
1、达梦主备守护集群各组件概述
1、达梦监视器monitor
- ①监控数据守护进程发送的消息(主、备数据库状态变化、故障切换过程中数据库模式、状态变化的完整过程);
- ②用户可以在监视器上输入命令,启动、停止守护进程的监控功能,执行主备库切换、备库故障接管等操作;
- ③发起故障自动接管命令,主库发生故障时,挑选符合接管条件的备库,并通知备库执行接管操作。
2、守护进程dbwatcher
- 守护进程负责监控数据库运行状态,必要时重启数据库服务。守护进程和实例链路建立成功后,数据库实例定时发送信息到守护进程,发送到守护进程的内容包括:实例进程ID、实例名、数据库模式、数据库状态、FILE_SEQ、FILE_LSN、CUR_SEQ、CUR_LSN、MAL链路状态、归档状态、公钥、MPP控制文件等信息。
- 守护进程更新本地记录的实例信息后,同时记录该时间戳。当检测到实例进程ID已经不存在或者超过一段时间没有收到实例消息(INST_ERROR_TIME),则会认定实例故障。如果配置了自动重启,则会将实例重新拉起。
3、主备数据同步原理
达梦主备数据同步原理图
主备集群同步机制归档流程
3.1、实时主备同步流程:
1、DDL和DML提交事务操作使主库产生Redo 信息,Redo 信息会存放在RLOG_PKG(Redo 日志包)中,在此过程中RLOG_PKG存放在内存当中,暂时不会写入联机日志中;
2、实时同步:MAL通讯系统将主库的RLOG_PKG包通过实时归档机制发送到备库B中,备库将最新收到的RLOG_PKG保存在内存中,然后进行校验是否合法,合法后标记为 KEEP_PKG,不会马上启动重演,但会将之前的KEEP_PKG通过APPLY线程队列加入日志重演任务系统,并马上响应主库,不需要等待之前的Redo日志重演结束后再响应主库;
3、为了防止备库上重演日志堆积太多、占用大量内存、备库重演无响应导致主库挂住不能提供服务等情况的发生 ,可通过适当调整 BUFFER 、REDOS_PRE_LOAD 、REDOS_BUF_SIZE、REDOS_BUF_NUM、REDOS_MAX_DELAY 这几个参数达到加快备库重演速度、达到设置的堆积上限后延迟响应主机 、 备库自动宕机等目的 。 其中REDOS_BUF_SIZE,REDOS_BUF_NUM 同时起作用,只要达到一个条件即延迟响应。
(注意:备库确认收到主库发送的Redo 日志,并不保证备库已经完成重演这些 Redo 日志,因此主备库之间的数据同步存在一定的时间差。一般情况下延迟时间非常短暂,用户几乎感觉不到,不能严格保证事务一致性。)
备库 KEEP_PKG 日志重演的时机包括:
1.备库收到新的 RLOG_PKG
备库收到新的 RLOG_PKG 时,会将当前保存的 KEEP_PKG 日志重演,并将新收到的RLOG_PKG 再次放入
KEEP_PKG 中。
2. 收到主库的重演命令
主库会定时将 FILE_LSN 等信息发送到备库,当主库 FILE_LSN 等于备库 SLSN 时,表明主库已经将
KEEP_PKG 对应的 Redo 日志写入联机日志文件中,此时备库会启动KEEP_PKG 的日志重演。
3. 备库切换为新主库
在监视器执行 SWITCHOVER 或 TAKEOVER 命令,或者确认监视器通知备库自动接管时,备库会在切换为
PRIMARY 模式之前,启动 KEEP_PKG 的日志重演。
4、主库收到备库的响应消息,确认备库已经收到 Redo 日志后,主库再将 Redo 日志写入联机日志文件中。
3.2、实时主备系统主要好处和功能
(1)实时数据同步
主备库通过实时归档完成数据同步,实时归档要求主库将 RLOG_PKG 发送到备库后,再将RLOG_PKG 写入本地联机 Redo 日志文件。但要注意的是,备库确认收到主库发送的Redo 日志,并不保证备库已经完成重演这些 Redo 日志,因此主备库之间的数据同步存在一定的时间差。
(2)主备库切换,主备库正常运行过程中,可以通过监视器的 Switchover 命令,一键完成主备库角色转换。主备库切换功能可以确保在软、硬件升级,或系统维护时,提供不间断的数据库服务。
(3)自动故障处理
备库故障,不影响主库正常提供数据库服务,守护进程自动通知主库修改实时归档为Invalid 状态,将实时备库失效。
(4)自动数据同步
备库故障恢复后,守护进程自动通知主库发送归档 Redo 日志,重新进行主备库数据同步。并在历史数据同步后,修改主库的实时归档状态为 Valid,恢复实时备库功能。备库接管后,原主库故障恢复,守护进程自动修改原主库的模式为 Standby,并重新作为备库加入主备系统。
(5)备库接管
主库发生故障后,可以通过监视器的 Takeover 命令,将备库切换为主库,继续对外提供服务。如果配置为自动切换模式,确认监视器可以自动检测主库故障,并通知备库接管,这个过程不需要人工干预。
(6)备库强制接管
如果执行 Takeover 命令不成功,但主库可能由于硬件损坏等原因无法马上恢复,为了及时恢复数据库服务,DM 提供了 Takeover Force 命令,强制将备库切换为主库。但需要由用户确认主库故障前,主库与接管备库的数据是一致的(主库到备库的归档是 Valid状态),避免引发守护进程组分裂。注意:执行Takeover Force有可能引发组分裂,而Takeover命令在确保不会产生组分裂情况下才允许执行。
2、监视器模式分类和区别
达梦监视器分2种类型:确认监视器和普通监视器。两者区别在于:确认监视器除了具备监控模式监视器所有功能外,还具有状态确认和自动接管两个功能。
- 监控模式(dmmonitor.ini: MON_DW_CONFIRM=0)
- 确认模式(dmmonitor.ini: MON_DW_CONFIRM=1)
两种监视器的配置如下:
1、确认监视器的配置文件 dmmonitor.ini
MON_DW_CONFIRM = 1 #确认监视器模式
MON_LOG_PATH = /home/dmdba/dmdbms/data/log #监视器日志文件存放路径
MON_LOG_INTERVAL = 60 #每隔 60s 定时记录系统信息到日志文件
MON_LOG_FILE_SIZE = 32 #每个日志文件最大 32M
MON_LOG_SPACE_LIMIT = 0 #不限定日志文件总占用空间
[GRP1]
MON_INST_OGUID = 453332 #组 GRP1 的唯一 OGUID 值
#以下配置为监视器到组 GRP1 的守护进程的连接信息,以IP:PORT的形式配置
#IP 对应 dmmal.ini 中的 MAL_HOST,PORT 对应 dmmal.ini 中的 MAL_DW_PORT
MON_DW_IP = 172.16.1.141:52141
MON_DW_IP = 172.16.1.142:52142
2、普通监视器的配置文件 dmmonitor1.ini
MON_DW_CONFIRM = 0 #非确认监视器模式
MON_LOG_PATH = /home/dmdba/dmdbms/data/log #监视器日志文件存放路径
MON_LOG_INTERVAL = 60 #每隔 60s 定时记录系统信息到日志文件
MON_LOG_FILE_SIZE = 32 #每个日志文件最大 32M
MON_LOG_SPACE_LIMIT = 0 #不限定日志文件总占用空间
[GRP1]
MON_INST_OGUID = 453332 #组 GRP1 的唯一 OGUID 值
MON_DW_IP = 172.16.1.141:52141
MON_DW_IP = 172.16.1.142:52142
3、操作命令:
- tip查看系统当前运行状态。
- list列出所有守护进程配置信息。
- show显示全局信息。
- login登录监视器。
- logout登出监视器
- 更多命令使用方法可以输入help查找。
3、数据同步方式
达梦的主备数据同步方式分为实时和即时主备两种,类似oracle dg的数据保护模式:最大保护、最大可用、最大性能,而达梦主备同步模式分为:事务一致模式(实时)和高性能模式(即时)。由dmarch.ini配置文件中的ARCH_WAIT_APPLY 配置项决定:
- 为0表示高性能模式
- 为1表示事务一致模式
1、实时主备(实时主备默认是高性能模式模式)
- 主库在 Redo 日志(RLOG_PKG)写入联机日志文件前,将 Redo日志发送到备库,
- 备库收到 Redo 日志(RLOG_PKG)后标记为 KEEP_PKG,
- 将原 KEEP_PKG加入日志重演任务系统,并马上响应主库。
- 不需要等待 Redo 日志重演结束后再响应主库。
- 主库收到备库的响应消息,确认备库已经收到 Redo 日志后,再将 Redo 日志写入联机日志文件中。
- ARCH_WAIT_APPLY 配置项默认值为 0,即采用高性能模式
2、即时主备(即时主备默认是事务一致模式)
- 主库将 Redo 日志写入联机日志文件后
- 通过 MAL 系统将 Redo日志发送到备库。
- 即时归档,ARCH_WAIT_APPLY 默认是1,重演完后响应主库。
- 即时归档的同步机制可以保证备库的 Redo 日志不会比主库的 Redo 日志多。
- 备库故障或主备库之间网络故障,导致发送 RLOG_PKG 失败后,主库马上修改即时归档为 Invalid 状态,并切换数据库为 Suspend 状态。
二、主备切换机制即故障处理场景
1、数据库模式
(1)Normal 模式
提供正常的数据库服务,操作没有限制。正常生成本地归档,但不发送实时归档(Realtime)、即时归档(Timely)和异步归档(Async)。
(2)Primary 模式
提供正常的数据库服务,操作有极少限制。该模式下部分功能受限,包括:不支持修改表空间文件名、不支持修改 arch_ini 参数。正常生成本地归档,支持实时归档(Realtime)、即时归档(Timely)和异步归档(Async)。Primary 模式下,对临时表空间以外的所有的数据库对象的修改操作都强制生成 Redo 日志。
(3)Standby 模式
可以执行数据库备份、查询等只读数据库操作。正常生成本地归档,正常发送异步归档Redo 日志;但实时归档(Realtime)、即时归档(Timely)均强制失效。该模式下时间触发器、事件触发器等都失效。
2、数据库状态
(1)Startup 状态
系统刚启动时设置为 Startup 状态。
(2)After Redo 状态
系统启动过程中联机日志重做完成后,回滚活动事务前设置为 After Redo 状态。非Standby 模式的实例在执行 alter database open 操作前,也会将系统设置为 After Redo 状态。
(3)Open 状态
数据库处于正常提供服务的状态,但不能进行归档配置等操作。
(4)Mount 状态
数据库在 Mount 状态下,不能修改数据,不能访问表、视图等数据库对象,但可以执行修改归档配置、控制文件和修改数据库模式等操作,也可以执行一些不修改数据库内容的操作,比如查询动态视图或者一些只读的系统过程。由于 Mount 状态不生成 PWR 日志,因此数据页可以正常刷盘,也正常推进检查点。系统从 Open 状态切换为 Mount 状态时,会强制回滚所有活动事务,但不会强制清理(Purge)已提交事务,不会强制断开用户连接,也不会强制 Buffer 中的脏页刷盘。
(5)Suspend 状态
数据库在 Suspend 状态下,可以访问数据库对象,甚至可以修改数据,但限制 Redo日志刷盘,一旦执行 COMMIT 等触发 Redo 日志刷盘的操作时,当前操作将被挂起。相比 Open 到 Mount 的状态切换,Open 到 Suspend 的状态切换更加简单、高效,不会回滚任何活动事务,在状态切换完成后,所有事务可以继续执行。一般在修改归档状态之前将系统切换为 Suspend 状态,比如备库故障恢复后,在历史数据(归档日志)同步完成后,需要重新启用实时归档功能时:
- 将系统切换为 Suspend 状态,限制 Redo 日志写入联机 Redo 日志文件;
- 修改归档状态为 Valid;
- 重新将数据库切换为 Open 状态,恢复 Redo 日志写入功能;
- 备库与主库重新进入实时同步状态。 另外,实时归档失败时(比如网络故障导致),Primary 实例将试图切换成 Suspend状态,防止后续的日志写入。因为一旦写入,主备切换时有可能备库没有收到最后那次的RLOG_PKG,导致主库上多一段日志,很容易造成主备数据不一致。当实例成功切换为SUSPEND 状态时,可直接退出,强制丢弃多余的日志,避免主备数据不一致。
(6)Shutdown 状态
实例正常退出时设置为 Shutdown 状态。
3、集群故障处理
(1)备库故障处理
故障自动切换模式下,备库故障后,如果主备库之间的归档状态仍然有效,主库的守护进程会先切换为 Confirm 状态,等待确认监视器的确认消息,如果确认为符合故障处理条件,主库守护进程再切换至 Failover 状态,将故障备库的归档失效。
故障手动切换模式下,备库故障后,如果主备库之间的归档状态仍然有效,会直接切换到 Failover 状态,并将故障备库的归档失效,不需要备库故障确认。备库故障后,备库的守护进程如果还处于活动状态且监控功能没有被关闭,则会切换到Startup 状态下。
备库故障重启后,如果存在活动主库,主库守护进程根据备库实例的模式、状态、备库守护进程状态、守护进程控制文件状态、备库已经同步到的 Open 记录以及备库的恢复间隔等信息判断是否可以进行故障恢复,在满足故障恢复条件的情况下,主库守护进程启动Recovery 流程,重新恢复主备库到一致状态。如果一直没有观察到主库守护进程发起 Recovery 流程,可以借助监视器的 check recover 命令查找备库不满足条件的原因,并做对应的处理。
(2)备库异常处理
备库异常,指备库的数据库实例正常,但响应速度出现异常,这里的响应速度可能受主备库之间的网络影响,比如网络不稳定、网速大幅下降,也可能受备库自身的软硬件影响,比如操作系统原因或磁盘读写速度异常降低等异常情况导致响应主库的速度变慢,这种情况下会极大拖慢主库性能,影响主库正常处理对外的业务请求。
守护进程提供 RLOG_SEND_THRESHOLD 参数用于监控主备之间的日志发送速度,此参数应配置为大于 0 的值,否则守护进程不会打开监控功能。主库守护进程在 Open 状态下对日志发送速度进行检测,一旦检测到异常,主库守护进程会切换到 Standby check 状态,并通知主库将异常备库的归档失效,暂停到此备库的数据同步,避免拖慢主库性能。
完整的备库异常处理流程如下(Standby check 状态处理):
- 收集所有的异常备库。
- 将主库守护进程上记录的这些异常备库的最近一次恢复时间修改为当前时间。恢复间隔仍然为 dmwatcher.ini 中配置的 INST_RECOVER_TIME 值。这一步骤的目的是为了防止修改备库归档为 Invalid 无效状态后,主库立马启动 recovery,但是还未取到备库最新的 LSN 信息,导致 recovery 无法正确执行的情况发生。
- 通知主库修改这些异常备库的归档为 Invalid 无效状态。
- 守护进程切回 Open 状态。
(3)主库故障处理
故障自动切换模式下,主库故障后,确认监视器会捕获到故障信息,自动选出可接管的备库,并通知备库进行接管。备库接管由确认监视器自动触发,无需用户干预。故障手动切换模式下,主库故障后,需要人工干预,通过监视器执行接管命令,将可接管备库切换为主库。
故障自动切换模式下,可以实时处理故障,但对网络稳定性要求更高,需要确保主备库之间,主备库与守护进程、确认监视器之间的网络稳定可靠,否则可能会误判主库故障,备库自动接管后,出现多个 Open 状态的主库,引发脑裂。故障手动切换模式下,备库不会自动接管,出现节点故障或者网络故障时,由用户根据各种故障情况,进行人工干预。
主库故障重启后,守护进程根据本地和远程库的 Open 记录、LSN 信息以及模式和状态信息来判定重启后的恢复策略,可能继续作为主库加入守护系统,也可能修改为 Standby模式,以备库身份重新加入守护系统,如果出现分裂,则需要用户干预。
(4)故障恢复处理
故障恢复状态(Recovery)由守护进程自行判断是否切换,和监视器无关。如果符合以下条件,主库的守护进程可自动进入 Recovery 状态,进行数据恢复:
- 本地主库 [Primary,Open],守护进程 Open 状态;
- 远程备库[Standby,Open],归档状态 Invalid,守护进程 Open 状态;
- 远程备库[Standby,Open]的ASEQ/ALSN和SSEQ/SLSN相等,没有待重做日志;
- 根据 Open 记录等信息判断备库可加入;
- 远程备库[Standby,Open]达到了设置的启动恢复的时间间隔。
对于前 4 点,只是概括说明,详细的条件比较多,这里不再逐一列出,如果某个备库一直没有被恢复,可以借助监视器的 check recover 命令来查找备库无法进行恢复的原因。
对于第 5 点,可通过配置主库守护进程 dmwatcher.ini 的 INST_RECOVER_TIME来控制,取值(3s~ 86400 s),该值对所有备库有效,可通过监视器的 show arch send info 命令查看当前设置的到指定备库的恢复时间间隔。也可以使用监视器的 set recover time 命令来动态设置指定备库的恢复间隔,该命令只会修改命令中指定的备库的恢复间隔,并且只保存在主库的守护进程内存中,不会写入到 dmwatcher.ini 文件。
在主备库运行正常,不需要执行备库故障恢复的情况下,主库守护进程内存中对备库的恢复间隔值和 dmwatcher.ini 中配置的 INST_RECOVER_TIME 值是一致的,在某些场景下会被设置为不同的值,下面分别进行说明:
①主库守护进程主动设置恢复间隔为 3s
在以下场景中,主库的守护进程会重置内存中的 INST_RECOVER_TIME 为 3s,对满足前述前 4 个条件的备库在 3s 后会立即启动恢复流程:
- 数据守护系统启动完成之后;
- 守护系统运行过程中,主库手动重启或者守护进程自动启动 Open 之后;
- 监视器执行Switchover 主备切换/Takeover 备库接管/强制 Open 主库的操作之后。
②使用监视器命令动态设置恢复间隔
监视器提供有以下命令可动态修改 INST_RECOVER_TIME 值:
- set database [group_name.]db_name recover time time_value动态修改指定备库实例的恢复间隔 ,只修改对应主库守护进程内存中的INST_RECOVER_TIME 值。
- set group [group_name] recover time time_value,动态修改指定组或所有组中所有备库的恢复间隔,只修改对应主库守护进程内存中的INST_RECOVER_TIME 值。
- set group [group_name] para_name para_value,动态修改指定组或所有组中所有守护进程的配置参数值,para_name 允许指定为 INST_RECOVER_TIME , 同时修改dmwatcher.ini 文件和主库内存中的INST_RECOVER_TIME 值。
以上 3 个命令都可以用来修改 INST_RECOVER_TIME 值,修改完成后,一旦主库对指定备库执行过恢复操作,不管恢复执行成功或失败,通过监视器动态修改的内存值都不再有效,主库守护进程在恢复完成后,会根据恢复结果重置内存中的恢复间隔值(对dmwatcher.ini 中的值没有影响)。
③主库守护进程根据恢复结果设置恢复间隔
如果备库恢复成功,会重置此备库的恢复间隔为主库 dmwatcher.ini 中配置的值。如果备库恢复失败,会根据失败 code 区分设置为不同的值,比如 1800s,一般是在主备库日志校验不连续的情况下设置,其他还可能设置为 3s、30s、300s 或者dmwatcher.ini 中设置的值,这里不再详细说明,具体可通过服务器和守护进程的 log日志查看详细的设置信息,也可以通过监视器的 show arch send info 命令查看相关code 信息。
完整的故障恢复流程如下:
- 通知备库丢弃 KEEP_PKG;
- 通知主库发送归档日志,同步历史数据;
- 通知主库切换为 Suspend 状态;
- 再次通知主库发送归档日志;
- 通知主库设置备库归档为 Valid 状态;
- 通知主库切换为 Open 状态。
整个恢复过程中最耗时的是发送归档日志,当存在多个备库需要恢复时,为了提高恢复的效率,采用多备库并行发送归档的方式进行。守护进程每次搜集一个可恢复备库到恢复列表,按照上述故障恢复流程执行单个步骤,在等待发送归档日志的过程中,继续检测是否有备库可以恢复,如果有则加入恢复列表,也对其开始进行恢复流程处理;如果没有则检查恢复列表中是否有归档日志发送完成的备库,有则对其进行后续步骤处理,直至归档变成有效状态后从恢复列表中删除。对于恢复过程中出错的备库,也从恢复列表中删除。当恢复列表为空时,恢复流程执行结束,守护进程恢复为 OPEN 状态。
恢复过程中,守护进程会继续检测是否有恢复列表之外的备库需要恢复,如果有则可以动态加入恢复列表,实现动态并行恢复。
注意:以下情况会导致 Recovery 过程中断:
- Recovery 过程中收到监视器的命令。
- 存在多个备库时,Recovery过程中发现其他正常备库故障,且符合failover 条件,则守护进程主动中断 Recovery,先做 failover 处理。
- 存在多个备库时,Recovery 过程中发现到其他正常备库归档发送异常,则守护进程主动中断 Recovery,先做异常处理。
- Recovery 过程中,当前正在被恢复的备库出现异常。 ⑤正在执行 Recovery 的主库或备库是 DMDSC集群,Recovery 过程中 DMDSC 集群启动故障处理或者故障重加入,也会中断当前的 Recovery动作。
在守护进程打开备库异常监控的情况下,对于异常备库的恢复处理需要注意下面两点:
- 如果主备库的 LSN 已经相等,但是根据统计出来的时间信息判断主库的归档发送时间或备库的日志重演时间仍然大于设置的阈值,则不会再进入Recovery状态,直到主库上有新的日志产生需要同步到备库,可以对统计的历史时间信息进行更新的情况下才会再进入 Recovery 状态尝试恢复。
- 在进入 Recovery 状态后,通知主库 Suspend之前(主备库数据已经同步一致),会对主库的归档发送时间和备库的日志重演时间进行检查,在两者都小于或等于设置的阈值的情况下,才允许继续执行Suspend,并恢复备库归档为有效状态,否则不允许再往下执行,本次 Recovery 执行失败。
4、集群数据守护场景
(1)正常运行状态
守护系统正常运行时,同一个守护进程组中,只有一个主库,其他的都是备库。主库处于 Open 状态,主库守护进程也处于 Open 状态,本地没有守护进程控制文件,其内存值是 Valid 有效状态。所有备库也处于 Open 状态,所有备库守护进程处于 Open 状态,本地没有守护进程控制文件,其内存值是 Valid 有效状态。主库到所有备库的归档也都处于 Valid 有效状态。
(2)数据守护的启动
Normal 模式的库默认以 Open 状态启动,也可以通过增加启动参数 Mount 将数据库启动到 Mount 状态。而 Primary/Standby 模式的库启动后,自动进入 Mount 状态,因此,数据守护系统启动时,所有数据库实例处于 Mount 状态。所有守护进程处于 Startup状态。如果实例还未启动到 Mount 状态(比如还处于 After redo 状态),守护进程不会通知实例 Open。
Local 守护类型的守护进程,直接 Open 数据库实例,并修改守护进程状态为 Open。
Global 守护类型的守护进程,需要相互协调信息,自动将数据库实例切换到 Open 状态,并将守护进程状态也切换为 Open 状态。
Global 守护类型的守护进程通知本地库 Open 的总体原则:
- 对于备库,如果可加入远程任意一个库,则允许将其 Open;
- 对于主库,如果远程所有库都可加入自己,则允许将其 Open。
还有一些细节条件这里不再具体列出,如果通过监视器没有观察到主库或备库 Open,可以借助监视器的 Check Open 命令查找原因,根据命令返回的原因考虑是否进行人工干预,比如需要通过监视器命令强制 Open 主库或备库。
注意:
- 手动方式启动数据守护系统时,对于守护进程,数据库实例和监视器的启动顺序没有严格要求,也可以通过监视器命令启动守护系统(前提是所有守护进程已经启动)。
- 启动流程中,守护进程在通知主库 Open 之前,会先收集出和主库数据一致的备库(备库的 ALSN 信息和主库的 FLSN 信息相等),守护进程会将这些备库的归档设置为 Valid 有效状态,其他数据不一致的备库则设置为Invalid 无效状态。Primary 模式数据库实例切换为 Open 状态时,需要回滚活动事务、Purge 已提交事务,并重构回滚段,会引发数据变化、LSN增长。对归档无效的备库,在数据守护启动完成后,主备库数据肯定是处于不一致状态。
- 主库守护进程 Open 主库后,会修改 INST_RECOVER_TIME 内存值为 3 秒(默认 60 秒),确保归档状态无效的备库 Open 后,尽快启动故障恢复流程,同步主库数据完成后,重新将归档设置为 Valid 状态。
- 如果在故障恢复流程完成之前,主库故障,并且不存在归档状态有效的备库,则无法执行备库接管;备库强制接管会引发守护进程组分裂。
- 读写分离集群,在 Timely 或 Realtime 归档变为 Valid 之前,不会在备库上创建数据库连接,只读操作也无法分流到对应的备库。
(3)强制 Open 数据库
正常情况下,守护进程 dmwatcher 可以自动 Open 数据库实例,但某些情况下(比如备库硬件故障无法启动),数据守护系统不满足启动条件,我们可以通过监视器执行 Open database 命令强制 Open 数据库实例。主备库都可以强制 Open,其执行流程如下:
1 假设需要强制 Open 数据库 A,只需要启动一个监视器,登录后输入 Open database A 即可完成强制启动。 如果数据库 A 是 Standby 模式,强制 Open 的执行流程如下:
①通知 A 的守护进程切换为 Open Force 状态
②通知 A 执行 Open 操作
③通知守护进程切换 Open 状态
2 如果数据库 A 是 Primary 模式,强制 Open 的执行流程如下:
①通知 A 的守护进程切换为 Open Force 状态
②修改 A 到所有归档目标的实时归档/即时归档状态为无效
③通知 A 执行 Open 操作
④通知守护进程切换 Open 状态
3 Primary 模式数据库实例切换为 Open 状态时,需要回滚活动事务、Purge 已提交事 务,并重构回滚段,会引发数据变化、LSN 增长。因此,这个操作可能会引发守护进程组分 裂,比如下面的场景:
①主库 A 故障
②备库 B 接管,成为主库
③B 故障
④A 重启,并强制 Open
⑤A 和 B 数据不一致,并且无法恢复到一致状态。此时,B 重启,就会产生守护进程 组分裂。
注意:
- 强制 Open 主库前,会设置主库到所有归档目标的实时归档/即时归档为 Invalid 状态。
- 强制 Open 主库命令,会修改主库守护进程 INST_RECOVER_TIME 内存值为3 秒(默认 60 秒),确保
- 主库 Open 后,尽快启动故障恢复流程,同步主库数据完成后,重新将归档设置为 Valid 状态。
- 如果在故障恢复流程完成之前,主库故障,将无法执行备库接管;备库强制接管会引发守护进程组分裂。
注意:
强制 Open 主库前,会设置主库到所有归档目标的实时归档/即时归档为 Invalid 状态。
强制 Open 主库命令,会修改主库守护进程 INST_RECOVER_TIME 内存值为3 秒(默认 60 秒),确保
主库 Open 后,尽快启动故障恢复流程,同步主库数据完成后,重新将归档设置为 Valid 状态。
如果在故障恢复流程完成之前,主库故障,将无法执行备库接管;备库强制接管会引发守护进程组分裂。
(4)关闭数据守护系统
关闭守护系统时,必须按照一定的顺序来关闭守护进程和数据库实例。特别是自动切换模式,如果退出守护进程或主备库的顺序不正确,可能会引起主备切换,甚至造成守护进程组分裂。通过监视器执行 Stop Group 命令关闭数据守护系统,是最简单、安全的方式。命令执行成功后,数据库实例正常关闭。但守护进程并没有真正退出,而是将状态切换为Shutdown 状态。
Stop Group 命令内部流程如下:
①通知守护进程切换为 Shutdown 状态
②通知主库退出
③通知其他备库退出
如果使用手动方式关闭数据守护系统,请严格按照以下顺序执行:
①如果启动了确认监视器,先关闭确认监视器(防止自动接管)
②关闭备库守护进程(防止重启实例)
③关闭主库守护进程(防止重启实例)
④Shutdown 主库
⑤Shutdown 备库
如果是只关闭主库,并且不想引发备库自动接管,有以下两种方法:
方法一:
1 通过 Detach database 命令将所有备库分离
2 通过 Stop database 命令退出主库
方法二:严格按照以下顺序执行:
1 通过 Stop dmwatcher 命令关闭所有守护进程监控
2 手动正常退出主库
如果是只关闭备库,并且不想引发主库发送日志失败进入 Suspend 状态,请严格按照
以下顺序执行:
1 通过 Detach database 命令将备库分离出数据守护系统
2 正常退出备库(手动退出或者通过 Stop database命令退出)
(5)主备库切换
主库维护,滚动升级等场景,可以执行 Switchover 命令,实现主备库切换。如果存在多个备库,需要先执行 Choose Switchover 命令,选出守护进程组中可以切换的备库。
Choose Switchover 命令选择可切换备库的条件如下:
主库守护进程是 Open 状态
备库守护进程是 Open 状态
主、备库的 OPEN 记录项内容相同,并且守护进程控制文件是 Valid 有效状态(内存值)
主库正常运行
备库正常运行
主库处于 Open 状态
备库处于 Open 状态
主库到备库的归档是 Valid 状态
假定选出的可切换备库是 B,Switchover 切换流程如下:
通知主备库守护进程,切换为 Switchover 状态
通知主库(A) Mount
实时或 MPP 主备环境下,通知备库(B) APPLY KEEP_RLOG_PKG
通知备库(B) Mount
通知(A) 切换为 Standby 模式
MPP 主备环境下,通知(A)修改 MPP_INI 内存值为 0
通知(B) 切换为 Primary 模式
通知(B) 修改所有归档目标的归档状态为无效
MPP 主备需要通知各组活动主库更新 dmmpp.ctl 文件,参考后文说明
通知新的备库(A) Open
通知新的主库(B) Open
通知主备库守护进程切换为 Open 状态
清理所有守护进程上记录的监视器命令执行信息
注意:
主备库切换在实现逻辑上等同于主备库正常状态 下用户主动发起的Takeover 操作。Swithover完成后,主备库之间数据是不完全同步的,要由新主库 B 的守护进程通过 Recovery 流程,重新同步数据到新备库 A。Switchover 命令会修改切换后主库守护进ZINST_RECOVER_TIME 内存值为 3 秒(默认 60 秒),确保尽快启动故障恢复流程,同步主库数据完成后,重新将归档设置为 Valid 状态。
在故障恢复流程完成之前,再次执行Switchover 命令会报错,如果主库故障,备库接管将会报错;备库强制接管会引发守护进程组分裂。
(6)主库故障、备库接管
当出现硬件故障(掉电、存储损坏等)原因导致主库无法启动,或者是主库内部网卡故障导致主库短期不能恢复正常的情况下,可使用备库接管功能,将备库切换为主库继续对外服务。
故障自动切换模式下,确认监视器会自动选择符合条件的备库进行接管。
故障手动切换模式下,可以先在监视器上执行 Choose Takeover 命令,选出守护进程组中可以接管的备库。
为了避免备库接管后,造成守护进程组分裂,执行 Takeover 必须满足下列条件:
主库是 Primary 模式、Open 状态时,发生故障
主库守护进程故障,故障前是 Startup/Open/Recovery 状态;或者主库守护进程正常
主库故障前到接管备库的归档状态为 Valid
接管备库是 Standby 模式、Open 状态
接管备库的守护进程控制文件状态为 Valid(内存值)
故障主库和接管备库的 Open 记录项内容相同
假设主库 A 故障时,在故障自动切换模式下确认监视器自动选出待接管备库 B 并通知备库 B 自动接管,或者在故障手动切换模式下,通过监视器上的 Choose Takeover 命令,选出待接管备库 B,在监视器上输入 Takeover 命令通知备库 B 执行接管,这两种方式的接管执行流程是一样的。
以备库 B 为例,接管的执行流程包括:
监视器通知守护进程(B)切换为 Takeover 状态
实时主备或 MPP 主备环境下,通知备库(B) APPLY KEEP_PKG
通知备库(B) Mount
通知(B) 切换为 Primary 模式
通知(B) 修改到所有归档目标的归档状态为 Invalid
MPP 主备需要通知活动主库更新 dmmpp.ctl 文件(步骤参考 6.5 主备库切换)
通知新的主库(B) Open
通知守护进程(B)切换为 Open 状态
(7)备库强制接管
有些情况下,备库接管会失败,但主库不能启动或者及时恢复对外服务的情况下,可以使用 Takeover Force 命令,进行备库强制接管。强制接管具有一定的风险,可能导致备库和故障主库数据不一致,而造成部分数据的丢失,出现数据库分裂的情况,所以应该慎重使用。
例如主库和守护进程故障时,监视器未启动,用户启动监视器后,由于监视器并未收到故障主库任何信息,因此不满足 Takeover 条件,执行 Takeover 会报错。如果用户可确认主库故障时主备数据是一致的(如故障时主库未执行操作,主备库归档有效的,并且两者的 LSN 一致)、或者丢失小部分数据的影响可忽略、或者丢失小部分数据的影响小于主库持续宕机造成的影响,则可以考虑执行 takeover force 强制接管。
强制接管,先通过 Choose Takeover Force 选出符合强制接管条件的备库,再执行 Takeover Force 命令。
备库强制接管时,如果接管备库是处于 Mount 状态/Standby模式的库,则会自动 Open 备库,其他执行流程与备库接管一致。强制接管的条件包括:
不存在活动主库
备库守护进程处于 Open 或 Startup 状态
备库实例运行正常
备库是 Standby 模式
备库处于 Open 或 Mount 状态
备库的 KLSN 必须是所有备库中最大的
备库守护进程控制文件必须有效
(8)主库故障重启(备库接管前重启)
主库故障后立即重启,此时主库的守护进程变成 Startup 状态,重新进入守护进程的启动流程,将数据一致的备库归档设置为有效状态,其余备库归档设置成无效状态,并重新Open 主库。Open 成功后继续作为主库,当检测到归档状态无效的备库正常时会启动Recovery 处理流程,重新同步主备库数据。
(9)备库故障处理
备库产生故障(硬件故障或者内部网卡故障)时,主库的处理流程对手动切换、自动切换模式处理上有些差异。
①手动切换模式
对于手动切换模式,检测到备库故障,满足 Failover 条件时,主库的守护进程立即切换到 Failover 状态,执行对应的故障处理,如果不满足切换 Failover 条件,则保持当前状态不变。
手动切换模式下,主库守护进程切换 Failover 条件:
备库实例故障,或者主备库之间出现网络故障,或者备库重演时校验 LSN 不匹配,这三种场景下引发主库
同步日志到备库失败挂起,主库实例处于 Suspend 状态
主库到此备库的归档状态是 Valid(读写分离集群没有此限制)
主库的守护进程处于 Startup、Open 或 Recovery 状态
当前没有监视器命令正在执行
②自动切换模式
对于自动切换模式,主库的守护进程会自动判断切换到 Failover 状态或者 Confirm确认状态,如果两种状态切换条件都不满足,则保持当前状态不变。
自动切换模式下,主库守护进程不进入 Confirm 确认状态,直接切换到 Failover 条件:
前四项条件,和上面列出的手动切换条件相同
备库实例故障,备库守护进程正常
如果只满足条件 1,不满足条件 2,则主库守护进程会先进入 Confirm 确认状态,等待确认监视器的确认消息。主库的守护进程进入 Confirm 确认状态后,会有下面几种不同的处理:
1、主库和确认监视器之间网络连接正常
主库的守护进程收到了确认监视器返回的确认消息,如果确认监视器认定可以执行 Failover,则主库的守护进程会切换为 Failover 状态并执行对应的处理;如果确认监视器认定不满足执行 Failover 条件,则主库的守护进程会一直保持在 Confirm 状态。确认监视器认定主库可以执行 Failover 条件:
1)主库守护进程处于 Confirm 状态
2)主库实例正常,处于 Suspend 状态
3)主库没有被接管,不存在其他主库
4)没有 takeover/switchover 命令在执行
5)当前所有归档有效的备库均可以加入主库
2 主库和确认监视器之间网络连接异常,或者没有启动确认监视器。满足下面条件后
主库允许切换至 Failover 状态执行故障处理:
1)主库实例正常,处于 Suspend 状态
2)备库守护进程正常
3)主库没有被接管,不存在其他主库
4)没有 takeover/switchover 命令正在执行
5)备库故障前可以加入主库
3 主库和确认监视器网络恢复正常后,主库已经被接管。老主库的守护进程切换为
Startup 状态,重新判断是否可加入新主库。
主库守护进程进入 Failover 状态后的执行流程(自动或手动切换模式下执行流程相
同):
1)对实时主备或 MPP 主备,通知主库修改发送归档失败的备库归档状态无效
2)通知主库重新 Open。
3)将主库的守护进程切换为 Open 状态
(10)确认监视器未启动
故障自动切换模式下,确认监视器必须一直处于启动状态,并且要确保确认监视器的配置正确(否则无法和守护进程通信,相当于确认监视器没有启动)。若确认监视器未启动或者配置错误的,在主库或备库发生故障时,无法通过确认监视器执行正常的故障处理。
在没有确认监视器或确认监视器配置错误的情况下:
- 如果主库故障,则备库无法自动接管为新主库。
- 如果备库实例和备库的守护进程都出现故障,或者主备库之间出现网络故障,则主库的守护进程无法通过确认监视器来确认备库状态,主库守护进程会处于Confirm 确认状态,实例处于 Suspend 挂起状态。
对于第 2 种情况,当备库实例和备库守护进程重新恢复正常,或者主备库之间的网络恢复正常后,即使没有确认监视器,主库的守护进程也会切换至 Failover 状态,将主库重新 Open,后续进行正常的备库恢复处理,而不会一直处于 Confirm 确认状态。可以通过监视器的 show monitor 命令查看连接到指定守护进程的所有监视器信息,以此可以检查守护系统中是否启动有确认监视器以及确认监视器和守护进程的通信是否正常,也可以尝试再启动一个新的确认监视器,如果守护系统中已经启动有确认监视器,则不允许再启动第二个。
三、疑问和问答
1、达梦redo log什么时候归档?
在 REDO 日志写入联机日志文件后触发,由归档线程dm_rsyswrk_thd完成本地归档动作,将对应的 RLOG_PKG (日志包 RLOG_PKG 为单位)由专门的归档线程写入本地归档日志文件中。
2、监控模式和确认模式的区别?
答:两者区别在于:确认监视器除了具备监控模式监视器所有功能外,还具有状态确认和自动接管两个功能。
3、实时归档备库什么时机apply?
主库:
写入 REDO 日志到本地归档文件,在 REDO 日志写入日志文件后触发(即redolog buffer刷盘后),由归档线程完成 本地归档动作。主库redo buffer 刷盘的条件满足:
事务提交commit
执行检查点chkpoint
每3秒
缓冲区写满,没有剩余空间时
数据库关闭时。
备库:
MAL通讯系统将主库的RLOG_PKG包通过实时归档机制发送到备库B中,备库将最新收到的RLOG_PKG保存在内存中,然后进行校验是否合法,合法后标记为 KEEP_PKG,不会马上启动重演,但会将之前的KEEP_PKG通过APPLY线程队列加入日志重演任务系统,并马上响应主库,不需要等待之前的Redo日志重演结束后再响应主库。
备库 KEEP_PKG 日志重演的时机包括:
1.备库收到新的 RLOG_PKG
备库收到新的 RLOG_PKG 时,会将当前保存的 KEEP_PKG 日志重演,并将新收到的RLOG_PKG 再次放入
KEEP_PKG 中。
2. 收到主库的重演命令
主库会定时将 FILE_LSN 等信息发送到备库,当主库 FILE_LSN 等于备库 SLSN 时,表明主库已经将
KEEP_PKG 对应的 Redo 日志写入联机日志文件中,此时备库会启动KEEP_PKG 的日志重演。
3. 备库切换为新主库
在监视器执行 SWITCHOVER 或 TAKEOVER 命令,或者确认监视器通知备库自动接管时,备库会在切换为
PRIMARY 模式之前,启动 KEEP_PKG 的日志重演。
4、什么时候用switchover(两边dbwatcher 都正常)?什么时候takover(异常dbwatcher)。
5、主库挂起之后是一直挂起还是?
答:Primary 实例将试图切换成 Suspend状态,是为了防止后续的日志写入。因为一旦写入,主备切换时有可能备库没有收到最后那次的RLOG_PKG,导致主库上多一段日志,很容易造成主备数据不一致。
分2种情况:监视器确认模式模式(超过)和非确认模式(一直挂起,需要手动处理)。