一、概述
本文将介绍如何给单实例搭建一个rac dg,以及如何对其进行角色转换,完成从单实例到rac的迁移。预先具备的知识(rac搭建,单实例-单实例dg搭建)
二、实验环境介绍
主库(已有数据库实例prod)
prod:192.168.56.102,sid:prod,version:11.2.0.4
从库rac(已安装rac软件,无数据库实例)
rac1:192.168.56.11,version:11.2.0.4
rac2:192.168.56.12,version:11.2.0.4
三、搭建dg
1. 主库打开归档模式,并强制写日志
先查看数据库的归档状态以及是否开启强制写日志,从下图可以看到目前数据库并没有打开归档,也没有开启强制写日志
SQL> select log_mode, force_logging from v$database;
数据库在mount状态下打开归档
[oracle@prod ~]$ mkdir -p /u01/app/oracle/oradata/prod/archivelog
SQL> alter system set log_archive_dest_1='location=/u01/app/oracle/oradata/prod/archivelog/' scope=spfile;
SQL> shutdown immediate;
SQL> startup mount;
SQL> alter database archivelog;
SQL> alter database open;
强制日志写,数据库在open状态就能修改
SQL> alter database force logging;
再来查看数据库的归档状态以及是否开启强制写日志
SQL> select log_mode, force_logging from v$database;
2. 主库打开dataguard开关
SQL> alter system set log_archive_config='dg_config=(prod,proddg)'; # prod是主库的db_unique_name,proddg是从库的db_unique_name,这里只需要把主从环境中所有db_unique_name列出来就行,谁先谁后并不影响。
3. 主库设置远程归档
SQL> alter system set log_archive_dest_3='service=proddg valid_for=(online_logfiles,primary_role) db_unique_name=proddg';
4. 将主库的口令文件传送给从库
[oracle@prod ~]$ scp $ORACLE_HOME/dbs/orapw$ORACLE_SID 192.168.56.11:$ORACLE_HOME/dbs/orapwproddg1
[oracle@prod ~]$ scp $ORACLE_HOME/dbs/orapw$ORACLE_SID 192.168.56.12:$ORACLE_HOME/dbs/orapwproddg2
5. 从库准备参数文件
[oracle@rac1 ~]$ vi /home/oracle/pfile_initproddg1.ora # 只在从库节点1上创建
*.audit_file_dest='/u01/app/oracle/admin/proddg/adump' *.audit_trail='db' *.compatible='11.2.0.4.0' *.control_files='+DATA/PRODDG/CONTROLFILE/control01.ctl' *.db_block_size=8192 *.db_domain='' *.db_name='prod' *.diagnostic_dest='/u01/app/oracle' *.log_archive_config='dg_config=(prod,proddg)' *.log_archive_dest_2='location=+DATA/PRODDG/ARCHSTDLOG/ valid_for=(standby_logfiles,standby_role) db_unique_name=proddg' *.memory_target=838860800 *.open_cursors=300 *.processes=150 *.remote_login_passwordfile='exclusive' *.standby_file_management=auto *.db_unique_name='proddg' *.db_file_name_convert='/u01/app/oracle/oradata/prod/','+DATA/proddg/datafile/','/u01/app/oracle/oradata/prod/','+DATA/proddg/tempfile/' *.log_file_name_convert='/u01/app/oracle/oradata/prod/','+DATA/proddg/onlinelog/' *.cluster_database=false proddg1.undo_tablespace='UNDOTBS1' proddg2.undo_tablespace='UNDOTBS2' proddg1.instance_number=1 proddg2.instance_number=2 proddg1.thread=1 proddg2.thread=2
6. 从库中准备相关目录
[oracle@oradg ~]$ mkdir -p /u01/app/oracle/admin/proddg/adump # 从库两节点都创建
[grid@rac1 ~]$ asmcmd # 只在从库节点1上创建
ASMCMD> lsdg
ASMCMD> cd data
ASMCMD> mkdir PRODDG
ASMCMD> cd PRODDG
ASMCMD> mkdir ARCHIVELOG
ASMCMD> mkdir ARCHSTDLOG
ASMCMD> mkdir CONTROLFILE
ASMCMD> mkdir DATAFILE
ASMCMD> mkdir ONLINELOG
ASMCMD> mkdir TEMPFILE
7. 从库生成spfile文件
[oracle@oradg ~]$ export ORACLE_SID=proddg1 # 只在从库节点1上做
[oracle@oradg ~]$ sqlplus / as sysdba
SQL> startup nomount pfile='/home/oracle/pfile_initproddg1.ora';
SQL> create spfile='+DATA/PRODDG/spfileproddg.ora' from pfile='/home/oracle/pfile_initproddg1.ora';
SQL> shutdown abort
SQL> exit
8. 从库生成pfile文件
[oracle@rac1 ~]$ echo "SPFILE='+DATA/PRODDG/spfileproddg.ora'" > $ORACLE_HOME/dbs/initproddg1.ora # 节点1生成
[oracle@rac2 ~]$ echo "SPFILE='+DATA/PRODDG/spfileproddg.ora'" > $ORACLE_HOME/dbs/initproddg2.ora # 节点2生成
9. 主库生成全库备份和standby controlfile并拷贝至从库节点1
[oracle@prod ~]$ export ORACLE_SID=prod
[oracle@prod ~]$ rman target /
RMAN> backup database format '/home/oracle/prod_%t_%s';
RMAN> backup current controlfile for standby format '/home/oracle/prod_control01.ctl';
[oracle@prod ~]$ scp /home/oracle/prod* 192.168.56.11:/home/oracle/backup
10. 在从库节点1启动实例,并恢复控制文件
[oracle@oradg ~]$ export ORACLE_SID=proddg1 # 只在从库节点1上做
[oracle@oradg ~]$ sqlplus / as sysdba
SQL> startup nomount
再开启一个窗口
[oracle@oradg ~]$ export ORACLE_SID=proddg1 # 只在从库节点1上做
[oracle@oradg ~]$ rman target /
RMAN> restore controlfile from '/home/oracle/backup/prod_control01.ctl';
RMAN> alter database mount;
RMAN> catalog start with '/home/oracle/backup'; # 将备份片的信息重新注册到控制文件中
11. 在从库节点1还原和恢复数据库备份
# 具体的数据文件和临时文件编号可以在主库通过dba_data_files,dba_temp_files查到
# 偶然通过实验发现一个比较神奇的现象,因为我前面在参数文件中定义了db_file_name_convert和log_file_name_convert,所以控制文件中的logfile和datafile的路径已经被转换好了,下面run中set newname for xxx其实是没必要的。
RMAN> run {
set newname for datafile 1 to '+DATA';
set newname for datafile 2 to '+DATA';
set newname for datafile 3 to '+DATA';
set newname for datafile 4 to '+DATA';
set newname for datafile 5 to '+DATA';
set newname for tempfile 1 to '+DATA';
restore database;
switch datafile all;
switch tempfile all;
}
RMAN> recover database;
以下错误可以暂时忽略,因为开启同步后,dg会自动同步归档日志
unable to find archived log archived log thread=1 sequence=8 RMAN-00571: =========================================================== RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS =============== RMAN-00571: =========================================================== RMAN-03002: failure of recover command at 12/16/2019 15:09:48 RMAN-06054: media recovery requesting unknown archived log for thread 1 with sequence 8 and starting SCN of 1019774
12. 在从库节点1创建standby log
# 添加的日志的大小跟主库的onlinelog保持一致,数量多两组(主库的onlinelog信息查看v$log)
SQL> alter database add standby logfile thread 1 group 21 ('+data') size 50M;
SQL> alter database add standby logfile thread 1 group 22 ('+data') size 50M;
SQL> alter database add standby logfile thread 1 group 23 ('+data') size 50M;
SQL> alter database add standby logfile thread 1 group 24 ('+data') size 50M;
SQL> alter database add standby logfile thread 2 group 25 ('+data') size 50M;
SQL> alter database add standby logfile thread 2 group 26 ('+data') size 50M;
SQL> alter database add standby logfile thread 2 group 27 ('+data') size 50M;
SQL> alter database add standby logfile thread 2 group 28 ('+data') size 50M;
13. 主库配置服务命名
[oracle@prod ~]$ vi $ORACLE_HOME/network/admin/tnsnames.ora
# 这里只需要指向节点1就行了
proddg = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.56.11)(PORT = 1521)) ) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = proddg) ) )
14. 从库打开应用日志
SQL> alter database recover managed standby database disconnect from session;
15. 主库切换归档
SQL> alter system switch logfile;
16. 打开从库
当从库应用归档一段时间后,就关闭应用归档日志,打开从库。
SQL> alter database recover managed standby database cancel;
SQL> alter database open;
SQL> alter database recover managed standby database using current logfile disconnect from session;
17. 验证同步
主库做修改
SQL> update scott.emp set sal=30;
SQL> commit;
从库查询
SQL> select * from scott.emp;
至此,从库rac1已经搭建完成,接下来将rac2加入进来
四、把从库节点2加入到集群中
18. 主库再添加一个undo tablespace
# 因为从库是2节点的rac,每个rac节点都需要使用自己的undo tablespace,所以主库添加的undotbs2同步到同库中,给从库节点2使用
SQL> create undo tablespace undotbs2 datafile '/u01/app/oracle/oradata/prod/undotbs02.dbf' size 1G autoextend on maxsize unlimited;
19. 在从库节点1修改数据库为rac模式
SQL> alter system set cluster_database=true scope=spfile;
SQL> alter system set cluster_database_instances=2 scope=spfile;
SQL> shutdown immediate
SQL> startup
SQL> alter database recover managed standby database using current logfile disconnect from session;
20. 启动从库节点2
[oracle@rac2 ~]$ export ORACLE_SID=proddg2
[oracle@rac2 ~]$ sqlplus / as sysdba
SQL> startup
21. 验证修改
主库做修改
SQL> update scott.emp set sal=40;
SQL> commit;
SQL> alter system switch logfile;
从库查询
SQL> select * from scott.emp;
22. 在从库节点1注册数据库到集群中
注册数据库
[oracle@rac1 ~]$ srvctl add database -d proddg -n prod -o /u01/app/oracle/product/11.2.0/db_1 -p +DATA/proddg/spfileproddg.ora -r physical_standby -a "DATA,OCR"
# 相关参数的意义可以通过srvctl add database -h查看
注册节点
[oracle@rac1 ~]$ srvctl add instance -d proddg -i proddg1 -n rac1
[oracle@rac1 ~]$ srvctl add instance -d proddg -i proddg2 -n rac2
检查资源配置
[oracle@rac1 ~]$ srvctl config database -d proddg
查看数据库实例是否随集群启动自动启动
[root@rac1 ~]# crsctl status res ora.proddg.db -p
修改成随集群启动自动启动
[root@rac1 ~]# crsctl modify res "ora.proddg.db" -attr "AUTO_START=always"
至此,给单实例搭建一个rac dg就已经完成,接下来将介绍如何对其做角色切换
五、主从切换准备
23. 主库添加standby logfile归档路径
[oracle@prod ~]$ mkdir -p /u01/app/oracle/oradata/prod/archstdlog
使用sys数据库账号,修改数据库参数
SQL> alter system set log_archive_dest_2='location=/u01/app/oracle/oradata/prod/archstdlog/ valid_for=(standby_logfiles,standby_role) db_unique_name=prod' sid='*';
24. 主库添加standby logfile
[oracle@prod ~]$ mkdir -p /u01/app/oracle/oradata/prod/standbylog
添加的日志的大小跟主库的onlinelog保持一致,数量多两组(主库的onlinelog信息查看v$log)
SQL> alter database add standby logfile group 21 '/u01/app/oracle/oradata/prod/standbylog/std01.log' size 50M;
SQL> alter database add standby logfile group 22 '/u01/app/oracle/oradata/prod/standbylog/std02.log' size 50M;
SQL> alter database add standby logfile group 23 '/u01/app/oracle/oradata/prod/standbylog/std03.log' size 50M;
SQL> alter database add standby logfile group 24 '/u01/app/oracle/oradata/prod/standbylog/std04.log' size 50M;
SQL> alter database add standby logfile group 25 '/u01/app/oracle/oradata/prod/standbylog/std05.log' size 50M;
SQL> alter database add standby logfile group 26 '/u01/app/oracle/oradata/prod/standbylog/std06.log' size 50M;
SQL> alter database add standby logfile group 27 '/u01/app/oracle/oradata/prod/standbylog/std07.log' size 50M;
SQL> alter database add standby logfile group 28 '/u01/app/oracle/oradata/prod/standbylog/std08.log' size 50M;
25. 主库修改参数文件
SQL> alter system set standby_file_management=auto sid='*';
SQL> alter system set db_file_name_convert='/u01/app/oracle/oradata/prod/','+DATA/proddg/datafile/' sid='*' scope=spfile;
SQL> alter system set log_file_name_convert='/u01/app/oracle/oradata/prod/','+DATA/proddg/onlinelog/' sid='*' scope=spfile;
到这里,主库转换为备库的准备工作已完成!
26. 从库配置tnsnames.ora
这里的配置tnsnames.ora的目的是,当原从库转变为新主库之后,原主库变为新从库,新主库需要给新从库发送归档日志,所以这里的tnsnames要指向新从库。
[oracle@rac1 ~]$ vi $ORACLE_HOME/network/admin/tnsnames.ora # rac两个节点都要设置
toprod = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.56.102)(PORT = 1521)) ) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = prod) ) )
27. 从库为onlinelog设置归档路径
# 只在节点1设置即可
SQL> alter system set log_archive_dest_1='location=+DATA/proddg/archivelog/ valid_for=(online_logfiles,primary_role) db_unique_name=proddg' sid='*';
28. 从库设置远程归档参数
# 只在节点1设置即可
SQL> alter system set log_archive_dest_3='service=toprod valid_for=(online_logfiles,primary_role) db_unique_name=prod' sid='*';
到这里,从库转为主库的准备工作已完成!
六、主从切换
29. 查看主库的角色转换状态
SQL> select database_role,switchover_status from v$database;
30. 主转从
执行以下命令,将主库转为从库,并且关闭实例
SQL> alter database commit to switchover to physical standby with session shutdown;
31. 在从库节点1上从转主
由于从库是集群,在从转主的过程中,只能有一个活动节点,因此关闭从库节点2
SQL> shutdown immediate # 只关闭节点2
SQL> select database_role,switchover_status from v$database;
如果是"NOT ALLOWED"表示归档还没有应用完成,可以等待一段时间
如果日志全部应用了再查看角色转换状态
SQL> select database_role,switchover_status from v$database;
如果角色转换状态是TO PRIMARY,那么表示可以进行角色转换
执行从转主的命令,命令执行成功后,数据库的状态会变为mount
SQL> alter database commit to switchover to primary;
SQL> alter database open;
32. 打开新从库
SQL> startup
应用归档
SQL> alter database recover managed standby database using current logfile disconnect from session;
在主库节点1上切换归档
SQL> alter system switch logfile;
33. 验证同步
主库做修改
SQL> update scott.emp set sal=4000;
SQL> commit;
从库查询
SQL> select * from scott.emp;
34. 在主库节点1上为节点2添加日志文件
SQL> alter database add logfile thread 2 group 4 '+DATA/proddg/onlinelog/redo04.log' size 50M;
SQL> alter database add logfile thread 2 group 5 '+DATA/proddg/onlinelog/redo05.log' size 50M;
SQL> alter database add logfile thread 2 group 6 '+DATA/proddg/onlinelog/redo06.log' size 50M;
SQL> alter database enable thread 2;
35. 启动新主库节点2实例
SQL> startup # 只在节点2上操作
36. 错误处理
如果发现日志传不到备库的话可以在主库通过以下命令查看错误原因
SQL> select dest_id,dest_name,log_sequence,status,error from v$archive_dest;
如果报上面的错误的话,可以把归档开关重启一下即可
SQL> alter system set log_archive_dest_state_3='defer' sid='*';
SQL> alter system set log_archive_dest_state_3='enable' sid='*';
七、总结
1. dg的切换需要停掉所有的应用,并把数据库的所有连接全部kill掉,账号全锁(此举是为了防止切换过程中有其它用户登录数据库),切换完成后再解锁
2. rac在切换时,只留一个活的实例,其它全部关闭
3. 命令每执行一条,就留意返回的结果,并实时查看alert.log
4. 由于篇幅限制,文章没有展示每步运行的结果。所以文章只是提供一个思路,具体步骤还需要根据自己库的实际情况来