一、Data Guard提供如下三种数据保护模式:
1)最高保护模式(Maximum Protection)
这里的”最高保护“是指最大限度的保护数据不丢失,也就是至少有一个standby和primary保持实时同步,但这样做的代价很大,因为只要当一个事务提交时,不但要写到primary段的online redo log,还有写到至少一个standby的standby redo log。这样会有一个严重的问题,就是当standby出现故障或网络故障,导致日志无法同步时,primary数据库会被shutdown,这在生产系统中是不可接受的,因此这种模式很少用。
2)最高性能模式(Maximum Performance)
最高性能正好和最高保护相反,当事务提交时,只要写入到primary的online redo log即可,primary几乎不受影响。然后再把redo同步到standby中,这样就无法保证primary和standby实时同步。这种模式在实际应用中比较常见,毕竟primary不受影响是最重要的,如果出现standby落后primary太多,DBA可以手工介入,在standby端apply redo。
3)最高可用性模式(Maximum Availability)
最高可用性模式介于前两者之间,在正常情况下,它和最高保护模式一样,但一旦standby出现故障,就立即切换成最高性能模式,primary不会shutdown。如果实际应用该模式,得关注一下实时应用时对primary的性能影响。
那么如何配置及修改DG的保护模式呢?首先你要检查以下2点:
1. 主备库的db_unique_name是否唯一?
2. log_archive_config的dg_config属性是否已经包含所有的主备库db_unique_name?
以上2点确认之后,就可以使用LOG_ARCHIVE_DEST_n来配置,下表显示该参数和保护模式的关系:
从上图可以看出,最大保护和最高可用性的配置一模一样(这很正常因为最高可用性在正常情况下就是最大保护):必须使用LGWR进程传输Redo,网络传输模式必须是sync,磁盘写选项AFFIRM,必须配置standby redo log。
而最大性能模式比较灵活,即可以用LGWR,也可以用ARCH进程传输redo,网络即可以sync也可以async,磁盘IO写即可以AFFIRM也可以NOAFFIRM,standby redo log也可有可无(建议有)。
上面所有的参数都确认配置无误之后,就可以用以下语句修改保护模式:
- ALTER DATABASE SET STANDBY DATABASE TO MAXIMIZE {AVAILABILITY | PERFORMANCE | PROTECTION};
修改成功后,可以通过以下语句验证:
- SELECT PROTECTION_MODE FROM V$DATABASE;
二、日志传输
Oracle Data Guard从宏观上来说,主要提供以下两个服务:
1)日志传输:主库把生成的Redo日志传输至备库;
2)日志应用:备库应用从主库传输过来的Redo日志。
1. 日志传输方式
有两种日志传输方式(ARC和LGWR),第一种是采用ARC进程传输日志,其示意图如下:
注:上图来自《大话Oracle RAC》
其大致过程如下:
1)主库:日志先写入在线重做日志,当在线重做日志满后(后人为切换), ARC0进程归档该日志至主库本地归档目录,归档完成后,ARC1马上将该归档日志传输到备库;
2)备库:RFS进程接收日志,如果备库有Standby重做日志,则把日志复制到Standby重做日志,接着把Standby重做日志归档至备库本地归档目录,最后应用归档日志;如果没有配置Standby重做日志,RFS进程接收日志后,直接把它放到备库的归档目录下,再应用该日志。
另外一种是使用LGWR进程传输日志,它和第一种方式有很大的不同,最明显的区别是它不需要等到主库完成日志切换后才能进行日志传输,其示意图如下:
注:上图来自《大话Oracle RAC》
其过程大致如下:
1)主库:只要有新的重做日志产生,LGWR进程将触发LNSn进程把新生成的日志传输到备库(注意:这里不能由LGWR直接传输,因为整个数据库实例只有一个LGWR,为了保证它的主要业务性能不受影响,不能由它直接传输);
2)备库:RFS进程接收到日志后,将其写入Standby重做日志,如果备库开启了实时应用,就立即做日志应用,如果没有开启,则等Standby重做日志归档后再应用。
2.日志发送的配置
SERVICE(必须):指定备库的网络连接名;
SYNC/ASYNC(默认为ASYNC):指定日志的传输模式(同步/异步);
NET_TIMEOUT:指定当采用SYNC传输模式时,超过多少秒则表示网路超时(默认为30s),在使用SNYC模式时,强烈建议设置改参数;
AFFIRM/NOAFFIRM:AFFIRM表示只有当日志写入Standby重做日志后才算日志传输成功,NOAFFIRM则没有这个要求;
DB_UNIQUE_NAME:指定备库的DB_UNIQUE_NAME;
VALID_FOR:格式为(
redo_log_type,
database_role),只有这两个条件全部符合,才会发送日志;
其中redo_log_type有如下取值:
ONLINE_LOGFILE, STANDBY_LOGFILE, ALL_LOGFILES
database_role有如下取值:PRIMARY_ROLE, STANDBY_ROLE, ALL_ROLES
REOPEN:指定当连接错误发生时,多少秒之后重试;
COMPRESSION:指定是否对日志进行压缩,已提高网络传输性能。
下面是log_archive_dest_n的一个例子:
DB_UNIQUE_NAME=BOSTON
LOG_ARCHIVE_CONFIG='DG_CONFIG=(BOSTON,CHICAGO,HARTFORD)'
LOG_ARCHIVE_DEST_2='SERVICE=CHICAGO ASYNC NOAFFIRM VALID_FOR=(ONLINE_LOGFILE,
PRIMARY_ROLE) REOPEN=60 COMPRESSION=ENABLE DB_UNIQUE_NAME=CHICAGO'
LOG_ARCHIVE_DEST_STATE_2='ENABLE'
LOG_ARCHIVE_DEST_3='SERVICE=HARTFORD SYNC AFFIRM NET_TIMEOUT=30
VALID_FOR=(ONLINE_LOGFILE,PRIMARY_ROLE) REOPEN=60 COMPRESSION=ENABLE
DB_UNIQUE_NAME=HARTFORD'
LOG_ARCHIVE_DEST_STATE_3='ENABLE'
3.日志接受的配置
SQL> SELECT GROUP#, BYTES FROM V$LOG;通过下面的语句可以查询备库Standby日志的大小和组数:
SQL> SELECT GROUP#, BYTES FROM V$STANDBY_LOG;假设主库有两组在线日志,每个日志文件大小为500M,那么我们至少需要3组Standby,且每个日志文件大小不少于500M:
SQL> ALTER DATABASE ADD STANDBY LOGFILE ('/oracle/dbs/slog1.rdo') SIZE 500M; SQL> ALTER DATABASE ADD STANDBY LOGFILE ('/oracle/dbs/slog2.rdo') SIZE 500M; SQL> ALTER DATABASE ADD STANDBY LOGFILE ('/oracle/dbs/slog3.rdo') SIZE 500M;
上面提到过,备库的Standby日志也会被归档,它的归档路径由备库的log_archive_dest_n参数的location属性设置,如下所示:
LOG_ARCHIVE_DEST_1 = 'LOCATION = /disk2/archive
VALID_FOR=(STANDBY_LOGFILE,STANDBY_ROLE)'
LOG_ARCHIVE_DEST_STATE_2=ENABLE
4.日志传输状态的监控
第一步:在主库执行如下语句获得最新归档序列号:
SQL> SELECT MAX(SEQUENCE#), THREAD# FROM V$ARCHIVED_LOG GROUP BY THREAD#;
第二步:在主库执行如下语句确认最新归档的日志是否已经传输至备库:
SQL> SELECT DESTINATION, STATUS, ARCHIVED_THREAD#, ARCHIVED_SEQ# FROM V$ARCHIVE_DEST_STATUS WHERE STATUS <> 'DEFERRED' AND STATUS <> 'INACTIVE';
DESTINATION STATUS ARCHIVED_THREAD# ARCHIVED_SEQ#
------------------ ------ ---------------- -------------
/private1/prmy/lad VALID 1 947
standby1 VALID 1 947
如果状态不是VALID,则说明日志传输失败。
5.手动解决日志传输GAP
Oracle DG会自动检测日志传输GAP并自动解决,但有时候GAP无法自动解决,必须DBA人工干预,下面我们讲讲手动解决的步骤:
首先,在备库执行下列语句查询是否有GAP:
SQL> SELECT * FROM V$ARCHIVE_GAP;
THREAD# LOW_SEQUENCE# HIGH_SEQUENCE#
----------- ------------- --------------
1 7 10
HIGH_SEQUENCE#减去LOW_SEQUENCE#就是当前的GAP数,上例显示备库缺少从7到10(不包含10)的归档日志。
接着,在主库查询这些归档日志的目录位置:
SQL> SELECT NAME FROM V$ARCHIVED_LOG WHERE THREAD#=1 AND DEST_ID=1 AND SEQUENCE# BETWEEN 7 AND 10;
NAME
--------------------------------------------------------------------------------
/primary/thread1_dest/arcr_1_7.arc
/primary/thread1_dest/arcr_1_8.arc
/primary/thread1_dest/arcr_1_9.arc
把这些归档日志从主库拷贝至备库,并在备库上注册:
SQL> ALTER DATABASE REGISTER LOGFILE '/physical_standby1/thread1_dest/arcr_1_7.arc';
SQL> ALTER DATABASE REGISTER LOGFILE '/physical_standby1/thread1_dest/arcr_1_8.arc';
SQL> ALTER DATABASE REGISTER LOGFILE '/physical_standby1/thread1_dest/arcr_1_9.arc';
三、日志应用
在上一节,我们介绍了DG的日志传输服务,当日志从主库传输至备库后,备库需要应用日志来保持和主库的同步,本节就来介绍日志应用服务。
Redo应用orSQl应用
我们知道有两种类型的备库,分别是物理备库和逻辑备库,物理备库的日志应用叫做Redo应用,而逻辑备库的日志应用叫做SQL应用。
所谓的Redo应用是指备库采用介质恢复的方式应用主库传输过来的日志,因此物理备库就像是主库的一面镜子,不但数据一样,物理结构(如数据块、数据文件等)都一样,这样的好处是同步速度快。
所谓的SQL应用是指备库通过Log Miner从日志中解析出SQL语句,然后应用这些SQL语句,很显然,SQL应用的性能比不上Redo应用,但它更灵活。逻辑备库采用SQL应用。
实时日志应用
- 物理备库通过以下语句开启实时应用:
- SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE ;
- 逻辑备库通过以下语句开启实时应用:
- SQL> ALTER DATABASE START LOGICAL STANDBYAPPLY IMMEDIATE;
开启/关闭日志应用服务
物理备库:
- --开启
- SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT;
- --关闭
- SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;
逻辑备库:
- --开启
- SQL> ALTER DATABASE START LOGICAL STANDBY APPLY;
- --关闭
- SQL> ALTER DATABASE STOP LOGICAL STANDBY APPLY;
今天需要对一个24*7的生产库创建一个DG的物理备库,要求主库不能停机,一开始以为不可能,后来查了下文档,原来通过rman的duplicate命令可以实现在线创建物理备库。
主备库的信息如下:
角色 db_name db_unique_name 主机 网络连接字符串
主库 jkka jkka lx32 jkkapri
备库 jkka jkka2 lx201 jkkasta
1.主库的准备工作
- SYS@JKKA>select log_mode,force_logging from v$database;
- LOG_MODE FOCE_LOGGING
- ARCHIVELOG NO
- $ orapwd file=$ORACLE_HOME/dbs/orapwjkka
- SYS@JKKA>show parameter remote_login_passwordfile
- NAME TYPE VALUE
- remote_login_passwordfile string EXCLUSIVE
- NAME TYPE VALUE
- db_name string jkka
- SYS@JKKA>show parameter db_unique_name
- NAME TYPE VALUE
- db_unique_name string jkka
- SYS@JKKA>alter system set log_archive_config='DG_CONFIG=(jkka,jkka2)';
- System altered.
- SYS@JKKA>alter system set log_archive_dest_1='location=/data/oradata/jkka/archivelog valid_for=(all_logfiles,all_roles) db_unique_name=jkka';
- System altered.
- SYS@JKKA>alter system set log_archive_dest_state_1=enable;
- System altered.
- SYS@JKKA>alter system set log_archive_dest_state_2=defer;
- System altered.
- SYS@JKKA>alter system set log_archive_dest_2='service=jkkasta ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) db_unique_name=jkka2';
- System altered.
- SYS@JKKA>alter system set fal_server=jkka2;
- System altered.
- SYS@JKKA>alter system set fal_client=jkka;
- System altered.
- SYS@JKKA>alter system set standby_file_management=auto;
- System altered.
- SYS@JKKA>create pfile from spfile;
- File created.
- db_unique_name='jkka2'
- fal_client='JKKA2'
- fal_server='JKKA'
- log_archive_dest_1='location=/data/oradata/jkka/archivelog valid_for=(all_logfiles,all_roles) db_unique_name=jkka2'
- log_archive_dest_2='service=jkkapri ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) db_unique_name=jkka'
- $ export ORACLE_SID=jkka
- $ sqlplus / as sysdba
- SQL>startup nomount
- 主备库的网络设置
- LISTENER =
- (DESCRIPTION_LIST =
- (DESCRIPTION =
- (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
- (ADDRESS = (PROTOCOL = TCP)(HOST = lx32)(PORT = 1521))
- )
- )
- LISTENER =
- (DESCRIPTION_LIST =
- (DESCRIPTION =
- (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
- (ADDRESS = (PROTOCOL = TCP)(HOST = lx201)(PORT = 1521))
- )
- )
- jkkasta =
- (DESCRIPTION =
- (ADDRESS_LIST =
- (ADDRESS = (PROTOCOL = TCP)(HOST =lx201)(PORT = 1521))
- )
- (CONNECT_DATA =
- (sid = jkka)
- )
- )
- jkkapri =
- (DESCRIPTION =
- (ADDRESS = (PROTOCOL = TCP)(HOST =lx32)(PORT = 1521))
- (CONNECT_DATA =
- (SERVER = DEDICATED)
- (sid =jkka)
- )
- )
- 主库:
- $ sqlplus sys@jkkasta as sysdba
- 备库:
- $ sqlplus sys@jkkapri as sysdba
5)复制主库到备库
- $ rman target /
- RMAN> backup full format='/home/oracle/backup/ora_bak/data/db_jkka_%U' database include current controlfile for standby
- plus archivelog format='/home/oracle/backup/ora_bak/data/arc_jkka_%U';
- $ rman target sys/***@jkkapri AUXILIARY /
- RMAN> duplicate target database for standby dorecover nofilenamecheck;
- ORACLE error from auxiliary database: ORA-19527: physical standby redo log must be renamed
- ORA-00312: online log 1 thread 1: '/data/oradata/jkka/data/redoa1.log'
- RMAN-05535: WARNING: All redo log files were not defined properly.
- SYS@JKKA>ALTER DATABASE ADD STANDBY LOGFILE GROUP 10 ('/data/oradata/jkka/data/standby_redo10.log') size 100M
- Database altered.
- SYS@JKKA>ALTER DATABASE ADD STANDBY LOGFILE GROUP 11 ('/data/oradata/jkka/data/standby_redo11.log') size 100M;
- Database altered.
- SYS@JKKA>ALTER DATABASE ADD STANDBY LOGFILE GROUP 12 ('/data/oradata/jkka/data/standby_redo12.log') size 100M;
- Database altered.
- SYS@JKKA>ALTER DATABASE ADD STANDBY LOGFILE GROUP 13 ('/data/oradata/jkka/data/standby_redo13.log') size 100M;
- Database altered.
- SQL>create spfile from pfile;
- File created.
- SQL>shutdown immediate
- SQL>startup
五、重建备库的online redo log
SYS@jkka> alter system set standby_file_management=manual;
System altered. SYS@jkka> alter system set LOG_FILE_NAME_CONVERT='/data/oradata/jkka/data/','/data/oradata/jkka/data/' scope=spfile;
System altered.
shutdown immediate;
startup;
SYS@jkka> alter database clear logfile group 1;
Database altered.
SYS@jkka> alter database clear logfile group 2;
Database altered.
SYS@jkka> alter database clear logfile group 3;
Database altered.
SYS@jkka> alter system reset LOG_FILE_NAME_CONVERT;
System altered.
shutdown immediate;
startup;
SYS@jkka> alter system set standby_file_management=auto;
System altered.
六)备库启动redo apply
System altered.
504 2013-08-22 14:41:54 2013-08-22 20:32:39