HADR 简介

HADR( 高可用性灾难恢复 ) 是 DB2 数据库的一个组件,是 DB2 提供给用户的一种高可用性和灾难恢复的解决方案。组成 HADR 需要一对机器,一个主机和一个备机。它的基本原理是主机将数据库产生的日志通过网络传输到备机,然后备机将这些日志重新应用,整个过程类似于前滚恢复。从而保证主机和备机数据库的一致。当主机发生意外停机以后,例如停电或者灾难等,备机可以很快的接替主机继续工作。从 DB2 V97FP1 开始,HADR 开始支持 ROS(Read On Standby),备机除了做备份数据库以外,还可以接收连接,执行读操作。

HADR 的监控

通过数据库参数获取 HADR 的配置信息

通过获取数据库配置信息,可以看到 HADR 的一些基本配置,如图 1,可以看到 HADR 的角色、同步方式、超时时间等等。

图 1. 通过获取数据库信息查看 HADR 配置

[db2inst1@petrel ~]$ db2 get db cfg for hadrdb| grep HADR

HADR database role                                      = PRIMARY

HADR Local host name                   (HADR_LOCAL_HOST)= petrel

HADR Local service name                 (HADR_LOCAL_SVC)= 54321

HADR remote host name                 (HADR_REMOTE_HOST)= grebe

HADR remote service name               (HADR_REMOTE_SVC)= 54321

HADR instance name of remote server   (HADR_REMOTE_INST)= db2inst1

HADR timeout value                        (HADR_TIME0UT)= 120

HADR Log write synch ronization mode     (HADR_SYNCMODE)= NEARSYNC

HADR peer window duration (seconds)   (HADR_PEER_WINDOW)= 10

 

如果需要修改这些参数,使用“db2 update db cfg for dbname using CONFIG_PARAM value”命令对相应的参数进行修改。修改以后,需要重新启动数据库新的配置才生效。

通过数据库快照获取 HADR 的运行状况

DB2 的快照信息显示了某个时刻数据库的运行状况。从这些数据里面,也可以观察到 HADR 的运行情况。例如,从图 2 中,可以看到 HADR 的角色、状态、连接状况、当前正在操作的日志文件等等。

图 2. 通过获取数据库信息查看 HADR 的运行状况

 

[db2inst1@grebe ~]$ db2 get snapshot for db on hadrdb|grep -A 17 "HADR Status"

HADR Status

Role                         = Standby

State                        = Remote catchup pending

Synchronization mode         = Nearsync

Connection status            = Disconnected,01/29/2018 10:34:35.573105

Peer window end              = 01/29/2018 10:34:55.000000(1279180244)

Peer window (seconds)        = l0

Heartbeats missed            = 0

Local host                   = grebe

Local service                = 54321

Remote host                  = petrel

Remote service               = 54321

Remote instance              = sibao

timeout(seconds)             = 120

Primary log position(file, page. LSN)= S0000014.LOG. 0. 0000000002333C81

Standby log position(Tile, page, LSN)= S0000014.LOG. 0. 0000000002333C81

Log gap running average(bytes)=0

通过 DB2PD 获取 HADR 运行状况

db2pd 是一个很强大的工具。通过这个工具,可以看到 DB2 在运行时,内存里面的一些状况。所以通过 db2pd 看到的信息都是实时信息。

通过 db2pd -hadr 看到的信息是非常完整的,下面会对这些输出项目进行详细的解释。

图 3. 通过 DB2PD 获取 HADR 的运行状况

[db2inst1@grebe ~]$ db2pd -d testdb -hadr

 

Database Partition 0 -- Database HADRDB -- Standby -- Up 1 days 01:50:06 -- Date 2018-01-29-10.36.36.786129

HADR Information:

Role    State                SyncMode HeartBeatsMissed   LogGapRunAvg (bytes)

Standby RemoteCatchupPending Nearsync 0

 

ConnectStatus ConnectTime                          Timeout

Disconnected  Mon Jan 29 10:01:00 2018 (123829184) 120

 

PeerWindowEnd                         PeerWindow

