前面已经手动一个个敲
Oracle
参数部署了dg的测试环境,当然生产上的情况要复杂的多,我们尽可能多摸摸底。今天主要划分以下任务:
- dg管理工具broker的使用
- broker和手工dg的对比
- 性能压力测试
broker是oracle自带的dg管理工具,可以帮助dba快速部署dg,这里做以了解。
select sum(table_rows) from information_schema.tables where table_schema = 'test_schema' ;
select table_name,sum(table_rows)sr from information_schema.tables where table_schema = 'test_schema' GROUP BY table_name order by sr desc
-- 想了下,测试不需要这样的铺底数据,而是实时同步的情况,所以不需要,我们写个小demo并发插数据就好了
-- 20200521 又想了一下
-- 数据量还是会影响性能的,排除其他因素不考虑(如存储等),delete,update这种还是会受索引数据量的影响,可能会使备库应用慢一下
方便起见,后面我们重新搭起来测试环境后,直接用Navicat同步一下(O(∩_∩)O哈哈~,Navicat也是逻辑同步嘛)
1. broker简介1
Data Guard broker
是建立在Data Guard
基础上的一个对Data Guard
配置,集中管理操作的一个平台。Data Guard
为我们提供了一套高可用的解决方案,但是在实际的使用方面确实显得有一些过于复杂,特别是在需要配置的standby机器多的时候更是如此,一个个机器去登陆配置显得特别的麻烦;在需要做switchover或者是failover的时候情况也是一样,需要操作一系列的命令才能完成一次switchover/failover的操作(同时也应该认识这种操作一般很少除非比如机房挂了这种比较严重的主库起不来的)。Data Guard broker
的推出就是为了简化DG复杂的管理过程的,它最大的作用就是集中化的统一管理,下面列出来一些Data Guard broker优势所在:
使用broker | 不使用broker | |
---|---|---|
一般 | 将primary数据库与全部standby数据库看成一个整体进行管理 | 必须对primary数据库和各个standby进行单独的操作。 |
创建standby | 通过使用OEM可以轻松的建立一个新的standby | 所有操作必须手工进行:拷贝数据/控制/日志文件,设置初始化参数等等 |
配置和管理 | 可以在一个地方对所有的数据库进行统一的配置和管理,这些配置会被自动同步到各个数据库中 | 必须手工的进行配置,然后对Primary和standby进行单独的管理 |
控制 | - 使用一个简单的命令进行failover和switchover的操作 - 通过配置可以自动的进行failover操作 | - 必须使用多个SQLPLUS才能完成对数据库的管理 |
监控 | - 自动持续对数据库配置,数据库状态以及其他参数进行自动管理 - 提供详细的数据库状态报告 - 和OEM Events集成 | - 没有统一的视图进行管理,只能通过Fixed View一个个进行查看 – 自定义OEM Events管理 |
1.1 broker组成
broker的组成主要分成两大部分,分别是:
1.1.1 客户端组件
客户端组件是一个管理员与broker服务器端组件的接口,用户通过客户端来发出命令对服务器端的行为进行控制。客户端组件由OEM
和DGMGRL
两个组成
-
OEM
2(Oracle Enterprise Manager
):图形化的Oracle管理工具,提供了多个向导功能方便DG的管理工作。 -
DGMGRL
(Data Guard command-line interface
): 命令行管理界面,可以通过命令很方便的操作以及监控数据库,命令列表见文档。1.1.2 服务器端组件
在每个配置了broker的数据库上面都存在一个服务器进程进行broker的管理操作,这个服务器进程就是Data Guard broker monitor(DMON)
,而这个DMON
所用到的所有配置信息都会保留在一个配置文件中。这个DMON进程和配置文件就构成了每个数据库上broker的服务器端组件
Data guard broker monitor process(DMON)
:DMON是一个用来管理broker的后台进程,这个进程负责与本地数据库以及远程数据库的DMON进程进行通讯(与远端数据库的DMON进程进行通讯的时候使用的是一个 动态注册 的service name “db_unique_name_DGB.db_domain”)。这个进程负责维护配置文件的正确性以及不同数据库之间配置文件的一致性。在第一次创建一个broker配置文件或者是将一个数据库加入一个现存的broker配置中的时候DMON会先收集现有数据库的DG配置信息并保存到配置文件中。- 配置文件:配置文件有DMON进行操作,它保存了broker管理的所有的数据库的状态信息,以及数据库相关属性(即数据库的初始化参数信息)的信息。同一个broker配置管理下的每个数据库上面都有一份相同的配置文件。
1.2 配置管理
Broker通过将DG环境划分成数据库配置和数据库这两种对象来简化DG的管理工作。
- 数据库配置对象:数据库配置是一个包含多个数据库信息的集合,这些数据库信息包括数据库对象当前的形态、状态、及属性设置。同时这个集合可以同时混合了物理standby和逻辑standby。
- 数据库对象:数据库对象指的是Primary和standby数据库。一般情况下一个数据库对象只包含一个实例,但是在RAC系统中一个数据库对象会包含多个实例。
broker通过将一个DG中的Primary数据库及所有的standby数据库逻辑的组成一个逻辑组来进行集中管理,因此每个broker配置就是一个数据库的逻辑集合,它包含了组成数据库的日志传输服务、日志应用服务等逻辑的对象。DBA可以broker来控制这个逻辑集合的配置,改变它的配置,同时还能监控这个组的整体健康状态。
DMON进程负责设置和维护broker配置,有了DMON的维护之后在实际管理中我们只需要把一个broker配置当初单个的单元管理就行了,剩下的工作由DMON去做,因此当执行一个影响到多个数据库的命令的时候,DMON实际上会进行下面的操作:
- 在Primary数据库上处理请求。
- 协调其他相关数据库上的DMON进程处理相应的请求。
- 更新本地系统中的配置文件。
- 与其他数据库上的DMON进程通讯以更新各自的配置文件。
每组配置文件中可以包含多个broker配置,但是每个数据库只会维护一组配置文件,因此在RAC环境中,配置文件是由组成这个RAC的各个instance共享的。DMON进程负责各个数据库之间配置文件的同步工作。
DMON进程通过配置文件中设定的数据库的参数来控制数据库的行为,这些属性通常都和数据库的某个DG相关的初始化参数相关联,在通过OEM或DGMGRL修改这些属性的时候,这些属性记录会先保存在配置文件中,然后DMON进程同时也会对相关数据库的参数进行修改,这就要求我们在配置数据库的时候必须使用SPFILE,保证DMON修改之后的参数能保留下来。
2. 使用broker搭建dg环境
环境:
hostname | ip | db_name | db_unique_name | net service name |
---|---|---|---|---|
db3 | 172.17.0.4 | orcl | primary | orcl |
db4 | 172.17.0.5 | orcl | standby | orcl |
2.0 启动数据库
# primary
docker run -d --name db3 -p 15213:1521 -p 223:22 -p 11583:1158 -v /mnt/hgfs/E/Workspace/Database/Oracle/data/db3:/data/oracle_data -e oracle_allow_remote=true registry.cn-hangzhou.aliyuncs.com/jydsun/oracle11g_ssg:1.04
# standby
docker run -d --name db4 -p 15214:1521 -p 224:22 -p 11584:1158 -v /mnt/hgfs/E/Workspace/Database/Oracle/data/db4:/data/oracle_data -e oracle_allow_remote=true registry.cn-hangzhou.aliyuncs.com/jydsun/oracle11g_ssg:1.04
因为镜像的原因,我这里挂载映射了本地路径,来存放数据文件,减少虚拟机空间。后面dg搭建好后,测试数据要新建个表空间存储。
2.1 broker配置
2.1.0 预先设置
后面发现有些东西还是要先设置好的…
2.1.0.1 主库开启日志
-- 开启日志
SQL> shutdown immediate
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 log,日志文件可以设置大点500m
--查看Redo和Standby Redo
SQL> select * from v$logfile;
SQL> select * from v$log;
SQL> alter database add standby logfile group 21 '/opt/oracle/app/oradata/orcl/standby21.log' size 50M;
SQL> alter database add standby logfile group 22 '/opt/oracle/app/oradata/orcl/standby22.log' size 50M;
SQL> alter database add standby logfile group 23 '/opt/oracle/app/oradata/orcl/standby23.log' size 50M;
SQL> alter database add standby logfile group 24 '/opt/oracle/app/oradata/orcl/standby24.log' size 50M;
2.1.0.2 生成standby controlfile
简直要哭了呀…
还是要用主库生成的standby controlfile来启动备库才行,好多人都没说明这些,他们是真的在已经部署好的dg上搞的嘛
用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
-- 查下备库状态,已经是physical standby了
SQL> select database_role,protection_mode,protection_level,open_mode from v$database;
2.1.1 主库启用broker3
-- 查看dg_broker_start参数设置
SQL> show parameter dg_broker_start;
-- 启用dg_broker_start,启用后oracle会自动启动一个dmon进程
SQL> alter system set dg_broker_start = true;
-- 默认broker配置文件位置
SQL> show parameter dg_broker_config_file;
2.1.2 主库配置listener.ora和tnsnames.ora
broker里面的连接的service_name默认是
<db_unique_name>_DGMGRL
,所以需要增加一个监听给broker用。不配置也可以用命令指定
DGMGRL>edit database db1 set property StaticConnectIdentifier= '(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=beijing-fuli-hadoop-01)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=db1)(INSTANCE_NAME=db1)(SERVER=DEDICATED)))';
太坑了,broker不能帮助我们自动调整db_unique_name,还是要自己先设置每个库的
db_unique_name
,保证区分。-- 主库db3: SQL> alter system set db_unique_name='primary' scope=spfile; -- 备库db4: SQL> alter system set db_unique_name='standby' scope=spfile; -- 而且这玩意需要重启库才能生效
# 切换监听文件目录
cd /opt/oracle/app/product/11.2.0/dbhome_1/network/admin/
# 配置listener.ora
vi 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 =
(GLOBAL_DBNAME = orcl)
(SID_NAME = orcl)
(ORACLE_HOME = /opt/oracle/app/product/11.2.0/dbhome_1)
)
(SID_DESC =
(GLOBAL_DBNAME = primary_DGMGRL)
(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(和手工一样)
vi tnsnames.ora
# 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 reload
2.1.3 备库启用broker和配置listener.ora&tnsnames.ora
同主库操作
哇,这不一样好麻烦,痛苦死了
2.1.4 主库创建broker配置文件
# 登陆dgmgrl控制台,primary是在tns配置的
[oracle@f77ebb7cf0da admin]$ dgmgrl sys/oracle@primary
# 创建配置文件,第一个primary是db_unique_name,第二个primary是tnsname
DGMGRL> CREATE CONFIGURATION dgconf01 AS PRIMARY DATABASE IS primary CONNECT IDENTIFIER IS primary;
# 配置有问题就
# DGMGRL> remove configuration;
这里我备份了一下spfile
SQL> create pfile='/data/oracle_data/pfile_after_create_config.ora' from spfile;
看到这时候因为前面设了db_unique_name,就多了这么一个参数
# 添加备库
DGMGRL> add database standby as connect identifier is standby maintained as physical;
这里报了个错,
Error: ORA-16831: operation disallowed on this standby database type Failed.
目测可能是standby日志什么的没开,哎,前面补一下。
然后发现有的参考是这么写的
在配置DG broker之前需要确保Dataguard配置正常且主库和备库均使用spfile.
我都蒙了,都配好了还要broker干啥,方便拓展操作么
哭了呀,弄好了日志也不是,仔细瞅了下,应该是备库不能创建为standby databse,我是直接startup的所以不行,然后停掉尝试mount standby database,然后还不行,controlfile不对,不是standby controlfile…
555~
standby controlfile可以在主库创建复制过来,也可以使用rman同步。索性我们先假装有主库,得先rman同步一次吧
rman完备库是physical standby状态
好了成功了继续吧…555~
# 启用配置
DGMGRL> ENABLE CONFIGURATION;
# 查看下
DGMGRL> show configuration;
再备份下spfile看看
SQL> create pfile='/data/oracle_data/pfile_after_enable_config.ora' from spfile;
对比下多了以下的参数配置:
# 主库增加以下配置 *.archive_lag_target=0 *.log_archive_config='dg_config=(primary,standby)' *.log_archive_dest_1='location=USE_DB_RECOVERY_FILE_DEST','valid_for=(ALL_LOGFILES, ALL_ROLES)' *.log_archive_dest_2='service="standby"','LGWR ASYNC NOAFFIRM delay=0 optional compression=disable max_failure=0 max_connections=1 reopen=300 db_unique_name="standby" net_timeout=30','valid_for=(all_logfiles,primary_role)' orcl.log_archive_format='%t_%s_%r.dbf' *.log_archive_max_processes=4 *.log_archive_min_succeed_dest=1 orcl.log_archive_trace=0 *.standby_file_management='MANUAL' # 备库增加以下配置 *.archive_lag_target=0 *.fal_server='primary' *.log_archive_config='dg_config=(standby,primary)' *.log_archive_dest_1='location=USE_DB_RECOVERY_FILE_DEST','valid_for=(ALL_LOGFILES, ALL_ROLES)' orcl.log_archive_format='%t_%s_%r.dbf' *.log_archive_max_processes=4 *.log_archive_min_succeed_dest=1 orcl.log_archive_trace=0 *.standby_file_management='MANUAL'
基本还是比较优秀的?对比手工的参数
*.db_unique_name='primary' *.archive_lag_target=1800 *.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=primary' *.log_archive_dest_2='service=standby lgwr async noaffirm valid_for=(online_logfiles,primary_role) compression=enable 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'
可以看出来
这个单纯的是主备库设置,我们之前手工设置还存在主备切换后的配置
*.standby_file_management
是MANUAL
手动的,一般还是设置AUTO
,可以自动备份表空间等变化归档日志使用了默认的
USE_DB_RECOVERY_FILE_DEST
,要注意日志不清理就会爆满了,之前是手工设置了日志保留位置SQL> show parameter db_recovery_file_dest SQL> show parameter db_recovery_file_dest NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ db_recovery_file_dest string /opt/oracle/app/flash_recovery _area db_recovery_file_dest_size big integer 3882M
log_archive_dest_state_1
这个参数没有自动生成,目测默认是enable
*.DB_FILE_NAME_CONVERT
,*.LOG_FILE_NAME_CONVERT
这个也不会自动生成,这是肯定的,但是我们自己要清楚,这是用来设置路径转换的,主备库路径不一样时需要转换的
2.3 broker管理dg
回想了下,漏了用broker设置保护模式,日志发送方式这些。额有兴趣自己了解下…
2.3.1 管理数据库
- 操作数据库
# 在primary登陆dgmgrl控制台
dgmgrl sys/oracle
# 启动数据库
DGMGRL> enable database primary;
DGMGRL> enable database standby;
# 瞅下数据库状态,都是success
DGMGRL> show database verbose primary;
DGMGRL> show database verbose standby;
# 设置standby database 只读
DGMGRL> edit database standby set state='read-only';
# 将主库离线:
DGMGRL> edit database orcl set state='offline';
DGMGRL> edit database orcl set state='online';
- 设置数据库参数
broker相当于提供了自己的语法,而且一旦用了broker,就不能用sqlplus来管理。(即用比如用broker修改参数,通过sqlplus查看可以看到参数被修改;但是用sqlplus修改参数,broker却没有同步修改。可以类似认为broker缓存了一份配置,它的管理是在它的缓存操作并通知数据库同步,但是数据库变了它反而不知道)
设置*.standby_file_management
DGMGRL> show database verbose primary StandbyFileManagement;
DGMGRL> edit database primary set property StandbyFileManagement='auto';
2.3.2 管理dg
-
管理
primary database
发送日志DGMGRL> edit database primary set state='transport-off'; DGMGRL> edit database primary set state='transport-on';
-
管理
standby database
应用日志# 停止应用 DGMGRL> edit database standby set state="APPLY-OFF"; # 启用应用 DGMGRL> edit database standby set state="APPLY-ON";
-
管理配置和备库
# 禁用配置 disable configuration # 删除配置 remove configuration # 禁用某个备用库 disable database 'standby'; # 从配置中删除备用库 remove database 'standby'
2.3.3 主备切换
这里单独从管理dg里拿出来了
2.3.3.1 Switchover
Swithchover通常都是人为的有计划的进行角色互换,比如升级等。它通常都是无损的,即不会有数据丢失。其执行主要分为两个阶段:
-
Primary转为Standby
-
Standby之一转为Primary
# 切换备库为主库
DGMGRL> switchover to standby;
# 启动下主备库
DGMGRL> enable database primary;
DGMGRL> enable database standby;
# 查看配置
DGMGRL> show configuration;
到这里忽然就有点香了,手工切换主备库…虽然也就2行命令,总怕哪里搞的不对(其实也不会了,搞清楚就很从容,手工更稳定点没错的),好了这里我们切换成功了,再看一下spfile是不是参数也互换了?
SQL> create pfile='/data/oracle_data/pfile_after_switchover_config.ora' from spfile;
配置文件有所变化:
# 主库变化 *.fal_server='standby' *.log_archive_dest_2='' *.log_archive_dest_state_2='ENABLE' # 备库变化 *.log_archive_dest_2='service="primary"','LGWR ASYNC NOAFFIRM delay=0 optional compression=disable max_failure=0 max_connections=1 reopen=300 db_unique_name="primary" net_timeout=30','valid_for=(all_logfiles,primary_role)' *.log_archive_dest_state_2='ENABLE'
可以看到
- 主库切换为备库后,增加了备库的参数
- 备库切换为主库后,增加了主库的参数
log_archive_dest_state
这个是用来控制主库日志是否输出的,看上去还是需要的,第一次主库没有自动生成估计是哪里出了小问题吧…完美,我们先切换回来做些测试。
2.3.3.2 failover
Failover是指由于Primary故障无法短时间恢复,Standby不得不充当Primay的角色,如果处于最高性能模式,这种切换很有可能导致数据丢失。
此时,主库不可用,登陆备库failover。一般这时候需要重建dg,极其痛苦。(要么rman增量备份?)
# 登陆备库failover
DGMGRL> failover to standby;
# 查看dg配置 备库已切换为主库,主库disable
DGMGRL> show configuration;
# 假装主库又起来了,先让它变备库同步这段时间的数据
# 一般这时候需要重建dg,极其痛苦
# 另外了解到如果主备库开启了闪回flashback,只要主库闪回到failover之前,就能用broker自动重建
# flashback还是开着的好,它的大小也会决定能会退的数据,如果短时间大量dml语句,基本就崩了很难回去,但是可以参考手工修复用scn,rman啥的修复?往下不继续测试了,了解下...
DGMGRL> reinstate database primary;
# 再切换主库回来
# 切换备库为主库
DGMGRL> switchover to primary;
# 启动下主备库
DGMGRL> enable database standby;
DGMGRL> enable database primary;
# 查看配置
DGMGRL> show configuration;
2.3.3.3 备库宕机
问题不大,和手工方式类似,手工方式需要重启并手工再开启应用。使用broker不用,备库启动后会自动应用日志。
2.4 扩展总结
无论手工还是broker,我们假设已有dg环境下扩展备库(以broker说明):
- 主库修改tnsname.ora,增加新备库tns
- 新备库启用broker
- 新备库同步主库为standby database(controlfile等)
- broker configuration增加新备库
- 在线调整参数
看上去扩展的时候主库不需要离线
3. 压力测试
因为上面测failover把主库搞挂了,用rman增量备份又麻烦,还好现在没啥数据,直接重新用rman全备到db3/primary,然后再切换主备库。
# db3同步db4
rman target sys/oracle@standby auxiliary sys/oracle@primary
# 恢复数据文件,standby控制文件,standby日志组
RMAN> duplicate target database for standby from active database nofilenamecheck;
# 登陆db4,启用primary
dgmgrl sys/oracle@standby
# 启用primary
DGMGRL> enable database primary;
# 查看状态,已经正常了
DGMGRL> show configuration;
# switchover切换
DGMGRL> switchover to primary;
好了,我们的环境又回来了
3.1 新增表空间
一方面新增表空间,datafile映射到主机上,另一方面,这不也可以再次验证dg吗。
首先得调下参数
DGMGRL> edit database primary set property StandbyFileManagement='auto';
DGMGRL> edit database standby set property StandbyFileManagement='auto';
# 还要注意,归档日志在DB_RECOVERY_FILE_DEST,这个大小不够,我们测试调大点不清理
开启闪回
# 备库关闭实时应用日志
SQL> sALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;
# 关闭dg
DGMGRL> disable configuration;
# 主备库开启闪回
SQL> select flashback_on from V$database;
SQL> ALTER SYSTEM SET UNDO_RETENTION=3600;
SQL> ALTER SYSTEM SET DB_FLASHBACK_RETENTION_TARGET=4320;
SQL> alter database flashback on;
SQL> ALTER SYSTEM SET db_recovery_file_dest_size=100G;
# 开启dg
DGMGRL> enable configuration
# 备库开启实时应用日志
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE using current logfile disconnect from session ;
主库表空间操作
SQL> create tablespace test datafile '/data/oracle_data/test_01.dbf' size 30m autoextend on next 128m maxsize 30G ;
SQL> create user test identified by 1 default tablespace test;
SQL> grant connect,resource to test;
备库开启只读
SQL> alter database open;
# 查一下
SQL> select default_tablespace from dba_users where username='TEST';
好的都没啥问题
3.2 并发写入
-- 表
SQL> create table test.test ( id number(30), name varchar2(20) );
写了一个小demo,并发1000线程往数据库写10000条数据,写完去查备库
其实跟1条我觉得差不多,并发是增加了数据库的压力,会反映慢一点。但是一个事务日志完成,就会去写日志到备库,更多的还是在网络延迟上
这里还是没有比较好的效果,1是数据造的简单,本身不大(但是又能有多大呢是吧?),2是在本机网络没啥延迟。其实我觉得还是看应用吧,写不多的情况,等等能看到效果问题不大。(话说现在好多app就连支付宝都会有问题,从理财转到银行卡,理财的金额还在显示,短暂的显示问题不大,而且这边也是做读库,看错了再刷一下说不定就好了)
package com.example;
import com.alibaba.druid.pool.DruidDataSource;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.*;
import java.time.Instant;
import java.util.Properties;
import java.util.concurrent.*;
/**
* @author theskyzero
* @create 2020/5/15 下午4:43
*/
public class Test {
public static void main(String[] args) throws IOException, InterruptedException {
DruidDataSource source = dataSource();
TimeUnit unit;
BlockingQueue workQueue;
ThreadPoolExecutor threadPoolExecutor = threadPoolExecutor();
String sql = new String("insert into test(id,name) values(?,?)");
final int count = 10000;
CountDownLatch latch = new CountDownLatch(count);
Instant begin = Instant.now();
for (int i = 0; i < count; i++) {
threadPoolExecutor.execute(new T1EveryConn(latch, source));
}
latch.await();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:15213:orcl", "test", "1");
PreparedStatement pst = connection.prepareStatement("select count(1) ct from test");
ResultSet resultSet = pst.executeQuery();
if (resultSet.next()){
System.out.println(resultSet.getInt("ct"));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
});
thread.join();
thread.start();
Instant end = Instant.now();
System.out.println(end.toEpochMilli()-begin.toEpochMilli());
System.out.println(begin);
System.out.println(end);
}
public static ThreadPoolExecutor threadPoolExecutor() {
final int corePoolSize = 10;
final int maximumPoolSize = 100;
long keepAliveTime = 0;
BlockingQueue workQueue = new LinkedBlockingQueue<>(10);
return new ThreadPoolExecutor(
corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue, new ThreadPoolExecutor.CallerRunsPolicy()
);
}
public static DruidDataSource dataSource() throws IOException {
DruidDataSource source = new DruidDataSource();
source.configFromPropety(dataSourceProperties());
return source;
}
public static Properties dataSourceProperties() throws IOException {
final String fileName = "druid.properties";
Properties properties = new Properties();
properties.load(Test.class.getResourceAsStream(fileName));
return properties;
}
static class T1EveryConn implements Runnable{
CountDownLatch latch;
DataSource source;
private static String sql = new String("insert into test(id,name) values(?,?)");
T1EveryConn(CountDownLatch latch, DataSource source){
this.latch = latch;
this.source = source;
}
@Override
public void run() {
Connection connection = null;
PreparedStatement pst = null;
try {
connection = source.getConnection();
pst = connection.prepareStatement(sql);
int finalI = 1;
pst.setInt(1, finalI);
pst.setString(2, finalI + "");
pst.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (null != pst) {
try {
pst.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
latch.countDown();
}
}
}
static class T2OneConn implements Runnable{
CountDownLatch latch;
DataSource source;
private static String sql = new String("insert into test(id,name) values(?,?)");
T2OneConn(CountDownLatch latch, DataSource source){
this.latch = latch;
this.source = source;
}
@Override
public void run() {
Connection connection = null;
PreparedStatement pst = null;
try {
connection = source.getConnection();
pst = connection.prepareStatement(sql);
int finalI = 1;
pst.setInt(1, finalI);
pst.setString(2, finalI + "");
pst.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (null != pst) {
try {
pst.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
latch.countDown();
}
}
}
}
# druid.properties
druid.db-type=com.alibaba.druid.pool.DruidDataSource
druid.driverClassName=oracle.jdbc.OracleDriver
druid.url=jdbc:oracle:thin:@localhost:15213:orcl
druid.username=test
druid.password=1
druid.initialSize=3
druid.minIdle=3
druid.maxActive=10000
druid.maxWait=5000