3.3 逻辑DataGuard滚动升级
想必熟悉Oracle的人都知道Data Guard(简称DG)。DG主要可分为两大类:物理standby和逻辑standby,前者主要用于同版本的迁移和容灾备份。后者使用得相对较少,把它用为迁移方式的更是寥寥无几,但使用逻辑DG迁移有着相当大的优势。Oracle的逻辑DG可以实现数据库的滚动升级,这将大大缩短业务的停用时间,其停机时间仅为两者的切换时间,这种方式对于7×24小时的业务非常适用。
那么逻辑DG是如何实现对数据库的滚动升级的呢,下面就以实际案例展开说明。
本文的环境为Linux 11.2.0.4单机+物理DG,首先将物理DG临时转换为逻辑DG,再在逻辑备库上执行升级,升级完成后,备库切换为主库,然后原主库切换为备库,再进行升级。此过程所需要的业务停顿时间,只是DataGuard的切换时间。逻辑DG主要是通过SQL apply应用增量数据来降低升级过程中的停机时间。
主要升级步骤如表3-2所示。
表3-2 逻辑DataGuard滚动升级步骤
注意,逻辑备库只需要在物理备库的基础上进行转换即可,此处不展开讲解物理备库的搭建过程,有兴趣的读者可以自行查看官方文档《Oracle Data Guard Concepts and Administration》进行搭建。
3.3.1 生产端前期准备
生产端的前期准备如下。
1)生产库创建强制闪回点(需要提前开启闪回),命令如下:
SQL> STARTUP MOUNT; SQL> CREATE RESTORE POINT pre_upgrade GUARANTEE FLASHBACK DATABASE;
为了回退需要,备份控制文件和在线日志文件,命令如下:
shell> cp /oracle/ora11204/oradata/orcl/*.ctl /oracle/ora11204/oradata/orcl/redo* / oracle/ora11204/bak/
开启SQL apply,主库必须在最大可用或最大性能模式下运行,命令如下:
SQL> alter database set standby database to maximize availability; SQL> ALTER DATABASE OPEN;
2)生产开启附加日志,命令如下:
SQL> ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY, UNIQUE INDEX) COLUMNS;
3)DG端设置一个额外的目录,用于存放逻辑DG产生的归档,命令如下:
SQL>alter system set log_archive_dest_3='LOCATION=/oracle/ora11204/arch/std VALID_FOR=(STANDBY_LOGFILES,STANDBY_ROLE)'; SQL> alter system set log_archive_dest_state_3=enable;
4)检查不支持的数据类型表,命令如下:
SQL> SELECT * FROM DBA_LOGSTDBY_EDS_SUPPORTED; SQL> EXECUTE DBMS_LOGSTDBY.EDS_ADD_TABLE(schema_name, table_name);
在生产库上通过如下命令捕捉不受sql apply支持的事务,记录到DBA_LOGSTDBY_EVENTS表中:
SQL>EXECUTE DBMS_LOGSTDBY.APPLY_SET('MAX_EVENTS_RECORDED', DBMS_LOGSTDBY.MAX_EVENTS); SQL> EXECUTE DBMS_LOGSTDBY.APPLY_SET('RECORD_UNSUPPORTED_OPERATIONS', 'TRUE');
5)生成sql apply需要的数据字典。
从主库上获取备库所需的数据字典信息,命令如下:
sql> EXECUTE dbms_logstdby.build;
logmnr会根据数据字典信息将redo转换为逻辑DG的sql。
3.3.2 备端前期准备
备端的前期准备如下。
1)DG端创建闪回点(需要提前开启闪回),命令如下:
SQL> STARTUP MOUNT; SQL> CREATE RESTORE POINT pre_upgrade GUARANTEE FLASHBACK DATABASE;
2)将物理DG转换为逻辑DG。
确认主备同步后,在备库上执行如下语句:
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL; SQL> ALTER DATABASE RECOVER TO LOGICAL STANDBY KEEP IDENTITY;
ADG(Active Data Guard)需要关闭,重启到mount状态。如果卡住,则先启用实时应用(real time apply),然后关闭再尝试。代码中的“KEEP IDENTITY”是为了保持DBID不变,这是Oracle 11g引入的新特性。Oracle 10g只能是“ALTER DATABASE RECOVER TO LOGICAL STANDBY db_name;”。
3)关闭逻辑DG的自动删除归档,命令如下:
SQL> EXECUTE DBMS_LOGSTDBY.APPLY_SET('LOG_AUTO_DELETE', 'FALSE');
4)逻辑DG启用sql apply,命令如下:
SQL> ALTER DATABASE START LOGICAL STANDBY APPLY IMMEDIATE;
immediate表示实时应用,同时还需要有备库重做日志(standby redolog),否则会报错。
5)安装Oracle 12c软件。
在DG端安装Oracle 12c软件的过程在此不展开讲解。
6)关闭数据库,停止监听,命令如下:
SQL> ALTER DATABASE STOP LOGICAL STANDBY APPLY; SQL> SHUTDOWN IMMEDIATE; shell> LSNRCTL STOP;
备库关闭监听后,主库无法将日志传输过来,可以在生产端临时停用日志传输,命令如下:
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_2=DEFER;
3.3.3 将逻辑DG升级至Oracle 12c
以下是升级步骤。
1)执行preupgrade.jar升级预检。Oracle 12c用preupgrade.jar替换了utlu112i.sql来执行预检工作,该Java程序会生成两个SQL脚本文件,用来修复一些简单的问题,比如,提前收集字典统计信息之类的操作,但是很多操作仍然需要手工完成。
preupgrade.jar的语法如下:
shell> Earlier_release_Oracle_home/jdk/bin/java -jar $New_release_Oracle_home/rdbms/ admin/preupgrade.jar [FILE|TERMINAL] [TEXT|XML] [DIR output_dir] FILE|TERMINAL <!--指定检查结果是输出到终端还是文件,默认是文件--> TEXT|XML <!--指定结果格式是文本格式还是XML格式,默认是文本--> DIR - <!--将日志输出到指定目录,如果没有指定,则优先输出到 $ORACLE_BASE/cfgtoollogs/<dbname>/preupgrade/目录,如果没有ORACLE_BASE环境变量, 则输出到 $ORACLE_HOME/cfgtoollogs/<db_name>/preupgrade/目录--> shell> export ORACLE_BASE=/oracle/ora11204 <!--注意要用Oracle 11g的JDK来执行--> shell> export ORACLE_HOME=$ORACLE_BASE/db_1 shell> export ORACLE_SID=tt $ORACLE_HOME/jdk/bin/java -jar /oracle/12c/product/12.2.0/dbhome_1/rdbms/admin/ preupgrade.jar file text dir ./precheck.log Preupgrade generated files: /home/oracle/precheck.log/preupgrade.log <!--检查结果--> /home/oracle/precheck.log/preupgrade_fixups.sql <!--升级前预检问题修复脚本,检查 结果中标记为AUTOFIXUP的可以通过这个修复--> /home/oracle/precheck.log/postupgrade_fixups.sql <!--升级后问题修复脚本-->
这里检查出以下问题:
+ Update NUMERIC INITIALIZATION PARAMETERS to meet estimated minimums. Parameter 12.2.0.1.0 minimum --------- ------------------ processes 300
建议删除sec_case_sensitive_logon参数。
删除EM组件可以减少升级停机时间(升级过程会自动删除,但是建议提前手动删除),删除命令如下:
Copy the $ORACLE_HOME/rdbms/admin/emremove.sql script from the target 12.2.0.1.0 ORACLE_HOME into the source 11.2.0.4.0 ORACLE_HOME. Step 1: If database control is configured, stop EM Database Control, using the following command shell> > emctl stop dbconsole Step 2: Connect to the database using the SYS account AS SYSDBA SQL> SET ECHO ON; SQL> SET SERVEROUTPUT ON; SQL> @emremove.sql Remove OLAP Catalog by running the 11.2.0.4.0 SQL script $ORACLE_HOME/olap/admin/catnoamd.sql script. The OLAP Catalog component, AMD, exists in the database. Starting with Oracle Database 12c, the OLAP Catalog (OLAP AMD) is desupported and will be automatically marked as OPTION OFF during the database upgrade if present. Oracle recommends removing OLAP Catalog (OLAP AMD) before database upgrade. (AUTOFIXUP) Gather stale data dictionary statistics prior to database upgrade in off-peak time using: SQL> EXECUTE DBMS_STATS.GATHER_DICTIONARY_STATS;
2)收集数据字典统计信息,命令如下:
SQL> EXECUTE DBMS_STATS.GATHER_DICTIONARY_STATS; SQL> EXECUTE DBMS_STATS.GATHER_FIXED_OBJECTS_STATS;
3)确认物化视图都已停止刷新,命令如下:
SQL> SELECT o.name FROM sys.obj$ o, sys.user$ u, sys.sum$ s WHERE o.type# = 42 AND bitand(s.mflags, 8) =8;
4)确认数据文件不需要介质恢复,且不处于备份(backup)模式,命令如下:
SQL> SELECT * from v$recover_file; SQL> SELECT * FROM v$backup WHERE status != 'NOT ACTIVE';
5)处理分布式事务,命令如下:
SQL> SELECT * FROM DBA_2PC_PENDING; IF THIS RETURNS ROWS YOU SHOULD DO THE FOLLOWING: SQL> SELECT LOCAL_TRAN_ID FROM DBA_2PC_PENDING; SQL> EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY(''); SQL> COMMIT;
6)创建DBLINK的脚本,命令如下:
SQL> SELECT 'CREATE '||DECODE(U.NAME,'PUBLIC','public ')||'DATABASE LINK '||CHR(10) ||DECODE(U.NAME,'PUBLIC',Null, 'SYS','',U.NAME||'.')|| L.NAME||chr(10) ||'CONNECT TO ' || L.USERID || ' IDENTIFIED BY "'||L.PASSWORD||'" USING '''||L.HOST||'''' ||chr(10)||';' TEXT FROM SYS.LINK$ L, SYS.USER$ U WHERE L.OWNER# = U.USER#;
7)清理回收站,命令如下:
SQL> PURGE DBA_RECYCLEBIN;
8)收集EM信息,命令如下:
shell> emdwgrd -save -sid tt -path /home/oracle
降级回退的时候需要收集EM信息。注意,为了减少升级时间,建议在升级Oracle 12c之前先删除EM组件,删除命令如下:
shell> emctl stop dbconsole
将Oracle 12c的emremove.sql脚本复制到/tmp目录中,命令如下:
shell> cp /oracle/12c/product/12.2.0/dbhome_1/rdbms/admin/emremove.sql /tmp SQL> SET ECHO ON; SQL> SET SERVEROUTPUT ON; SQL> @/tmp/emremove.sql
9)修改必要参数,命令如下:
shell> vi $ORACLE_HOME/dbs/initorcl.ora *.audit_file_dest='/oracle/12c/admin/orcl/adump' *.audit_trail='NONE' *.compatible='11.2.0.4.0' *.control_files='/oracle/ora11204/oradata/orcl/std' *.db_block_size=8192 *.db_domain='' *.db_name='orcl' *.diagnostic_dest='/oracle/12c' *.dispatchers='(PROTOCOL=TCP) (SERVICE=orclXDB)' *.fal_client='DG' *.fal_server='prod' *.log_archive_dest_1='location=/oracle/ora11204/arch valid_for=(online_logfiles, all_roles)'<!--这个用来存放逻辑DG写操作产生的归档--> *.log_archive_dest_2='service=prod valid_for=(online_logfile,primary_role)' *.log_archive_dest_3='LOCATION=/oracle/ora11204/arch/std VALID_FOR= (STANDBY_LOGFILES,STANDBY_ROLE)' <!--这个是为了接收生产传过来的归档--> *.open_cursors=300 *.pga_aggregate_target=1203765248 *.processes=500 *.remote_login_passwordfile='EXCLUSIVE' *.sga_target=3613392896 *.undo_tablespace='UNDOTBS1' *.db_recovery_file_dest='/oracle/ora11204/fast_recovery_area' *.db_recovery_file_dest_size='20G' shell> mkdir -p /oracle/12c/admin/orcl/adump
10)删除OLAP组件,命令如下:
SQL> @?/olap/admin/catnoamd.sql SQL> select distinct(trunc(last_refresh)) from dba_snapshot_refresh_times; SQL> select s.obj#,o.obj#,s.containerobj#,lastrefreshdate,pflags,xpflags,o.name, o.owner#, bitand(s.mflags, 8) from obj$ o, sum$ s where o.obj# = s.obj# and o.type# = 42 AND bitand(s.mflags, 8) = 8;
11)检查拥有ADMINISTER DATABASE TRIGGER权限的用户。如果用户创建了数据库级别的触发器,则必须要拥有ADMINISTER DATABASE TRIGGER权限,示例代码如下:
SQL> SELECT OWNER, TRIGGER_NAME FROM DBA_TRIGGERS WHERE BASE_OBJECT_TYPE='DATABASE' AND OWNER NOT IN (SELECT GRANTEE FROM DBA_SYS_PRIVS WHERE PRIVILEGE='ADMINISTER DATABASE TRIGGER'); SQL> grant ADMINISTER DATABASE TRIGGER to xxxx;
12)升级APEX。为了减少升级时间,可以提前升级APEX,本例中没有提前升级,而是在数据库升级的过程中一起升级的,示例代码如下:
The database contains APEX version 3.2.1.00.12 and will need to be upgraded to at least version 5.0.4.00.12. To reduce database upgrade time, you can upgrade APEX manually before the database upgrade. Refer to My Oracle Support Note 1088970.1 for information on APEX installation upgrades.
13)升级数据库。用Oracle 12c软件启动逻辑DG,命令如下:
SQL> startup upgrade shell> nohup dbupgrade -oracleHome /oracle/12c/product/12.2.0/dbhome_1 &
14)重新打开数据库,刷新无效对象,命令如下:
shell> sqlplus / as sysdba SQL> create spfile from pfile; SQL> startup shell> cd $ORACLE_HOME/rdbms/admin shell> $ORACLE_HOME/perl/bin/perl catcon.pl -n 1 -e -b utlrp -d '''.''' utlrp.sql <!--此时,dba_registry内所有组件的状态都从UPGRADED变为VALID-->
刷新完无效对象之后,与之前的无效对象进行对比,命令如下:
SQL> select owner,object_name from dba_objects where status<>'VALID' and object_name not in (select object_name from invalid_object_20191124);
执行预检生成的修复脚本,包括重新收集x$基表和字典统计信息等,命令如下:
SQL> @/home/oracle/precheck.log/postupgrade_fixups.sql
15)复制tnsnames.ora和密码文件到Oracle 12c环境,命令如下:
shell> [oracle@high admin]$ cp /oracle/ora11204/db_1/network/admin/tnsnames.ora . shell> [oracle@high dbs]$ cp /oracle/ora11204/db_1/dbs/orapworcl
3.3.4 第一次主备切换
第一次主备切换的过程如下。
1)启用SQL apply追平数据。逻辑DG再次启用SQL apply,命令如下:
SQL> ALTER DATABASE START LOGICAL STANDBY APPLY IMMEDIATE; SQL> ALTER SESSION SET NLS_DATE_FORMAT = 'yy-mm-dd HH24:MI:SS'; SQL> SELECT SYSDATE, APPLIED_TIME FROM V$LOGSTDBY_PROGRESS; SYSDATE APPLIED_TIME ----------------- ----------------- 17-04-18 17:38:38 17-04-18 05:47:34
监控以上SQL apply的进度,检查是否与当前时间点接近。
2)处理不受SQL apply支持的表。正式关闭应用,确保生产库没有连接,命令如下:
SQL> SELECT EVENT_TIMESTAMP, EVENT, STATUS FROM DBA_LOGSTDBY_EVENTS ORDER BY EVENT_TIMESTAMP;
检查升级过程中的监控事件,在逻辑DG上查询DBA_LOGSTDBY_EVENTS视图,该视图可用于记录在逻辑备库上有没有应用的DDL与DML操作,ORA-16226错误表示在逻辑备库上不支持相关的DDL操作,常见的原因是该类操作涉及内部对象;ORA-16129错误表示在逻辑备库上不支持相关的DML操作。
如果有业务表出现如上所说的错误,则需要通过impdp将问题对象同步到逻辑DG上,同步命令如下:
shell> impdp \"/ as sysdba\" NETWORK_LINK=databasea TABLES=scott.emp TABLE_EXISTS_ACTION=TRUNCATE
3)主备切换。先检查生产库状态,命令如下:
SQL> SELECT database_role,SWITCHOVER_STATUS FROM V$DATABASE; DATABASE_ROLE SWITCHOVER_STATUS ---------------- -------------------- PRIMARY SESSIONS ACTIVE
然后检查逻辑DG的状态,命令如下:
SQL> SELECT database_role,SWITCHOVER_STATUS FROM V$DATABASE; DATABASE_ROLE SWITCHOVER_STATUS ---------------- -------------------- LOGICAL STANDBY NOT ALLOWED
之后将主库切换成逻辑DG,这条命令会等待事务完成:
SQL> ALTER DATABASE COMMIT TO SWITCHOVER TO LOGICAL STANDBY;
切换完成后,主备库DATABASE_ROLE都变成了逻辑备库(LOGICAL STANDBY),然后再将原先的逻辑DG切换成主库,命令如下:
SQL> ALTER DATABASE COMMIT TO SWITCHOVER TO PRIMARY;
现在就是由原逻辑DG(Oracle 12c版本)接管应用了。
3.3.5 升级原生产库
升级原生产库的过程如下。
1)闪回原生产。将原主库闪回到起初创建的还原点上,命令如下:
SQL> SHUTDOWN IMMEDIATE; SQL> STARTUP MOUNT; SQL> flashback database to restore point pre_upgrade; SQL> SHUTDOWN IMMEDIATE;
将原生产库$ORACLE_HOME/dbs目录下的密码文件和network/admin中的listener.ora、tnsnames.ora复制到新的Oracle 12c目录中。
2)准备参数文件。从当前生产(原逻辑DG)复制相关文件,命令如下:
shell> scp initorcl.ora orapworcl 192.168.200.34:/oracle/12c/product/12.2.0/ dbhome_1/dbs shell> vi initorcl.ora修改如下内容 *.control_files='/oracle/ora11204/oradata/orcl/control01.ctl' *.fal_client='PROD' *.fal_server='dg' *.log_archive_dest_1='location=/oracle/ora11204/arch valid_for=(online_ logfiles,all_roles)' *.log_archive_dest_2='service=dg valid_for=(online_logfile,primary_role)' *.log_archive_dest_3='LOCATION=/oracle/ora11204/arch/std VALID_FOR=(STANDBY_ LOGFILES,STANDBY_ROLE)'
3)用Oracle 12c加载原生产库,命令如下:
shell> cp nsnames.ora /oracle/12c/product/12.2.0/dbhome_1/network/admin/ shell> mkdir /oracle/12c/admin/orcl/adump shell> startup mount
停止Oracle 11g监听,启动Oracle 12c监听。
4)将原生产库切换回物理备库,命令如下:
SQL> ALTER DATABASE CONVERT TO PHYSICAL STANDBY; SQL> SHUTDOWN IMMEDIATE;
原生产库只需要通过应用升级期间产生的归档日志即可完成自身的升级,相关命令如下:
SQL> STARTUP MOUNT; SQL> RECOVER MANAGED STANDBY DATABASE DISCONNECT;
3.3.6 升级失败回退措施
如果按3.3.3节的方式将逻辑DG升级至Oracle 12c失败,则直接用创建的闪回点闪回至升级开始之前的状态即可,生产不用进行任何操作。回退命令如下:
SQL> startup mount SQL> flashback database to restore point pre_upgrade; SQL> shutdown immediate SQL> startup mount; SQL> recover managed standby database disconnect;