目前接触的项目是有对以oracle数据库的服务跨机房灾备/读压力分载这样的需求。从成本、需求等方面考虑,暂定为用oracle企业版免费提供的data guard
(下称DG)操作实现跨机房灾备。
上有业务层的切换这里不做说明,仅说明DG作为灾备的方案如何选择合适的冷备方案。
另外,对于oracle11g版本的DG,可在备份数据的同时提供只读服务。
下面对DG说明它的工作方式,并附上简单部署实例。
提及Oracle数据同步、复制、备份等等这些关键字,其实Oracle本身作为商业型数据库就提供了很多的工具。但是侧重点不同,这里结合查询的资料大概说下,也可以作为实际环境中解决问题时一点参考。
RAC(real application clusters)
:实时应用集群,强项在于解决单点故障和负载均衡,因此RAC方案常用于7*24的核心系统,但RAC方案中的数据只有一份,尽管可以通过RAID等机制可以避免存储故障,但是数据本身是没有冗余的,容易形成单点故障。,比较适合短距离(单机房)内保障应用可用性。
DG
:通过冗余数据来提供数据保护,通过日志同步机制保证冗余数据和主数据之前的同步,这种同步可以是实时,延时,同步,异步多种形式。Data Gurad常用于异地容灾和小企业的高可用性方案. Oracle 11g版本中增强物理Standby的应用功能,在11g版本中,物理Standby可以在OPEN READ ONLY模式下继续应用REDO数据,这就极大地提升了物理Standby数据库的应用场合。+
名词解释:
Primary Database 主库
Standy Database 备库
Redo Log Oracle Redo Log 实时日志
日志就是数据库操作的记录
DG架构按功能可分为3部分:
Primary Database
运行过程中,会源源不断地产生Redo
日志,这些日志需要发送到Standy Database
。
DG支持2种方式发送,一种通过ARCH
进程发送归档日志,一种通过LGWR
发送实时日志。
可以看到都会占用数据库额外的一部分资源完成这项工作。
ARCH
进程这是默认方式,即主库日志归档时通过ARCH进程发送归档日志给备库。基本流程如下:
Primary Database
不断产生Redo Log
,这些日志被LGWR
进程写到联机日志(Log Switch)
并且会触发本地归档,本地归档位置是采用LOG_ARCHIVE_DEST_1='LOCATION=/path'
这种格式定义的ARCH
进程通过Net把归档日志发送给Standby Database
的RFS(Remote File Server)
进程Standby Database
端的RFS
进程把接收的日志写入到归档日志Standby Database
端的MRP(Managed Recovery Process)
进程(Redo Apply)
或者LSP
进程(SQL Apply)
在Standby Database
上应用这些日志,进而同步数据可以看到,Primary Database
只有在发生归档时才会发送日志到Standby Database
,而且不写入备机的重做日志(Standby Redologs)
。所以,如果Primary Database
异常宕机,联机日志中的Redo
内容就会丢失,因此使用ARCH
进程无法避免数据丢失的问题。
要想避免数据丢失,就必须使用LGWR
。
使用LGWR
又分SYNC
(同步)和ASYNC
(异步)两种方式。
同步方式即主库的事务得确认日志写入成功才会提交。它的流程如下:
Primary Database
产生的Redo
日志要同时写到联机日志文件和本地的LNSn
进程(LGWR Network Server Process)
,再由LNSn(LGWR Network Server process)
进程把日志通过网络发送给远程的目的地,每个远程目的地对应一个LNS
进程,多个LNS
进程能够并行工作LGWR
必须等待写入本地日志文件操作和通过LNSn
进程的网络传送都成功,Primary Database
上的事务才能提交,这也是SYNC
的含义所在。Standby Database
的RFS
进程把接收到的日志写入到Standby Redo Log
日志中。Primary Database
的日志切换也会触发Standby Database
上的日志切换,即Standby Database
对Standby RedoLog
的归档,然后触发Standby Database
的MRP
或者LSP
进程恢复归档日志。使用LGWR SYNC方式时,还可以同时使用NET_TIMEOUT参数,这个参数单位是秒,代表如果多长时间内网络发送没有响应,LGWR 进程会抛出错误。示例如下:(抛出错误不意味着失败,可以设置重试发送或者等待下一次归档时再次发送 2)
alter system set log_archive_dest_2 = 'SERVICE=ST LGWR SYNC NET_TIMEOUT=30' scope=both;
Question: 这里主库日志切换是redo日志组满了,备库那边的日志组是什么情况,和主库一样?
如果某次同步挂了,理论上备库的日志组大小要大于主库的日志组文件大小?另外下一次归档发送时主库日志一部分已归档,如何发送?
Reply:备库是用主库生成的standby controlfile建立实例的,日志组和主库一样。如何发送待测试:先停掉备库,主库操作不断归档日志,再开启备库看看同步情况
对于归档失败的处理,LOG_ARCHIVE_DEST_n参数有几个属性,可以用来控制归档过程中出现故障时应该采取的措施。
REOPEN
指定时间后再次尝试归档,默认300s
MAX_FAILURE
控制失败尝试次数
LOG_ARCHIVE_DEST_1='LOCATION=E:/ora10g/oradata/jsspdg/ REOPEN=100 MAX_FAILURE=3'
ALTERNATE
指定替补的归档目的地
LOG_ARCHIVE_DEST_1='LOCATION=/disk1 ALTERNATE=LOG_ARCHIVE_DEST_2'
// REOPEN优先级更高,先重试再替补
显然同步方式受网络影响,而且比较影响主库性能。超时时间设置也要考虑网络延迟的影响。不过同步方式能有效的保证数据准确性。
异步方式不要求网络日志写入成功,基本流程如下:
Primary Database
一段产生Redo
日志后,LGWR
把日志同时提交给日志文件和本地LNS
进程,但是LGWR
进程只需成功写入日志文件就可以,不必等待LNSn
进程的网络传送成功LNSn
进程异步地把日志内容发送到Standby Database
。多个LNSn
进程可以并发发送Primary Database
的Online Redo Log
写满后发生Log Switch
触发归档操作,也触发Standby Database
对Standby Redo Log
的归档;然后触发MRP
或者LSP
进程恢复归档日志Standby Database
的RFS(Remote File Server)
进程接收到日志后,就把日志写到Standby Redo Log
或者Archived Log
文件中。具体写入哪个文件,取决于Primary
的日志传送方式和Standby database
的位置。
日志应用服务,就是在Standby Database
上重演Primary Database
日志,从而实现两个数据库的数据同步。
根据Standby Database
重演日志方式的不同,可分为物理Standby(Physical Standby)
和逻辑Standby(Logical Standby)
。
根据Redo Apply
发生的时间可以分成两种: 实时应用(Real-Time Apply)
和归档时应用。
物理Standby:
接收完Primary数据库生成的REDO数据后,以介质恢复的方式实现同步,这种方式也叫Redo Apply。没有数据类型的限制,可以保证两个数据库完全一致。只能在Mount 状态下进行恢复,11g版本后可以以同时只读方式打开。
逻辑Standby:
接收后将其转换成SQL语句,在Standby数据库上执行SQL语句实现同步,这种方式叫SQL Apply。不支持所有数据类型,可以在视图DBA_LOGSTDBY_UNSUPPORTED 中查看不支持的数据类型,如果使用了这种数据类型,则不能保证数据库完全一致。可以在恢复的同时进行读写操作。
创建
逻辑Standby
数据库要先创建一个物理Standby
数据库,然后再将其转换成逻辑Standb
y数据库。Physical DG转换Logical DG
实时应用(Real-Time Apply),:
这种方式必须Standby Redo Log,每当日志被写入Standby Redo Log时,就会触发恢复,使用这种方式的好处在与可以减少数据库切换(Switchover 或者Failover)的时间,因为切换时间主要用在剩余日志的恢复上。
归档时应用:
这种方式在Primary Database发生日志切换,触发Standby Database 归档操作,归档完成后触发恢复。 这也是默认的恢复方式。
-- Physical Standby启用Real-Time:
Alter database recover managed standby database using current logfile;
-- Logical Standby启用Real-Time:
Alter database start logical standby apply immediate;
-- 查看是否使用Real-Time apply:
Select recovery_mode from v$archive_dest_status;
某些情况下你可能不希望Standby
数据库与Primary
太过同步,那就可以在Primary数据库端发送REDO数据的相应LOG_ARCHIVE_DEST_n
参数中指定DELAY属性(单位为分钟,如果指定了DELAY属性,但没有指定值,则默认是30分钟)。
ALTER SYSTEM SET LOG_ARCHIVE_DEST_3='SERVICE=DavePrimary ARCH VALID_ FOR=
(ONLINE_LOGFILES, PRIMARY_ROLE) DB_UNIQUE_NAME=Dave DELAY=15';
-- 物理Standby可以通过下列语句取消延迟应用:
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE NODELAY;
-- 逻辑Standby可以通过下列语句取消延迟应用:
ALTER DATABASE START LOGICAL STANDBY APPLY NODELAY;
Data Guard 允许定义3钟数据保护模式:
要求所有的事务在提交前其REDO不仅被写入到本地的Online Redologs
,还要同时写入到Standby
数据库的Standby Redologs
,并确认REDO
数据至少在一个Standby数据库中可用(如果有多个的话),然后才会在Primary
数据库上提交。如果出现了什么故障导致Standby数据库不可用的话(比如网络中断),Primary
数据库会被Shutdown,以防止数据丢失。
可以看到,必须有一个备库同步成功,主库事务才提交。如果只有一个备库,是完全保证主备库数据一致的。
结合前面我们知道这种方式也就是使用LGWR
线程同步发送并且AFFIRM
。
与最大保护模式类似,也是要求本地事务在提交前必须至少写入一台Standby数据库的Standby Redologs中,不过与最大保护模式不同的是,如果出现故障导致Standby数据库无法访问,Primary数据库并不会被Shutdown,而是自动转为最高性能模式,等Standby数据库恢复正常之后,Primary数据库又会自动转换成最高可用性模式。
结合前面我们知道这种方式也是使用LGWR线程同步发送并且AFFIRM
3。
Question: 这里怎么设置的?和最大保护如何区别,如果不设置超时时间,怎么判定备库不可用,而此时主库如何做?设置超时时间也是类似,超时是shutdown还是commit?
参见[设置保护模式](#3.2.4 设置保护模式)
默认方式,归档方式或异步方式发送日志,事务的提交不依赖于网络日志的写入 4。
可以LGWR ASYNC
或者ARCH
。
Question:这里事务提交会确认本地日志写成功吗?应该是的,否则就很容易出问题
上面的疑问可以取消了,数据库有参数设置的。
关闭数据库,重启到Mount 状态,如果是RAC,需要关闭所有实例,然后只启动一个实例到mount状态。
修改模式:
-- {PROTECTION | AVAILABILITY | PERFORMANCE}
ALTER DATABASE SET STANDBY DATABASE TO MAXIMIZE PERFORMANCE;
打开数据库: alter database open;
确认修改数据保护模式
select protection_mode,protection_level from v$database;
当Primary Database
的某些日志没有成功发送到Standby Database
,这时候发生了归档裂缝(Archive Gap)
。缺失的日志就是Gap。
Data Guard能够自动检测,解决归档裂缝,不需要DBA的介入。这需要备库配置FAL_CLIENT
,FAL_SERVER
这两个参数。
FAL_CLIENT
和FAL_SERVER
两个参数都是Oracle Net Name
。FAL_CLIENT
通过网络向FAL_SERVER
发送请求,FAL_SERVER
通过网络向FAL_CLIENT
发送缺失的日志。FAL_CLIENT
向FAL_SERVER
发送请求时,会携带FAL_CLIENT
参数值,用来告诉FAL_SERVER
应该向哪里发送缺少的日志。 这个参数值也是一个Oracle Net Name,这个Name是在FAL_SERVER
上定义的,用来指向FAL_CLIENT
.
查看是否有日志GAP:
SELECT UNIQUE THREAD#, MAX(SEQUENCE#) OVER(PARTITION BY THREAD#) LAST FROM V$ARCHIVED_LOG;
SELECT THREAD#, LOW_SEQUENCE#, HIGH_SEQUENCE# FROM V$ARCHIVE_GAP;
如果有,则拷贝过来
手工的注册这些日志:
ALTER DATABASE REGISTER LOGFILE '路径';
LOG_ARCHIVE_DEST_n参数中的VALID_FOR属性,用来指定传输的内容,该属性有两个参数值需要指定:REDO_LOG_TYPE和DATABASE_ROLE。该参数的主要目的是为了确保,一旦发生角色切换操作后数据库的正常运转。
REDO_LOG_TYPE:
ONLINE_LOGFILE、STANDBY_LOGFILE、ALL_LOGFILES。
DATABASE_ROLE:
PRIMARY_ROLE、STANDBY_ROLE、ALL_ROLES。
DB_UNIQUE_NAME作用是指定唯一的Oracle数据库名称,保证REDO数据在传输过程中才能确认传输到DBA希望被传输到的数据库上。
要确保REDO数据被传输到指定服务器,除了在LOG_ARCHIVE_DEST_n参数中指定正确DB_UNIQUE_NAME属性之外,还有一个初始化参数LOG_ARCHIVE_CONFIG也需要进行正确的配置。该参数除了指定Data Guard环境中的唯一数据库名外,还包括几个属性,用来控制REDO数据的传输和接收:
-- SEND:允许数据库发送数据到远端。
-- RECEIVE:允许Standby接收来自其他数据库的数据。
-- NOSEND,NORECEIVE:自然就是禁止喽。
LOG_ARCHIVE_CONFIG='NORECEIVE,DG_CONFIG= (PRI,ST) '
Oracle 11gR2 DG部署(RMAN方式)
本机使用docker完成实例,后面尽可能复现些异常情况。
借助与docker容器占用轻量资源以及容器间暴露的端口默认互通,数据库之间的网络是连通的。
这里把整个操作流程总结下。
hostname | ip | db_name | db_unique_name | net service name |
---|---|---|---|---|
db1 | 172.17.0.2 | orcl | primary | orcl |
db2 | 172.17.0.3 | orcl | standby | orcl |
docker pull registry.cn-hangzhou.aliyuncs.com/jydsun/oracle11g_ssg:1.04
登陆账号:root/install oracle/install
实例密码:sys/oracle
其实都用不着,在docker里直接获取到root权限,切换oracle用户就有sysdba权限
# primary
docker run -d --name db1 -p 15211:1521 -v /mnt/hgfs/E/Workspace/Database/Oracle/data/db1:/data/oracle_data -e oracle_allow_remote=true registry.cn-hangzhou.aliyuncs.com/jydsun/oracle11g_ssg:1.04
# standby
docker run -d --name db2 -p 15212:1521 -v /mnt/hgfs/E/Workspace/Database/Oracle/data/db2:/data/oracle_data -e oracle_allow_remote=true registry.cn-hangzhou.aliyuncs.com/jydsun/oracle11g_ssg:1.04
另外了解到oracle对dg也是有个管理工具DG_Broker的,可以帮助dba快速部署dg,这里给个链接了解下 DG_Broker配置。
以下是手工部署的过程,使用broker更简单点,但其实最终也是帮助生成以下过程中的参数设置等等,所以这里展示下手工的全过程,帮助了解每个细节点。(其实是之前根本不知道db_broker,后来才知道有这玩意,不然我也想先用broker啊…后面再补充个文档吧,o(╥﹏╥)o)
--干净的关闭数据库
SQL> shutdown immediate
--以mount模式启动
SQL> startup mount
--切换到归档模式
SQL> alter database archivelog;
--开启强制日志
SQL> alter database force logging;
--打开数据库
SQL> alter database open;
--查看归档
SQL> archive log list;
--查看是否为强制日志
SQL> select force_logging from v$database;
Standby Redo Log
--查看Redo和Standby Redo
SQL> select * from v$logfile;
--仅仅显示Online Redo,不显示Standby Redo
SQL> select * from v$log;
--新增一组大小为500M的Standby Redo,这里的group号不得与Online redo重复,大小和online redo 一样,每个实例Standby Redo数量比online redo 多一个
SQL> alter database add standby logfile group 21 '/u01/app/oracle/oradata/orcl/standby21.log' size 500M;
SQL> alter database add standby logfile group 22 '/u01/app/oracle/oradata/orcl/standby22.log' size 500M;
SQL> alter database add standby logfile group 23 '/u01/app/oracle/oradata/orcl/standby23.log' size 500M;
SQL> alter database add standby logfile group 24 '/u01/app/oracle/oradata/orcl/standby24.log' size 500M;
-- 创建pfile,默认保存在$ORACLE_HOME/dbs/initorcl.ora,也可以指定路径pfile='/path'
SQL> create pfile from spfile;
-- 修改主库初始化参数,在pfile后面追加
*.db_unique_name='primary'
*.service_names='orcl'
*.fal_client='primary'
*.fal_server='standby'
*.log_archive_config='DG_CONFIG=(primary,standby)'
*.log_archive_dest_1='location=/data/oracle_data/dataguard/log valid_for=(all_logfiles,all_roles) db_unique_name=primary'
*.log_archive_dest_2='service=standby lgwr async valid_for=(online_logfiles,primary_role) db_unique_name=standby'
*.log_archive_dest_state_1='enable'
*.log_archive_dest_state_2='enable'
*.log_archive_format='%t_%s_%r.dbf'
*.DB_FILE_NAME_CONVERT='/opt/oracle/app/oradata/orcl','/opt/oracle/app/oradata/orcl'
*.LOG_FILE_NAME_CONVERT='/data/oracle_data/dataguard/log','/data/oracle_data/dataguard/log'
*.standby_file_management='auto'
-- 创建新的spfile并重启
SQL> shutdown immediate
SQL> create spfile from pfile;
SQL> startup
下列参数为Primary角色相关的初始化参数
DB_NAME 注意保持同一个Data Guard中所有数据库DB_NAME相同 例如:DB_NAME=Dave DB_UNIQUE_NAME 为每一个数据库指定一个唯一的名称,该参数一经指定不会再发生变化,除非DBA主动修改它 例如:DB_UNIQUE_NAME=DavePre LOG_ARCHIVE_CONFIG 该参数用来控制从远端数据库接收或发送REDO数据,通过DG_CONFIG属性罗列同一个Data Guard中所有DB_UNIQUE_NAME(含Primary数据库和Standby数据库),以逗号分隔,SEND/NOSEND属性控制是否可以发送,RECEIVE/NORECEIVE属性控制是否能够接收 例如:LOG_ARCHIVE_CONFIG=‘DG_CONFIG=(DavePre,DaveDG)’ LOG_ARCHIVE_DEST_n 归档文件的生成路径。该参数非常重要,并且属性和子参数也特别多(可以直接查询Oracle官方文档。Data Guard白皮书第14章专门介绍了该参数各属性及子参数的功能和设置)。例如: LOG_ARCHIVE_DEST_1=‘LOCATION=l:/oracle/oradata/Dave VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=DavePre’ LOG_ARCHIVE_DEST_STATE_n 是否允许REDO传输服务传输REDO数据到指定的路径。该参数共拥有4个属性值,功能各不相同。 REMOTE_LOGIN_PASSWORDFILE 推荐设置参数值为EXCLUSIVE或者SHARED,注意保证相同Data Guard配置中所有DB服务器SYS密码相同
以下参数为与Standby角色相关的参数(建议在Primary数据库的初始化参数中也进行设置,这样即使发 生角色切换,新的Standby也能直接正常运行)
FAL_SERVER 指定一个Net服务名,该参数值对应的数据库应为Primary角色。当本地数据库为Standby角色时,如果发现存在归档中断的情况,该参数用来指定获取中断的归档文件的服务器 例如:FAL_SERVER=DavePre 提示:FAL是Fetch Archived Log的缩写 FAL_SERVER参数支持多个参数值的哟,相互间以逗号分隔 FAL_CLIENT 又指定一个Net服务名,该参数对应数据库应为Standby角色。当本地数据库以Primary角色运行时,向参数值中指定的站点发送中断的归档文件 例如:FAL_CLIENT=DaveDG FAL_CLIENT参数也支持多个参数值,相互间以逗号分隔。 DB_FILE_NAME_CONVERT Standby数据库的数据文件路径与Primary数据库数据文件路径不一致时,可以通过设置DB_FILE_NAME_CONVERT参数的方式让其自动转换。该参数值应该成对出现,前面的值表示转换前的形式,后面的值表示转换后的形式 例如:DB_FILE_NAME_CONVERT=‘f:/oradata/DavePre’,‘l:/oradata/DaveDG’ LOG_FILE_NAME_CONVERT 使用方式与上相同,只不过LOG_FILE_NAME_CONVERT专用来转换日志文件路径 例如: LOG_FILE_NAME_CONVERT=‘f:/oradata/DavePre’,‘l:/oradata/DaveDG’ STANDBY_FILE_MANAGEMENT 如果Primary数据库数据文件发生修改(如新建、重命名等)则按照本参数的设置在Standby数据库中作相应修改。设为AUTO表示自动管理。设为MANUAL表示需要手工管理 例如:STANDBY_FILE_MANAGEMENT=AUTO
注意细节:
- ORACLE_HOME 最后不要/
- listener.ora 的sid_name和tnsnames.ora sid_name一样
太难受了…
# 修改listener.ora /app/product/11.2.0/dbhome_1/network/admin/listener.ora,
# listener.ora Network Configuration File: C:\app\Administrator\product\11.2.0\dbhome_1\network\admin\listener.ora
# Generated by Oracle configuration tools.
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(SID_NAME = orcl)
(ORACLE_HOME = /opt/oracle/app/product/11.2.0/dbhome_1)
)
)
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 172.17.0.2)(PORT = 1521))
)
)
ADR_BASE_LISTENER = /opt/oracle/app/admin
# tnsnames.ora 增加primary和standby
# tnsnames.ora Network Configuration File: C:\app\Administrator\product\11.2.0\dbhome_1\network\admin\tnsnames.ora
# Generated by Oracle configuration tools.
ORACLR_CONNECTION_DATA =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
)
(CONNECT_DATA =
(SID = CLRExtProc)
(PRESENTATION = RO)
)
)
ORCL =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 172.17.0.2)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = orcl)
)
)
#primary
PRIMARY =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 172.17.0.2)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = orcl)
)
)
#standby
STANDBY=
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 172.17.0.3)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = orcl)
)
)
# 重启监听服务
lsnrctl stop
lsnrctl start
- 将主库oracle目录下的admin,cfgtollogs,diag,flash_recover_area目录拷贝到备用库的相同路径
- 将主库oracle目录下的oradata文件夹下内容复制到从库相同目录下 。
- 将主库生成的密码文件拷贝到从库相同路径下
- 将D:\app\interlib拷贝到备库相同路径
- 将standby.ctl文件拷贝到备库的数据文件夹内(D:\app\Administrator\oradata\orcl\)和D:\app\Administrator\flash_recovery_area\orcl\下。在两个路径下将文件复制为control01.ctl,control02.ctl,control03.ctl。
- 将主库的listener.ora和tnsname.ora拷贝到备库相同路径 。
- 主库和备库创建D:\app\interlib\tmp文件夹。
注:通过rman先恢复时可以只创建文件夹,standby controlfile可以不用创建
我这里因为是docker直接创建的容器实例,所以这些东西都有了,问题不大
# 复制主库密码到备库(sys用户密码设置一致)
cd /u01/app/oracle/product/11.2.0/dbhome_1/dbs/
scp orapworcl db2:/u01/app/oracle/product/11.2.0/dbhome_1/dbs/
# 复制pfile
cd /u01/app/oracle/product/11.2.0/dbhome_1/dbs/
scp initorcl.ora db2:/u01/app/oracle/product/11.2.0/dbhome_1/dbs/
# 复制监听文件listener.ora和tnsnames.ora
cd /u01/app/oracle/product/11.2.0/dbhome_1/network/admin/
scp listener.ora db2:/u01/app/oracle/product/11.2.0/dbhome_1/network/admin/
cd /u01/app/oracle/product/11.2.0/dbhome_1/network/admin/
scp tnsnames.ora db2:/u01/app/oracle/product/11.2.0/dbhome_1/network/admin/
# 备库新建实例
oradim -new -sid orcl
# 主库创建密码
# orapwd file=$ORACLE_HOME/dbs/orapworcl password=oracle entries=10 ignorecase=Y
# 这里用db1,db2应该要配hosts的,应该可以用ip替代
# 这里测试时用docker映射在主机上,所以直接在windows下操作日志文件部分的复制
-- 修改备库初始化参数
*.db_unique_name='standby'
*.service_names='orcl'
*.fal_client='standby'
*.fal_server='primary'
*.log_archive_config='DG_CONFIG=(primary,standby)'
*.log_archive_dest_1='location=/data/oracle_data/dataguard/log valid_for=(all_logfiles,all_roles) db_unique_name=standby'
*.log_archive_dest_2='service=primary lgwr async valid_for=(online_logfiles,primary_role) db_unique_name=primary'
*.log_archive_dest_state_1='enable'
*.log_archive_dest_state_2='enable'
*.log_archive_format='%t_%s_%r.dbf'
*.DB_FILE_NAME_CONVERT='/opt/oracle/app/oradata/orcl','/opt/oracle/app/oradata/orcl'
*.LOG_FILE_NAME_CONVERT='/data/oracle_data/dataguard/log','/data/oracle_data/dataguard/log'
*.standby_file_management='auto'
使用oracle用户,(复制文件夹)
mkdir -p /u01/app/oracle/oradata/orcl/
mkdir -p /u01/app/oracle/admin/orcl/adump/
mkdir -p /u01/app/oracle/fast_recovery_area/orcl/
# 还包括和主库一样的归档日志文件夹等
修改备库listener.ora和tnsnames.ora
# 验证监听
tnsping primary
tnsping standby
sqlplus sys/oracle@primary as sysdba
-- 创建备库spfile
SQL> create spfile from pfile;
-- nomount挂载
SQL> startup nomount;
DG是日志的同步,在开启归档之前的数据还是要全量备份到备库上。可以用impdp逻辑备份,也可以rman物理备份。(以前用expdp/impdp比较多,也可以通过数据库连接远程备份,对rman其实还不怎么了解,了解一下)
# 在备库执行,连接目标库和辅助数据库
rman target sys/oracle@primary auxiliary sys/oracle@standby
# 恢复数据文件,standby控制文件,standby日志组
RMAN> duplicate target database for standby from active database nofilenamecheck;
# 注意如果没有用rman,控制文件要手动建的,在主库创建standby controlfile,并复制为备库启动的controlfile
# alter database create standby controlfile as '/data/oracle_data/dataguard/standby.ctl';
# scp /data/oracle_data/dataguard/standby.ctl db2:/data/oracle_data/dataguard/standby.ctl
# cp /data/oracle_data/dataguard/standby.ctl /opt/oracle/app/oradata/orcl/control01.ctl
# cp /data/oracle_data/dataguard/standby.ctl /opt/oracle/app/flash_recovery_areduplicate target database for standby from active database nofilenamecheck;a/orcl/control02.ctl
复制成功后,备库自动被加载为mount模式,进入sqlplus查看
-- 查看备库实例状态
SQL> select status from v$instance;
-- 开启备库只读(oracle 11g:adg) alter database open read only
SQL> alter database open;
-- 后台实时日志应用
SQL> alter database recover managed standby database using current logfile disconnect from session;
-- 从库也可以直接startup,会默认mount为从库和open为只读
-- 查看主备库状态
SQL> select database_role,protection_mode,protection_level,open_mode from v$database;
-- 查看dg日志
SQL> select * from v$dataguard_status;
select * from (select a.*,rownum rn from v$dataguard_status a order by timestamp desc) where rn=1;
-- 查看dg:process
SQL> select process,client_process,sequence#,status from v$managed_standby;
主库执行:
SQL> archive log list;
SQL> alter system switch logfile;
SQL> archive log list;
备库查看:
SQL> archive log list;
主库执行:
-- 表空间
SQL> create tablespace testtablespace datafile '/home/oracle/ora_dbf/testkts.dbf' size 2m autoextend off;
-- 用户
SQL> create user testuser identified by 1 default tablespace testtablespace;
SQL> grant resource,connect to testuser;
-- 表
SQL> create table testuser.testtable ( id number(30), name varchar2(20) );
-- 索引
SQL> create index testindex on testuser.testtable(id);
-- 数据
SQL> insert into testuser.testtable(id,name) values(1,'first record');
SQL> commit;
-- 切换日志
SQL> alter system switch logfile;
-- 查看备库
SQL> select * from testuser.testtable;
ID NAME
---------- --------------------
1 first record
主要做dg的正常及异常测试,然后关注主库的发送日志(备库接收)和备库的应用日志
测试案例:
-- 表空间
SQL> create tablespace testtablespace datafile '/home/oracle/ora_dbf/testkts.dbf' size 2m autoextend off;
-- 用户
SQL> create user testuser identified by 1 default tablespace testtablespace;
SQL> grant resource,connect to testuser;
-- 表
SQL> create table testuser.testtable ( id number(30), name varchar2(20) );
-- 索引
SQL> create index testindex on testuser.testtable(id);
-- 数据
SQL> insert into testuser.testtable(id,name) values(1,'first record');
SQL> commit;
-- 切换日志
SQL> alter system switch logfile;
-- 查看备库
SQL> select * from testuser.testtable;
ID NAME
---------- --------------------
1 first record
结论:备库监听停掉对同步数据无影响。但是备库无法被应用连接
操作:
分析:主库发送日志通过参数log_archive_dest_2设置service=standby,这个standby应该是主库配置的tns里的。但是备库的tns挂掉没影响主库发送数据,同样不影响备库接收和应用数据。
这里在用tnsping standby 是报错无监听的,但是还是发过去了,可能是有缓存?
重启了主库,备库没有正常同步和应用。查看v$dataguard_status,连接standby出错了,应该还是有缓存。先这样吧…不去追究缓存多久啥啥啥的了==
重启备库监听,重启主库,备库自动同步ok
-- 初始状态
-- 主库
SQL> select * from testuser.testtable;
ID NAME
---------- --------------------
1 first record
1 first record
1 first record
-- 备库
SQL> select * from testuser.testtable;
ID NAME
---------- --------------------
1 first record
1 first record
1 first record
# 备库停止监听
[oracle@babc3aa59656 ~]$ lsnrctl stop
LSNRCTL for Linux: Version 11.2.0.1.0 - Production on 12-MAY-2020 10:44:23
Copyright (c) 1991, 2009, Oracle. All rights reserved.
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=172.17.0.3)(PORT=1521)))
The command completed successfully
# 主库查看监听
[oracle@c368a7303eee ~]$ tnsping standby
TNS Ping Utility for Linux: Version 11.2.0.1.0 - Production on 12-MAY-2020 10:44:36
Copyright (c) 1997, 2009, Oracle. All rights reserved.
Used parameter files:
Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 172.17.0.3)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = orcl)))
TNS-12541: TNS:no listener
-- 主库操作dml
SQL> drop table testuser.testtable;
Table dropped.
-- 备库查询
SQL> select * from testuser.testtable;
select * from testuser.testtable
*
ERROR at line 1:
ORA-00942: table or view does not exist
结论:主库日志正常保存的情况下,备库数据库关闭/宕机/网络异常等不影响。备库正常时,会比较两边的日志,具有一定的自动修复gap能力。(需要配置fal_server
)
操作:
分析:数据库会记录已归档日志,主备库会通过类似比较日志记录号来确认日志是否备份OK,对于备库日志确缺失的时候(归档日志或实时日志),在设置fal_server
参数情况下,备库具有一定自动修复gap的能力,会从主库下载缺少的日志文件并应用。
-- 关闭备库
SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
-- 主库dml操作,并切换日志
SQL> insert into testuser.testtable(id,name) values(1,'first record');
1 row created.
SQL> commit;
Commit complete.
SQL> alter system switch logfile;
System altered.
-- 切换日志,主库归档一条,备库日志文件夹没变化,查看主库dataguard_status,可以看到主库往备库standby写日志写挂了
-- 重启备库
SQL> startup
ORACLE instance started.
Total System Global Area 521936896 bytes
Fixed Size 2214936 bytes
Variable Size 251659240 bytes
Database Buffers 260046848 bytes
Redo Buffers 8015872 bytes
Database mounted.
Database opened.
-- 备份数据
SQL> alter database recover managed standby database using current logfile disconnect from session;
Database altered.
SQL> select * from testuser.testtable;
ID NAME
---------- --------------------
1 first record
1 first record
1 first record
SQL>
-- 这里看到备库从主库下载了中间差的几条日志,说明dg是有自动修复gap的能力的,会从主库下载有差异的日志文件。
-- 这里比较显然的如果主库的归档文件丢了,就自动修复不了了,需要人工处理,后面看看怎么人工处理?归档文件都丢了...
-- 用rman增量更新应该是可行的?
同[2.2 备库数据库关闭](#2.2 备库数据库关闭),主库正常,备库有一定的自动修复能力。
同[2.2 备库数据库关闭](#2.2 备库数据库关闭),主库正常,备库有一定的自动修复能力。
同[2.2 备库数据库关闭](#2.2 备库数据库关闭),主库正常,备库有一定的自动修复能力。
这里需要注意的是,日志=归档日志+实时日志。对于归档日志可以通过archive log list
查看已归档日志的序号,具体的归档日志文件dbf我们姑且认为记录了这种序号(大概是scn什么的…),所以增量归档是在已归档基础上继续备份新的文件并重置序号。通常也是比较archive log对比主备库是否一致。
所以删除备库之前的文件也没啥用因为已经归档过了,删除之后的文件也就和宕机一直没下载一样,如果是没应用的日志,还是会自动修复gap重新从主库下载。
首先应该明确都是tns挂了=应用连接数据库挂了。这时候其实主库正常来说也是不会再产生有效的应用日志了。
问题不是很大,修复正常应该就可以了。
备库tns的时候已经测试了,数据库启动时应该是缓存了有效的tns的,所以单纯的tns挂掉不影响什么
个人认为这时候通常更多可能是先看看主库是不是能快速正常启动,实在over的情况会切换到备库。
这里的高可用首选应该还是RAC,要么真的是机房宕机,停电等,切换第二机房备库。
主备库切换详见后文
这里应该认为是发送到备库网络异常
如果主库网络本身异常,通常来说和主库数据库关闭、宕机类似的,应用连接会异常。可以认为主库已经挂掉了。这时候是考虑修复主库或者切换备库吧
发送到备库异常同[2.3 备库网络异常未接收/应用](#2.3 备库网络异常未接收/应用),也没啥影响
参见 [2.7 主库数据库关闭](#2.7 主库数据库关闭)
这个还是比较麻烦的,描述的是备库日志没有而且主库日志也缺失,正常应该也不会出现这种情况:
其实考虑这个就是基于日志清理考虑的,日志是占硬盘的,不可能一直存着。
如果实实在在出现这个情况,只能手工处理,在后面异常情况描述。
日志压缩当然还是能开启就开启的好。
保护模式可设置lgwr async, 尽量实时发送日志,async保证一定性能
这个是11g的新特性,说是adg的部分,要花钱的,配置方式如下:(LOG_ARCHIVE_DEST_N
增加COMPRESSION=ENABLE
)
LOG_ARCHIVE_DEST_2='SERVICE=CHICAGO ASYNC NOAFFIRM VALID_FOR=(ONLINE_LOGFILE, PRIMARY_ROLE) REOPEN=60 COMPRESSION=ENABLE DB_UNIQUE_NAME=CHICAGO'
这个大概要用一些网络测试工具才能搞出来,傻傻的比较了下日志文件,然后发现大小一样,暂时先放弃了
查了下,有一些dba也有一些测试文档,资料不是很多,我们就科普一下。
另外我觉得这个如果是实时日志的话可能会导致整体较慢,但是单次性能看不出效果来,实时日志数据量太小了。发送归档文件大概能看出来。整体较慢感觉更体现在一直占用网络和io吧
归档文件的疑惑:备库的standby日志组和主库的standby组是一样的,如果备库的standby组一个在写的日志文件快满的时候,主库挂了,这时候备库的standby redo log怎么办?这里应该和主库处理一样,那主库怎么处理?嗯…都记录了日志只是没有归档,应该问题不大,主库的standby redo log 和 备库的standby redo log一直保持一样就可以了
我们已经知道dg有3中保护模式,最高可用、最大可用都要求日志必须写到备库。
这里想了解的是:
为什么要了解这个,因为最高可用和最大可用都要求要写到备库,从日志参数来说必须lgwr sync affirm,但这个日志参数不确定是哪种保护模式。
测了一下,日志
LOG_ARCHIVE_DEST_n
会影响保护模式,两者相互制约的。强行设了最大保护,参数用arch,数据库起不来,查看alert日志报错如下:LGWR: Primary database is in MAXIMUM PROTECTION mode LGWR: Destination LOG_ARCHIVE_DEST_2 is not serviced by LGWR
另外查询资料说,数据库可以在open模式下从最大性能先升级到最高可用再升级到最大保护,不能直接升级。是使用默认的参数可以这样?目测如果一样设置了比如lgwr async 可能启动最高可用也是有问题的
-- 修改参数
-- *.log_archive_dest_2='service=standby arch async valid_for=(online_logfiles,primary_role) compression=enable db_unique_name=standby'
-- 创建spfile
-- SQL> create spfile from pfile='/data/oracle_data/dataguard/initora.ora';
-- 主库设置最大保护
-- shutdown
SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
-- startup mount
SQL> startup mount;
ORACLE instance started.
Total System Global Area 521936896 bytes
Fixed Size 2214936 bytes
Variable Size 251659240 bytes
Database Buffers 260046848 bytes
Redo Buffers 8015872 bytes
Database mounted.
-- alter
SQL> ALTER DATABASE SET STANDBY DATABASE TO MAXIMIZE PROTECTION;
ALTER DATABASE SET STANDBY DATABASE TO MAXIMIZE PROTECTION
Database altered.
-- open
SQL> alter database open; -- 这里应该open不起来了或者上面alter就alter不了,我不是按这个步骤来的结果是一样的
主备库的切换不复杂,但应该结合实际情况,考虑:
切换也应该考虑开始设置的主库和备库的参数是否合适,比如路径,服务等等(开始的参数其实就是全量参数,包含primary和standby的设置)
----查看主库状态
SQL> select OPEN_MODE,PROTECTION_MODE,PROTECTION_LEVEL,SWITCHOVER_STATUS from v$database;
OPEN_MODE PROTECTION_MODE PROTECTION_LEVEL
-------------------- -------------------- --------------------
SWITCHOVER_STATUS
--------------------
READ WRITE MAXIMUM PERFORMANCE MAXIMUM PERFORMANCE
TO STANDBY
----进行切换
SQL> alter database commit to switchover to physical standby;
Database altered.
SQL> shutdown immediate;
ORA-01507: database not mounted
ORACLE instance shut down.
SQL> startup
ORACLE instance started.
Total System Global Area 521936896 bytes
Fixed Size 2214936 bytes
Variable Size 251659240 bytes
Database Buffers 260046848 bytes
Redo Buffers 8015872 bytes
Database mounted.
Database opened.
SQL> alter database recover managed standby database using current logfile disconnect from session;
Database altered.
-- 查看备库状态
SQL> select OPEN_MODE,PROTECTION_MODE,PROTECTION_LEVEL,SWITCHOVER_STATUS from v$database;
OPEN_MODE PROTECTION_MODE PROTECTION_LEVEL
-------------------- -------------------- --------------------
SWITCHOVER_STATUS
--------------------
READ ONLY MAXIMUM PERFORMANCE MAXIMUM PERFORMANCE
TO PRIMARY
SQL> alter database commit to switchover to primary;
Database altered.
SQL> shutdown immediate;
ORA-01109: database not open
Database dismounted.
ORACLE instance shut down.
SQL> startup
ORACLE instance started.
Total System Global Area 521936896 bytes
Fixed Size 2214936 bytes
Variable Size 251659240 bytes
Database Buffers 260046848 bytes
Redo Buffers 8015872 bytes
Database mounted.
Database opened.
宕机就宕机吧…问题不大
见 [2.2 备库数据库关闭](2.2 备库数据库关闭)
先看看需不需要切换备库,切换备库如下
-- 前提:关闭主库
alter database recover managed standby database finish;
-- 备库切换主库
SQL> alter database recover managed standby database finish;
Database altered.
SQL> alter database commit to switchover to primary;
Database altered.
SQL> shutdown immediate;
ORA-01109: database not open
Database dismounted.
ORACLE instance shut down.
SQL> startup;
ORACLE instance started.
Total System Global Area 521936896 bytes
Fixed Size 2214936 bytes
Variable Size 251659240 bytes
Database Buffers 260046848 bytes
Redo Buffers 8015872 bytes
Database mounted.
Database opened.
-- 主库重启(状态出问题了,也做不了从库)
SQL> startup
ORACLE instance started.
Total System Global Area 521936896 bytes
Fixed Size 2214936 bytes
Variable Size 251659240 bytes
Database Buffers 260046848 bytes
Redo Buffers 8015872 bytes
Database mounted.
Database opened.
SQL> select OPEN_MODE,PROTECTION_MODE,PROTECTION_LEVEL,SWITCHOVER_STATUS from v$database;
OPEN_MODE PROTECTION_MODE PROTECTION_LEVEL
-------------------- -------------------- --------------------
SWITCHOVER_STATUS
--------------------
READ WRITE MAXIMUM PERFORMANCE MAXIMUM PERFORMANCE
FAILED DESTINATION
SQL> shutdown immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> alter database commit to switchover to physical standby;
alter database commit to switchover to physical standby
*
ERROR at line 1:
ORA-01034: ORACLE not available
Process ID: 589
Session ID: 1144 Serial number: 5
SQL> startup mount standby database;
SP2-0714: invalid combination of STARTUP options
SQL> startup nomount;
ORACLE instance started.
Total System Global Area 521936896 bytes
Fixed Size 2214936 bytes
Variable Size 251659240 bytes
Database Buffers 260046848 bytes
Redo Buffers 8015872 bytes
SQL> alter database mount standby database;
alter database mount standby database
*
ERROR at line 1:
ORA-01665: control file is not a standby control file
-- 这里做不了从库了,重新复制standby controlfile过来替换就能做备库,暂时没看到其他的方法
gap:就是主库和备库差异的地方
之前说了主库日志完整的情况下, 备库是可以自动修复gap的。只能手工的话,基本就是主库日志也GG了。
参考:Dataguard gap修复
要通过SCM的增量备份修复GAP
Oracle Data Guard 的配置方法,请参考下面的文档:
tip:链接过去可以看看很多oracle的特性和文档…
但是我们也不是oracle的dba啊,假装知道就好了
关于Active Data Guard的最佳实践经验,请参考文档:
Data Guard 日志传输参数:
dataguard 日志传输服务(参数解析)
12g版本及以前,lgwr是单进程;12c以后可以多进程 ↩︎
Question: 这里主库日志切换是redo日志组满了,备库那边的日志组是什么情况,和主库一样? ↩︎
Question: 这里怎么设置的?和最大保护如何区别,如果不设置超时时间,怎么判定备库不可用,而此时主库如何做?设置超时时间也是类似,超时是shutdown还是commit? ↩︎
Question:这里事务提交会确认本地日志写成功吗?应该是的,否则就很容易出问题 ↩︎