Mon Jan 29 10:01:12 2018 (123829192)  10

 

LocalHost                                LocalService

grebe                                    54321

 

RemoteHost                               RemoteService      RemoteInstance

petrel                                   54321              db2inst1

 

PrimaryFile  PrimaryPg PrimayrLSN

S0000014.LOG 0         0x0000000002333c01

 

StandByFile  StandByPg StandByLSN         StandByRcvBufUsed

S0000014.LOG 0         0x0000000002333c01 0%

[db2inst1@grebe ~]$

 

通过以上方式,可以看到如下监控项。

角色(Role):标志数据库是主数据库还是从数据库。

状态(State):HADR 当前的状态。包括 Local Catchup、Remote Catchup、Remote Catchup Pending、Peer、Disconnect Peer。

Local Catchup: 如果备机在这种状态下,表明备机这在从本地的磁盘上读取日志文件,并且对日志进行重新重做;如果主机在这种状态下,表明它正在等待备机的连接。HADR 的主机并没有从本地读日志并重做的过程,我们之所以让主机显示这个状态,就是通过主机上的这个状态告诉用户,备机正在做本地日志的重做。

Remote Catchup: 处于这个状态的 HADR 的主机正在从本地读日志,并且将这些日志发送给备机;而备机会从主机接受日志,并且将这些日志写入它本地的磁盘,并且对这些日志进行重做。

Remote Catchup Pending: 如果备机出于这种状态,表明它正在尝试连接主机。出现这种状态,一般是因为主机不存在或者主机还没有完全的启动起来,导致连接没有成功。

Peer: 如果 HADR 的主备机器处于这种状态,表明主机和备机的网络连接良好。日志可以顺利的从主机发送到备机。

Disconnect Peer: 如果 HADR 的主备机器处于这种状态,表明主机和备机的网络已经断开,但是连接断开的时间并没有超过 PEER_WINDOW。这个状态内,主机上的事务不可以提交。如果这个时候网络恢复,主机和备机重新建立连接,主备机器会重新回到 PEER 状态;如果双方进入这个状态的原因是主机出现了故障,当在备机上做接管(takeover)操作时,不会发生数据丢失。就是说不会出现主机提交了某个事务,但是备机没有提交这个事务的情况。

Disconnected: 如果主机处于这种状态,表明主机没有收到来自备机的连接。如果备机处于这种状态,表明备机不能连接到主机。

同步方式(SyncMode):HADR 传输日志的三种方式,同步模式,近同步模式,异步模式。由于这三种方式对 HADR 来说特别重要,笔者在这里将详细介绍这三种方式。

1. 同步模式:这种模式下,主机首先将日志写入本地磁盘,然后发送给备机。备机收到这些日志以后,首先将这些日志写入本地磁盘以后,然后向主机发送一个回应。当主机收到这个回应以后,事务才可以提交。

这种模式下,因为当事务提交时,相应的日志已经保存在了备机的磁盘上。所以主机在任何时间下发生故障,备机切换以后可以保证不丢失数据。

2. 近同步模式:在这种模式下,主机在将日志写入磁盘的同时将日志发送到备机。当备机收到日志以后,就会向主机发送回应消息。主机收到这条回应消息以后,事务才可以提交。

也就是说,当主机收到回应消息时,刚才发送备机的日志不一定写到了备机的磁盘上,而有可能还在备机的内存里。如图 5 所示:

这种模式下,因为主机发送的日志已经保存在了备机的内存中。只有当主机和备机同时出现故障停机的时候,才会丢失数据。

3. 异步模式:与近同步模式类似,在这种模式下,主机也是写日志到磁盘的同时发送日志到备机。与近同步模式不同的是,在异步模式下,主机并不会等备机的回应消息。而是日志发送成功以后,事务就可以提交。在这里,日志发送成功并不代表主次一定收到了这条消息,这条消息也可能保存在了主机的 TCP 发送缓冲区里面。

这种模式下,因为日志有可能仍然在主机的 TCP 缓冲区里面,如果这个时候主机出现故障停机,这些数据就会丢失。但是和另两种模式相比,异步模式网络上的开销减小了,这种模式对数据库性能影响是最小的。

