数据容灾解决方案之dataguard

    技术2026-01-04  4

          前一阵子被客户要求提供一份备份策略,主要包含数据库、应用层面的,其目的很明确就是防止将来的生产环境发生意外而提前制定一系列的系统容灾方案。制定这套方案一般是在系统建设初期,设备采购阶段。说起来可笑,这眼看二期都要竣工,客户才要求我们提供这套方案,不知道是我们工作失职,还是客户够沉得住气,这里也不多说了,先把数据库的备份策略贴出来,有不足的地方还请大家多多指教.

          提到ORACLE数据库容灾,我以往接触到都是逻辑备份,通过exp命令导出,利用crontab 制定备份周期,最终通过人工将DMP拷贝到离线设备中。个人觉得那个太落后,恢复时间太过漫长。一旦数据文件损坏,还需要重新建库,这对运营支撑系统来说,损失是惨重的,当然dbstar是个例外。 ORACLE的备份功能很强大、很灵活,客户既然花了那么多钱购买service,一定要充分利用。

          ORACLE10G推出以后,DATA GUARD 让人眼前一亮,Oracle Data Guard 是管理、监控和自动化软件的基础架构,它创建、维护和监控一个或多个备用数据库,以保护企业数据结构不受故障、灾难、错误和崩溃的影响,所以我决定利用这个利器来制定数据库级别容灾策略。

         

    关于DG的介绍请查看官网的文档,这里废话不多说,直接贴出我的配置步骤:

    一、主机与数据库的配置

    DBSTAR主库

    10.1.252.153

    db_name = orcl

    db_unique_name/ORACLE_SID = primary

    DBSTAR物理备库

    10.1.251.133

    db_name = orcl    --需和主库一致

    db_unique_name/ORACLE_SID = standby

    二、数据库监听的配置

    DBSTAR主库

    SID_LIST_LISTENER =

      (SID_LIST =

       (SID_DESC =

          (GLOBAL_DBNAME = primary)

          (ORACLE_HOME = /home/oracle/oracle/product/10.2.0/db_1)

          (SID_NAME = orcl)

        )

       (SID_DESC =

          (GLOBAL_DBNAME = primary_DGMGRL)

          (ORACLE_HOME = /home/oracle/oracle/product/10.2.0/db_1

          (SID_NAME = orcl)

        )

      )

    LISTENER =

      (DESCRIPTION_LIST =

        (DESCRIPTION =

          (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))

          (ADDRESS = (PROTOCOL = TCP)(HOST = test_host1)(PORT = 1521))

        )

      )

    DBSTAR物理备库

    SID_LIST_LISTENER =

    (SID_LIST =

    (SID_DESC =

          (GLOBAL_DBNAME = standby)

          (ORACLE_HOME = /home/oracle/oracle/product/10.2.0/db_1)

          (SID_NAME = orcl)

        )

       (SID_DESC =

          (GLOBAL_DBNAME = standby_DGMGRL)

          (ORACLE_HOME = /home/oracle/oracle/product/10.2.0/db_1)

          (SID_NAME = orcl)

        )

      ) 

    LISTENER =

      (DESCRIPTION_LIST =

        (DESCRIPTION =

          (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))

          (ADDRESS = (PROTOCOL = TCP)(HOST = test_host2)(PORT = 1521))

        )

      )

    三、将主、备库设置为归档模式

    archive log list;

    shutdown immediate;

    startup mount;

    alter database archivelog;

    alter database open

    SQL>alter system set LOG_ARCHIVE_DEST_1='LOCATION=/home/oracle/archive/$db_unique_name';

    四、修改主库的初始化文件

    在$ORACLE_HOME/DBS/init$ORACLE_SID添加下面内容

    #将主备库的DB_UNIQUE_NAME添加到DATA GUARD中,如果缺少这个参数,可能会导致归档路径被禁用。

    log_archive_config='DG_CONFIG=(primary,standby)'

    #设置主库默认日志归档的路径

    log_archive_dest_1='LOCATION=/home/oracle/oradata/archive/primary VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=primary'

    log_archive_dest_state_1='ENABLE'

    五、通过RMAN将主库复制到备库上一份

    $ rman target /

    RMAN> backup full database format '/home/oracle/backup/dbfull_%T_%s_%p.bak';

    RMAN> exit

    六、通过主库给备库创建初始化文件initstandby.ora

    $ sqlplus '/as sysdba'

    SQL> alter system archive log current

    SQL> alter database create standby controlfile as '/home/oracle/backup/control01.ctl' reuse;

    SQL> exit

    为安全起见,控制文件一般设置三份:

    $ cp /home/oracle/backup/control01.ctl /home/oracle/backup/control02.ctl

    $ cp /home/oracle/backup/control01.ctl /home/oracle/backup/control03.ctl

    注意:建备库控制文件前产生的归档文件后续不会传送给备库,这是正常的。

    七、拷贝上面生成的文件backup_*.bak、control0*.ctl、init*.ora到备机对应目录下

    注意:备机上RAMN对应的备份目录与主机一定要相同,否则无法恢复

    八、在备库上建spfile并启动备库

    SQL> create spfile from pfile='/home/oracle/backup/initstandby.ora ';

    SQL> startup nomount;

    SQL> alter database mount standby database;

    SQL> exit 

    九、备库做rman恢复

    $ rman target /

    RMAN> restore database

    RMAN> exit

    十、启动监听并确保在主备库间能互相tnsping通

    $ lsnrctl start

    $ tnsping standby

    $ lsnrctl status (确保备库监听standby实例成功) 

    主库(primary):

    $ tnsping primary

    $ tnsping standby

    $ lsnrctl status (确保主库监听primary实例成功)

    十一、主库增加归档目的地参数并归档测试

    $ sqlplus '/as sysdba'

    SQL> alter system set log_archive_dest_2='SERVICE=standby LGWR ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=standby' scope=both;

    SQL> alter system set log_archive_dest_state_2='ENABLE' scope=both;

    SQL> alter system archive log current; --这时主库生成的归档日志就会同步到备库上

    十二、将备库激活为recover 状态

    SQL> alter database mount standby database;

    SQL> alter database recover managed standby database disconnect from session;  (standby)

    这样一来数据库就可以根据归档日志来做同步了。

    十三、将备库修改为只读状态

    SQL> alter database recover managed standby database cancel;(standby)

    SQL> alter database open readly

    此时数据库以只读模式打开,可以对数据进行查询操作(standby 数据库不能做修改删除等其它类型的操作)

    当遇到下面这个错误时

    ERROR at line 1:

    ORA-16004: backup database requires recovery

    ORA-01152: file 1 was not restored from a sufficiently old backup

    ORA-01110: data file 1: '/home/oracle/oradata/orcl/system01.dbf'

    请将备份再次激活为recover 状态,然后在主库里执行一次日志切换,生成备份后最后一次的归档日志。

    SQL> alter database recover managed standby database disconnect from session;  --主库

    SQL> alter system switch logfile; --主库

    SQL> alter database open; --备库

    因为当你做备份整个数据库时,主库的归档日志和控制文件任然会发生改变,其SCN号与数据文件不一致,所以备库需要根据主库新生成的日志进行恢复。

    十三、角色切换(主备库切换)

    这里我们使用DGMGRL管理 Data Guard broker,当主库发生故障时,利用dgmgrl进行主备库切换,下面是角色的转换的几种情况和注意事项:

    主数据库和备用数据库角色的转换

    转换

    –  计划的角色转换

    –  无需将数据库重新实例化

    –  用于维护操作系统和硬件

    故障切换

    –  主数据库出现意外故障(例如灾难)

    –  在failover之前一定要将数据库设置成闪回模式,否则原主库在做了灾难恢复之后如果想再次作为备库使用,只能重建。

    利用简单的 SQL / GUI 界面进行初始化

    Data Guard 使涉及到的过程自动化.

    十四、归档日志的清理

        DG的工作机制就是通过主库向备库传输归档日志,由备份数据库做apply操作完成的。

    它不单在DG中使用,在任何一种灾难的恢复过程中都是必不可少的,由此可见归档日志的重要性。不过每天产生的归档文件,长年累月积累下来会占用系统很大的空间,尤其是分布式数据库(BOSS)对数据库的操作频度比较大,如果不及时清理磁盘空间达到饱和以后,就会发生严重的后果。主库和备库都需要定期的删除日志文件,备库可以根据apply的状态为=YES直接删除,但主库在只有做了备份以后才可以做删除,否则如果发生数据文件损坏的时候,丢失了任何一个时间点的日志文件,都是无法做数据库恢复的。

    #!/bin/bash

    ##################################################################################################################

    #

    # This script is to delete the arch logs for the standby database after it has applied the logs to the instance.

    #

    ##################################################################################################################

    source /home/oracle/.bash_profile

     

    #####################

    usage()

    { #usage

    echo " USAGE: `basename $0` $retention"

    exit 2

    ArgNum=1

    if [ ! $# -eq $ArgNum ]; then

    echo " "

    echo " Incorrect parameter"

    usage

    fi

    retention=$1

    script=`basename $0` 

    dir=/home/oracle/backup

    tmpf=$dir/.$script.tmp

    # get archived log list for standby database

    function GetLogListForStandby

    {

    echo "congqing"

    sqlplus -S /nolog <<EOF >$tmpf

    connect / as sysdba

    set head off

    set feedback off

    set pages 0

    select name from(

    select name,sequence#,row_number() over(partition by a.sequence# order by name) rn,

    count(decode(applied,'YES',1,null)) over (partition by a.sequence#) cn #检查是否做了apply

    from v/$archived_log a

    where completion_time <sysdate-$retention

    and a.resetlogs_id in (

    select i.resetlogs_id from v/$database_incarnation i where status = 'CURRENT')

    )

    where rn=1 and cn=1

    order by sequence#;

    exit

    EOF

    return

    }

    function GetDBRole

    {

    sqlplus -S /nolog <<EOF

    connect / as sysdba

    set head off

    set feedback off

    set pages 0

    select controlfile_type from v/$database;

    exit

    EOF

    return

    }

    # get archived log list for primary database

    function GetLogListForPrimary

    {

    sqlplus -S /nolog <<EOF > $tmpf

    connect / as sysdba

    set head off

    set feedback off

    set pages 0

    select name from(

    select name,sequence#,row_number() over(partition by a.sequence# order by name) rn,

    sum(backup_count) over(partition by a.sequence# ) bk_cnt, #检查是否做过备份(可选)

    count(decode(applied,'YES',1,null)) over (partition by a.sequence#) cn #检查是否做了apply

    from v/$archived_log a where completion_time <sysdate-$retention

    and a.resetlogs_id in (

    select i.resetlogs_id from v/$database_incarnation i where status = 'CURRENT')

    )

    where rn=1 and cn=1 and bk_cnt>0

    order by sequence#;

    exit

    EOF

    return

    }

    function GetDBRole

    {

    sqlplus -S /nolog <<EOF

    connect / as sysdba

    set head off

    set feedback off

    set pages 0

    select controlfile_type from v/$database;

    exit

    EOF

    return

    }

    # check database role

    DBROLE=`GetDBRole`

    NUM=0

    if [ $DBROLE = "CURRENT" ];then

    echo "It's a primary database ......"

    # get archived log list for primary

    GetLogListForPrimary

    elif [ $DBROLE = "STANDBY" ];then

    echo "It's a standby database ......"

    # get archived log list for standby

    GetLogListForStandby

    fi

    echo "deleting archived log files ......" 

    if [ -n $tmpf ]; then

    for ARCH in `cat $tmpf`;do

    if [ -f $ARCH ];then

    NUM=`expr $NUM + 1`

    rm -f $ARCH

    fi

    done

    fi

    rm -f $tmpf

    echo "finished deleting $NUM files"

     

    设置定时任务crontab 定期执行脚本,清除归档日志

    crontab –u oracle –e

    * * */1 * * /home/oracle/backup/delArchLogs.sh 1

    每天执行一次

     

    待续....

    最新回复(0)