zoukankan      html  css  js  c++  java
  • oracle异机恢复测试

    (一)问题背景

    最近在生产环境中,开发人员误操作,使用truncate将oracle数据库某个表的数据全部删除了,在删除之后,开发人员发现自己闯祸了,于是联系值班的DBA进行紧急数据恢复。

    经过分析,表被truncate后,使用一般的闪回表、闪回查询、闪回事物等方法,是不可能将数据找回来的,可以使用闪回数据库、闪回数据归档的方法来进行恢复,但是通常在生产环境中,都不会开启这2个特性,所以剩下的只有使用RMAN进行数据恢复了。

    对于使用RMAN进行数据恢复,可以在生产环境上直接进行,也可以恢复到其它机器上。

    • 直接在生产环境上恢复:①需要停止生产数据库;②数据库需要保持一致性,比如说,我需要将数据库恢复到12:00,那么数据库中其他表的数据也将恢复到12点,有可能会丢失较多数据;③如果恢复过程中出现其它问题也比较麻烦,耽误了生产业务执行。
    • 恢复到其它机器上:②不需要停生产库;②仅仅丢失truncate表的数据,比如说,我需要将数据库恢复到12:00,那么我只需将整个库在测试环境上恢复到12点,再将我们丢失表的数据通过DB_LINK或数据泵等方式恢复到生产环境,生产环境其它表的数据是不受影响的;③恢复失败,并不会影响到生产库。

    所以,经过一番考虑,决定将数据库恢复到其它机器上,然后再将truncate表的数据导回到生产环境。

    此次恢复操作是同事做的,在恢复过程中,由于流程不熟悉,查资料耽误了一些时间(大约20分钟),虽然数据库恢复完成了,但没有达到快速恢复的要求。思考了一下,假如自己来做,能否在开发人员焦急等待的情况下,自己毫不慌乱、快速稳定的完成数据库恢复?确实是不可能的。一方面恢复流程不熟练,毕竟数据库恢复操作一年也不可能遇到几次,另一方面在用户及开发人员催促的情况下,DBA也很容易慌张,影响效率。因此最好的方式是:提前演练、写好操作流程。当故障发生时,照着文档操作,以最快的速度恢复生产。

     

    (二)环境准备

      生产环境 异机环境
    操作系统 RedHat6.7 RedHat6.7
    数据库版本 11.2.0.4(RAC,2个节点) 11.2.0.4(单节点)
    db_name prodb prodb
    instance_name prodb1、prodb2 prodb
    数据库安装情况 安装GI+数据库软件+创建数据库 安装GI+数据库软件 (不用创建数据库)
    磁盘组信息 OCR   : 3*1GB,normal
    DATA :3*5GB,external
    ARCH :  1*5GB,external
    OCR   : 3*1GB,normal
    DATA :3*5GB,external
    ARCH :  1*5GB,external

    备注:为了方便,在后续环境中,生产环境数据库简称“生产库”,异机环境的数据库简称“测试库”。

    (三)测试方案

    image

    (四)详细执行过程

    (4.1)创建测试表

    这里创建了2个测试表,作用分别如下:

    lijiaman.test01:用于做truncate测试的表,最后在测试库需要进行test01表的恢复。

    lijiaman.test02:用于模拟数据库事务,对该表不断执行插入操作,使得数据库产生大量归档日志。

    (Ⅰ)表test01,一共有14笔数据。

    SQL> CREATE TABLE test01 AS SELECT * FROM scott.emp;
    Table created
    
    SQL> select count(*) from test01;
      COUNT(*)
    ----------
            14

    (ⅠⅠ)表test02,持续往里面写入数据

    --创建表test02
    create table test02
    (
        col1      number,    
        col2      number,
        col3      varchar2(30),
        col4      date,
        col5      varchar2(100)                           
    );
    
    --创建随机数据插入存储过程
    create or replace procedure p_insert_test02 is
    BEGIN
      FOR i IN 1..10000 LOOP
      insert into test02(col1,col2,col3,col4,col5)
      values
        ((select round(dbms_random.value(1, 100000000)) from dual),
         (select round(dbms_random.value(10000, 100000000)) from dual),
         (select dbms_random.string('a', 25) from dual),
         sysdate,
         (select dbms_random.string('a', 85) from dual));
      commit;
      END LOOP;
    end  p_insert_test02;
    
    --制定job,没隔30s执行一次上面的存储过程
    declare
    job1 number;
    begin
    sys.dbms_job.submit(job => job1,
    what => 'p_insert_test02;',
    next_date => sysdate,
    interval => 'sysdate + 30/(1440*60)');                --每隔30s向test02表插入10000笔随机数据
    commit;
    end;
    /

    (4.2)对数据库进行完全备份

    rman target /
    
    RMAN> run {
    allocate channel c1 type disk;
    allocate channel c2 type disk;
    sql' alter system archive log current';
    backup database format '/databaseBackup/full_db_%U';
    sql' alter system archive log current';
    backup archivelog all format '/databaseBackup/archlog_%U';
    backup current controlfile format '/databaseBackup/controlfile_%U';
    backup spfile format '/databaseBackup/spfile_%U';
    release channel c1;
    release channel c2;
    }

    生成的备份集如下:

    [oracle@node1 databaseBackup]$ ls -l
    total 4136752
    -rw-r----- 1 oracle asmadmin 1451128832  Sep 27 19:27 archlog_0iucr7hg_1_1
    -rw-r----- 1 oracle asmadmin 1462116352  Sep 27 19:27 archlog_0jucr7hh_1_1
    -rw-r----- 1 oracle asmadmin     1406464   Sep 27 19:27 archlog_0kucr7lr_1_1
    -rw-r----- 1 oracle asmadmin   18841600   Sep 27 19:28 controlfile_0lucr7m2_1_1
    -rw-r----- 1 oracle asmadmin  805953536   Sep 27 19:25 full_db_0eucr7f7_1_1
    -rw-r----- 1 oracle asmadmin  477528064   Sep 27 19:25 full_db_0fucr7f7_1_1
    -rw-r----- 1 oracle asmadmin   18841600   Sep 27 19:25 full_db_0gucr7h3_1_1
    -rw-r----- 1 oracle asmadmin        98304   Sep 27 19:25 full_db_0hucr7ha_1_1
    -rw-r----- 1 oracle asmadmin        98304   Sep 27 19:28 spfile_0mucr7m5_1_1

    确认归档日志备份情况,可以看到,本次全备份归档日志备份到了thread1:57,thread2:48。

    RMAN> list archivelog all;

    List of Archived Log Copies for database with db_unique_name PRODB
    =====================================================================

    Key     Thrd  Seq     S  Low Time
    ------- ---- ------- - ---------
    3            1    6       A 24-SEP-19
            Name: +ARCH/prodb/archivelog/2019_09_24/thread_1_seq_6.258.1019832847
    ......
    100        1     57      A 27-SEP-19
            Name: +ARCH/prodb/archivelog/2019_09_27/thread_1_seq_57.355.1020108489

    1           2     1       A 24-SEP-19
            Name: +ARCH/prodb/archivelog/2019_09_24/thread_2_seq_1.256.1019830885
    ......
    80         2     48      A 24-SEP-19
            Name: +ARCH/prodb/archivelog/2019_09_24/thread_2_seq_48.335.1019838555

    (4.3)数据库正常运行,产生大量归档

    由于日志序列号是递增的(以resetlogs打开数据库例外),因此查询每个实例上生成的最大日志即可

    SELECT *
    FROM 
    (SELECT thread#,
           SEQUENCE#,
           NAME,
           ROW_NUMBER() OVER(PARTITION BY thread# ORDER BY SEQUENCE# DESC) rn
      FROM V$ARCHIVED_LOG)
    WHERE rn=1;

    结果为:

    image

    即thread1上的归档日志最大序列号为67,thread2上的归档日志最大序列号为48(这里因为个人电脑开较多虚拟机太卡,所以只开了节点1,节点2就没有日志生成,并不影响本次实验结果的准确性)。

     

    (4.4)模拟test01表被truncate,记下时间

    SQL> select sysdate from dual;
    
    SYSDATE
    -------------------
    2019-09-27 19:37:31
    
    SQL> 
    SQL> truncate table test01;
    
    Table truncated.

    (4.5)数据库正常运行,产生大量归档

    上一次备份到了sequence=57的日志,上一次备份后又生成了25个日志,这里生成大量日志是为了模拟生产数据库这次交易的情况。

    image

    (4.6)开发人员发现表数据被truncate

    开发人员发现程序报错,查看表test01,发现数据全没了,开发人员确认数据被自己删除(假设)。

     

    (4.7)DBA执行异机恢复

    思路整理:

    image

    本次恢复,需要将test01表恢复到truncate之前,我们需要有执行truncate操作之前的数据库全备和归档备份。第一次全备归档日志文件之备份到了thread1=57,thread2=48,在执行全被之后,又生成了许多的日志文件,我们要将数据库恢复到truncate之前(这里以我们记录的时间2019-09-27 19:37:31 为恢复点),那么我们还需要新的日志来做恢复,需要的日志如下:

    thread1:日志57~67肯定需要,日志67~82不一定需要;

    thread2:由于节点未开启,不需要日志来做恢复。

    step1:将生产库的备份集传到测试库

    [oracle@node1 databaseBackup]$ scp * 192.168.10.66:/databaseBackup/

    step2:对恢复需要的归档日志进行再次备份,得到缺少的归档日志

    run {
    allocate channel c1 type disk;
    sql' alter system archive log current';
    backup archivelog all format '/databaseBackup/archlog_20190927_%U';
    release channel c1;
    }

    得到的归档日志备份集如下:

    -rw-r----- 1 oracle asmadmin 1621476864 Sep 27 20:50 archlog_20190927_0nucrcd2_1_1
    -rw-r----- 1 oracle asmadmin 1643560960 Sep 27 20:51 archlog_20190927_0oucrcg5_1_1
    -rw-r----- 1 oracle asmadmin 1581030912 Sep 27 20:53 archlog_20190927_0pucrcjj_1_1

    传送到备库上
    [oracle@node1 databaseBackup]$ scp archlog_20190927_0* 192.168.10.66:/databaseBackup/
    step3:根据生产库的pfile,构造一个测试库的pfile

    [oracle@test dbs]$ pwd
    /u01/app/oracle/product/11.2.0/db_1/dbs
    
    [oracle@test dbs]$ vim init initprodb.ora
    # 添加如下信息
    audit_file_dest='/u01/app/oracle/admin/prodb/adump'
    audit_trail='db'
    compatible='11.2.0.4.0'
    control_files='+DATA/prodb/controlfile/current.260.1019830577'
    db_block_size=8192
    db_create_file_dest='+DATA'
    db_domain=''
    db_name='prodb'
    diagnostic_dest='/u01/app/oracle'
    dispatchers='(PROTOCOL=TCP) (SERVICE=prodbXDB)'
    enable_ddl_logging=TRUE
    log_archive_dest_1='LOCATION=+arch'
    log_archive_format='%t_%s_%r.dbf'
    open_cursors=300
    pga_aggregate_target=399507456
    processes=200
    remote_login_passwordfile='exclusive'
    sessions=225
    sga_target=1199570944
    prodb.undo_tablespace='UNDOTBS1'
    
    [oracle@test dbs]$ ls
    hc_prodb.dat  hc_testdb1.dat  hc_testdb.dat  init.ora  initprodb.ora  lkTESTDB

    创建pfile里面涉及到的路径:

    [oracle@test ~]$ mkdir -p /u01/app/oracle/admin/prodb/adump

    step4:将备库启动到nomount状态

    [oracle@test ~]$ export ORACLE_SID=prodb
    [oracle@test ~]$ sqlplus / as sysdba
    
    SQL*Plus: Release 11.2.0.4.0 Production on Fri Sep 27 20:58:15 2019
    
    Copyright (c) 1982, 2013, Oracle.  All rights reserved.
    
    Connected to an idle instance.
    
    SQL> startup nomount;
    ORACLE instance started.
    
    Total System Global Area 1202556928 bytes
    Fixed Size            2252704 bytes
    Variable Size          402653280 bytes
    Database Buffers      788529152 bytes
    Redo Buffers            9121792 bytes
    SQL>

    step5:将数据库添加到HA中,以便可以使用ASM存储

    [oracle@test ~]$ srvctl add database -d prodb -o /u01/app/oracle/product/11.2.0/db_1

    step6:恢复控制文件,修改pfile文件,重新启动数据库到mount状态

    RMAN> restore controlfile from "/databaseBackup/controlfile_0lucr7m2_1_1";

    注意:此时存在一个问题,我们在构造pfile文件的时候,里面填写了控制文件的位置,这个位置是生产库上的位置,我们执行控制文件恢复后,需要对参数文件中的control_files参数进行修改,修改方法如下:

    --首先,确认contril file在asm中的位置,

    ASMCMD> pwd
    +data/prodb/controlfile
    ASMCMD> ls -lt
    Type         Redund  Striped  Time             Sys  Name
    CONTROLFILE  UNPROT  FINE     SEP 27 21:00:00  Y    current.256.1020114329

    --接下来,修改pfile文件的control_files参数

    [oracle@test ~]$ cd $ORACLE_HOME/dbs
    [oracle@test dbs]$ vim initprodb.ora 
    # 改control_files位置
    control_files='+data/prodb/controlfile/current.256.1020114329'

    --重启数据库到mount状态

    [oracle@test ~]$ sqlplus / as sysdba
    
    SQL*Plus: Release 11.2.0.4.0 Production on Fri Sep 27 21:17:26 2019
    
    Copyright (c) 1982, 2013, Oracle.  All rights reserved.
    
    
    Connected to:
    Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
    With the Partitioning, Automatic Storage Management, OLAP, Data Mining
    and Real Application Testing options
    
    SQL> shutdown immediate
    ORA-01507: database not mounted
    
    
    ORACLE instance shut down.
    SQL> startup mount
    ORACLE instance started.
    
    Total System Global Area 1202556928 bytes
    Fixed Size            2252704 bytes
    Variable Size          402653280 bytes
    Database Buffers      788529152 bytes
    Redo Buffers            9121792 bytes
    Database mounted.
    SQL>

    step7:注册新的归档日志备份集到备库的控制文件中

    RMAN> catalog backuppiece "/databaseBackup/archlog_20190927_0nucrcd2_1_1";
    RMAN> catalog backuppiece "/databaseBackup/archlog_20190927_0oucrcg5_1_1";
    RMAN> catalog backuppiece "/databaseBackup/archlog_20190927_0pucrcjj_1_1";

    step8:恢复数据库到truncate之前

    RMAN>SQL"ALTER SESSION SET NLS_LANGUAGE=''AMERICAN''";
    RMAN>SQL"ALTER SESSION SET NLS_DATE_FORMAT=''YYYY-MM-DD HH24:MI:SS''";
    RUN{
    SET UNTIL TIME '2019-09-27 19:37:31';
    RESTORE DATABASE;
    RECOVER DATABASE;
    }
    step9:确认数据是已经否恢复回来
    --先以只读方式打开数据库,如果有问题,还可以重新执行恢复
    SQL> alter database open read only;
    Database altered.
    
    --确认数据是否找回来
    SQL> select count(*) from lijiaman.test01;
      COUNT(*)
    ----------
        14

    step10:如果没问题,关闭数据库,以resetlogs方式打开

    SQL> shutdown immediate;
    Database closed.
    Database dismounted.
    ORACLE instance shut down.
    
    SQL> startup mount
    ORACLE instance started.
    
    Total System Global Area 1202556928 bytes
    Fixed Size            2252704 bytes
    Variable Size          402653280 bytes
    Database Buffers      788529152 bytes
    Redo Buffers            9121792 bytes
    Database mounted.
    
    SQL> alter database open resetlogs;
    
    Database altered.

    恢复完成。

    (4.8)将恢复的数据导入到生产环境

    可以使用expdp/impdp或者是dblink将数据从测试库导入到生产库中。

    【完】

  • 相关阅读:
    javaweb(十四)——JSP原理
    JavaWeb(十三)——使用Session防止表单重复提交
    javaweb(十一)——使用Cookie进行会话管理
    javaweb(十)——HttpServletRequest对象(一)
    javaweb(八)——HttpServletResponse对象(二)
    javaweb(七)——HttpServletResponse对象(一)
    《锋利的jQruery》读书笔记
    rem单位在手机网站中的使用
    JavaScript权威指南读书笔记
    dreamwaver cs6 主题配色方案
  • 原文地址:https://www.cnblogs.com/lijiaman/p/11577001.html
Copyright © 2011-2022 走看看