心跳丢失数量(HeartBeatMissed):主机会不断地向备机发送心跳,以确认仍然可以和对方通信。这个值表明了有多少心跳信号没有发送成功或者没有接收成功。

日志 LSN 差异(LogGapRunAvg):这个值表示一段时间以内,主机和备机日志差异的平均值。如果这个值一直很大,可能表明网络状况比较差,或者备机的性能和主机差异太大,以至于日志不能及时的从主机传到备机。

连接状态(ConnectStatus):包括三种 CONNECTED, DISCONNECTED, CONGESTED。CONNECTED 表示连接状况良好;DISCONNECTED 表示主机和备机已经断开连接;CONGESTED 表示当前的网络状况不太好,日志或者消息的发送遇到拥塞。

连接时间(ConnectTime):如果主机和备机是连接的,表示连接建立起来的时间;如果连接时断开的,表示的是连接断开的时间;如果发生了网络拥塞,则表示上次网络拥塞的时间。

超时时间(Timeout):如果 HADR 在这段时间内没有收到来自同伴的任何消息,它就会断开网络连接。需要注意的是,这个时间并一定是网络出现错误以后的等待时间。HADR 可以发现网络上的大部分错误,当这些错误发生时,HADR 会立刻断开和对方的连接,而并不会等待。另外,这项配置还有另外两个作用:

1. 心跳的时间间隔为 HADR_TIMEOUT/4 和 30 秒钟两者之间的较小的那个值

2. 如果首先在主机上执行启动 HADR 的操作,如果主机没有在 HADR_TIMEOUT 时间以内没有收到备机的连接,主机上的数据库就会停掉,以防止两台主数据库的存在而导致脑裂。

同伴窗口(PeerWindow):相对应 DB2 配置文件中的 HADR_PEER_WINDOW,该参数只对 SYNC 和 NEARSYNC 两种同步模式有效。如果该参数不为零,当主机和备机断开连接时,在 HADR_PEER_WINDOW 这段时间以内,数据库处于 DISCONNECTED PEER 状态。主机在这段时间内不能提交任何事务。所以,这段时间内,如果备机做了接管,备机不会丢失任何事务。这个参数通对于在 TSA 对 HADR 自动做接管的环境中特别重要,因为 TSA 执行“takeover hard on db dbname by force peer window only”这个命令进行接管。

同伴窗口结束时间(PeerWindowEnd):显示了同伴窗口的结束时间。过了这个时间以后,HADR 将处于 DISCONNECTED 状态。

本地主机名(LocalHost):本地 HADR 所在的主机名或者 IP 地址。

本地服务名(LocalService):本地 HADR 所使用的服务名称或者端口号。

远程主机名(RemoteHost):对端 HADR 所在机器的的主机名或者 IP 地址。

远程服务名(RemoteService):对端 HADR 使用的服务名称或者端口号。

远程实例(RemoteInstance):对端 HADR 数据库所在的实例的名字。

主机日志文件(PrimaryFile):主机目前正在写的日志文件。

主机日志页号(PrimaryPg):主机目前正在写的日志文件中的页号。

主机日志序号(PrimaryLSN):主机正在处理的日志记录的序列号。

备机日志文件(StandByFile):备机目前正在写的日志文件。

备机日志页号(StandByPg):备机目前正在写的日志文件中的页号。

备机日志序号(StandByLSN):备机正在处理的日志记录的序列号。

对于很多 DBA 来说,知道主机和备机的同步情况很重要。从主机日志序号和备机日志序号里面,我们可以判断出来主机还有多少日志没有传输到备机。例如以下db2pd 的结果:

HADR Information:

Role    State                SyncMode HeartBeatsMissed   LogGapRunAvg (bytes)

Primary Peer                 Nearsync 0                  18

 

ConnectStatus ConnectTime                          Timeout

Connected  Mon Jan 29 14:24:22 2018 (123829344676) 120

 

LocalHost                                LocalService

petrel                                   54321

 

RemoteHost                               RemoteService      RemoteInstance

grebe                                    54321              db2inst1

 

PrimaryFile  PrimaryPg PrimayrLSN

S0000000.LOG 1         0x000000000FC179C

 

StandByFile  StandByPg StandByLSN       

S0000000.LOG 1         0x000000000FC16E6

我们可以看出来主机和备机的日志相差 0x0000000000FC179C-0x0000000000FC16E6 = 0xB6。也就是十进制的 182 个字节。

通过 db2trace 来计算 HADR 对交易性能的影响

db2trc 命令是 DB2 提供的跟踪工具。该跟踪工具记录有关操作的信息并将此信息格式化为可读格式。需要注意的是,运行跟踪时会增加开销,所以启用跟踪工具可能会影响系统性能。

db2trace 可以跟踪每个函数以及该函数的执行时间。利用这一性质,我们可以计算出来每次写日志花费的时间以及 HADR 带来的开销。

首先,我们需要找到主机上的写日志的 EDU(Engine Dispatchable Unit),即 db2loggw 的线程号(或进程号)。对于 v91 及以前的版本,我们使用 db2procs,如下图:

通过 DB2PROCS 查看 EDU 的进程号

[db2inst1@petrel ~]$ db2procs

db2procs: Instance "db2inst1"

 

30084    root db2wdog  15:28    db2wdog

30085    db2inst1 db2sysc   15:28   db2sysc

30086    root db2ckpwd 15:28    db2ckpwd

30087    root db2ckpwd 15:28    db2ckpwd

30088    root db2ckpwd 15:28    db2ckpwd

30089    root db2pmd     15:28  db2pmd

30090    db2inst1 db2gds     15:28  db2gds

  32564  db2inst1 db2logts 15:31    db2logts (HADRDB)

  32565  db2inst1 db2logmgr 15:31    db2logmgr (HADRDB)

  32566  db2inst1 db2loggr 15:31    db2loggr (HADRDB)

  32567  db2inst1 db2loggw 15:31    db2loggw (HADRDB)

  32568  db2inst1 db2lfr   15:31    db2lfr   (HADRDB)

  32569  db2inst1 db2dlock 15:31    db2dlock (HADRDB)

  32570  db2inst1 db2pclnr 15:31    db2pclnr

对于 v95 及以后版本,db2 基于线程模型,使用 db2pd -edus,如下图:

通过 DB2PD 查看 EDU 的线程号

[db2inst1@petrel ~]$ db2pd -edus

db2procs: Instance "db2inst1"

DB2 HADR监控_DB2

找到 HADR 的 EDU 以后,我们可以通过 db2trc 去跟踪 loggw 这个进程(或者线程)。例如对于上图,使用命令:

db2trc on -t -p 32567 -f trace.dump

等主机上运行过了需要写日志的交易(例如插入,删除,修改)以后,将 db2trc 关掉,然后格式化 db2trace 的 dump 文件:

db2trc off;

db2trc flow -t trace.dump trace.flow

打开文件 trace.flow,以下图为例。

格式化以后的 TRACE 文件

DB2 HADR监控_数据库_02

注意标记红线和红色框里面的内容,计算 hadr 的方法如下:

  1. 找到 sqlpgwlp      函数, 

  2. 找到这个函数内的      sqloWaitEDUWaitPost 

  3. 计算 sqlpgwlp      的执行时间。T1 = 0.196988000 - 0.192810000 =      0.004178000 

  4. 计算      sqloWaitEDUWaitPost 的执行时间。T2 = 0.196951000 -      0.196946000 = 0.000005000

T1 是完成这次写日志的总时间,T2 就是这次写日志时,HADR 带来的开销

如果我们跟踪了多次写日志的操作,就跟得到多个上面的片段。可以根据所有的片段计算平均值,从而得到更精确地开销比例。


总结

通过对 HADR 的监控,管理员可以更清楚的了解当前主机和备机的配置以及运行情况,可以根据监控的结果做出优化或者相应的管理措施。

通过计算 HADR 对整个数据库交易的影响,管理员可以作出相应的调优方案,例如改进 IO 性能,网络性能,修改 HADR 的同步模式等等。