关于Oracle数据恢复的两个临界点(r5笔记第42天)
有的网友对我之前写的一篇技术博文中的描述提出了疑问,http://blog.itpub.net/23718752/viewspace-1436965/
其中的主要意思是:oracle中采用了undo+redo机制来作为数据恢复的基石,数据的恢复是通过前后台结合来实现的,在缓存级别,通过dbwr,能够把修改后的数据块刷入数据文件,这是一个异步的过程,不会因为发生数据变更就马上写入数据文件,同时存在log buffer,能够通过log buffer生成redo日志,最后通过lgwr把这部分变更刷到redo 日志,在这个过程中lgwr负责了保持数据完整性的任务,保证了数据不会丢失。
这句话再浓缩一下就是Oracle能够保证对于commit操作的数据都能够成功恢复。
今天可以通过两个特殊的场景来解释一下。
场景1:模拟Oracle ACID的异常情况,事务已经提交,但是redo log buffer还没有写到磁盘
第一个场景就是把lgwr写入redo的操作影响放大,操作时间延长。这个可以参考Jonathan Lewis的博客。https://jonathanlewis.wordpress.com/2011/08/19/redo-2/
这个场景被称为模拟Oracle ACID的异常情况,事务已经提交,但是redo log buffer还没有写到磁盘.我们来看看再下结论。
window #1: --打开一个窗口1,然后创建一个临时表t1
create table t1(n1 number);
insert into t1 values(1);
commit;
然后通过v$process查到对应的LGWR pid
n1@TEST11G> select v$process.pid from v$process where pname='LGWR';
PID
----------
11
window #2 --打开窗口2,开启oradebug,绑定到lgwr上
sys@TEST11G> oradebug setorapid 11
Oracle pid: 11, Unix process pid: 11767, image: oracle@oel1 (LGWR)
sys@TEST11G>oradebug suspend
Statement processed.
window #1--然后回到窗口1,做一个dml操作,commit
n1@TEST11G> update t1 set n1 = 2;
1 row updated.
n1@TEST11G> commit;
这个时候commit操作会一直hang在那儿
window #3 --开启第3个窗口,然后查看是否更新后的值已经可以成功查看。
sys@TEST11G> select count(*)from n1.t1;
COUNT(*)
----------
2
1 row selected.
这个时候我们马上做类似断电的场景,shutdown abort
sys@TEST11G> shutdown abort
ORACLE instance shut down.
这个时候如果观察第一个窗口,会发现下面的错误,可以得知对应的session已经被强制释放了。
n1@TEST11G> commit;
ERROR:
ORA-03114: not connected to ORACLE
commit
*
ERROR at line 1:
ORA-03113: end-of-file on communication channel
Process ID: 15180
Session ID: 125 Serial number: 84
然后我们重启数据库
idle> startup
ORACLE instance started.
Total System Global Area 435224576 bytes
Fixed Size 1337044 bytes
Variable Size 272632108 bytes
Database Buffers 155189248 bytes
Redo Buffers 6066176 bytes
Database mounted.
Database opened.
这个时候再查看数据,就会发现更新后的值已经丢失了。
idle> select *from n1.t1;
N1
----------
1
1 row selected.
对于这个问题,网上大家也是各有所见,有的说commit没有成功返回,就不算是一个完整的事务,没有恢复是可以理解的。有的说,这个是Oracle对于数据恢复的一个灰色地带。
我的意见是首先这是一个测试,把整个过程放慢,影响放大了,整个过程处于一个快要提交但是还没有提交的边界。这部分内容还是没有写入redo中的。只是从缓存中完成了整个数据变更的过程。
commit在这个放慢的临界点没有完成,严格意义上应该不属于一个完整的事务。
上面这个案例是通过debug的方式来做的,我们来用另外一个场景来模拟一下,看看实际中可能碰到的场景如果出现类似问题,redo是否依旧可靠。
场景2:模拟Oracle 归档满的临界点,事务是否依然能够成功提交,成功恢复
我们来模拟在归档日志满的时候,无法再写入redo,依旧可以成功commit,但是数据是否能够成功恢复的案例。
我们在测试环境简单模拟一下归档满的临界点,查看磁盘空间,归档所在的挂载点还有6G的可用空间。
[ora11g@oel1 archivelog]$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda3 30G 23G 6.0G 79% /u02
none 690M 104K 690M 1% /var/lib/xenstored
我们来使用dd来创建一些dummy文件。
[ora11g@oel1 archivelog]$ time dd if=/dev/zero bs=1M count=5000 of=direct_5000M
5000+0 records in
5000+0 records out
5242880000 bytes (5.2 GB) copied, 224.21 seconds, 23.4 MB/s
real 3m44.222s
user 0m0.024s
sys 0m20.317s
创建后再逐步缩小范围。
[ora11g@oel1 archivelog]$ time dd if=/dev/zero bs=1M count=1000 of=direct_1000M
[ora11g@oel1 archivelog]$ time dd if=/dev/zero bs=1M count=100 of=direct_100M
最后发现空间都被占用完了。
[ora11g@oel1 archivelog]$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda3 30G 29G 0 100% /u02
直到没有空间可用我们才收手。
[ora11g@oel1 archivelog]$ time dd if=/dev/zero bs=1M count=10 of=direct_10M
dd: writing `direct_10M': No space left on device
1+0 records in
0+0 records out
0 bytes (0 B) copied, 0.000909 seconds, 0.0 kB/s
最后生成的dd文件如下:
-rw-r----- 1 ora11g dba 33485824 May 20 15:30 1_4_879784710.dbf
-rw-r--r-- 1 ora11g dba 5242880000 May 20 15:36 direct_5000M
-rw-r--r-- 1 ora11g dba 1048576000 May 20 15:37 direct_1000M
-rw-r--r-- 1 ora11g dba 104603648 May 20 15:38 direct_100M
-rw-r--r-- 1 ora11g dba 0 May 20 15:39 direct_10M
使用sqlplus报出下面的错误,这样我们就可以开始这个临界点的测试了。
sys@TEST11G> conn n1/n1
ERROR:
ORA-00257: archiver error. Connect internal only, until freed.
sys@TEST11G> create table aa as select *from cat;
Table created.
sys@TEST11G> insert into aa select *from aa;
4856 rows created.
sys@TEST11G> commit;
Commit complete.
sys@TEST11G> insert into aa select *from aa;
9712 rows created.
sys@TEST11G> commit;
Commit complete.
sys@TEST11G> select count(*)from aa;
COUNT(*)
----------
19424
可以看到这个过程中还是能够成功commit数据的。查取更新都可以使用顺利完成。
可以再开一个窗口运行alter system switch logfile做几个日志刷新。发现这个时候日志刷新也hang住了。
看看alert日志,发现已经提示空间不够,无法生成归档日志了。
Wed May 20 15:43:59 2015
Errors in file /u02/ora11g/diag/rdbms/test11g/TEST11G/trace/TEST11G_arc1_13247.trc:
ORA-19504: failed to create file "/u02/ora11g/flash_recovery_area/TEST11G/archivelog/1_5_879784710.dbf"
ORA-27044: unable to write the header block of file
Linux Error: 28: No space left on device
Additional information: 3
ARC1: Error 19504 Creating archive log file to '/u02/ora11g/flash_recovery_area/TEST11G/archivelog/1_5_879784710.dbf'
ARCH: Archival stopped, error occurred. Will continue retrying
Non critical error ORA-00001 caught while writing to trace file "/u02/ora11g/diag/rdbms/test11g/TEST11G/trace/TEST11G_arc1_13247.trc"
Error message:
Writing to the above trace file is disabled for now on...
ORACLE Instance TEST11G -
这个时候我们继续模拟一个断电场景shutdown abort.
原有的日志刷新也会自动终止。
ERROR:
ORA-03114: not connected to ORACLE
alter system switch logfile
*
ERROR at line 1:
ORA-03113: end-of-file on communication channel
Process ID: 9686
Session ID: 125 Serial number: 480
如果这个时候启动到open阶段就会自动停止,原因就是归档空间的问题。
我们做一个小改动。腾出一小部分空间来。
[ora11g@oel1 archivelog]$ rm direct_100M
然后再次尝试启动数据库就没有问题了
idle> alter database open;
Database altered.
这个时候查看归档路径下,会发现已经生成了3个归档文档
-rw-r--r-- 1 ora11g dba 5242880000 May 20 15:36 direct_5000M
-rw-r--r-- 1 ora11g dba 1048576000 May 20 15:37 direct_1000M
-rw-r--r-- 1 ora11g dba 0 May 20 15:39 direct_10M
-rw-r----- 1 ora11g dba 2048 May 20 15:55 1_6_879784710.dbf
-rw-r----- 1 ora11g dba 204800 May 20 15:55 1_5_879784710.dbf
-rw-r----- 1 ora11g dba 1808384 May 20 15:55 1_7_879784710.dbf
这个时候发现对于这些信息变更已经成功刷新到了归档中。这样就为数据恢复提供了强有力的基石,保证了数据在commit成功的情况下能够成功恢复。
- SpringMVC【校验器、统一处理异常、RESTful、拦截器】
- OpenStack与SDN控制器的集成
- 使用机器学习算法对流量分类的尝试——基于样本分类
- 曾经做过的40道程序设计课后习题总结(一)
- 基于ODL与Pica8交换机端到端的限速实验
- SpringBoot就是这么简单
- SpringData JPA就是这么简单
- Openflow细节理解之—Buffer_id篇
- 移动商城项目总结
- 移动商城第一篇【搭建项目环境+数据模型】
- 移动商城第二篇(品牌管理模块)【文件上传、数据校验、CRUD】
- 手把手在亚马逊EC2上搭建Keras GPU
- 移动商城第三篇(商品管理)【查询商品、添加商品】
- 移动商城第四篇(商品管理)【添加商品续篇、商品审核和上下架、前台展示、后台筛选】
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Redis过期策略和数据淘汰机制
- 图片由彩色渐变到黑白动画
- Kafka如何保证数据可靠性
- ubuntu中snap包的安装、更新删除与简单使用
- 学习在kernel态下使用NEON对算法进行加速的方法
- Centos7上Mesos和Marathon的安装和配置
- Redis高级数据类型-Bitmap和HyperLogLog
- Redis持久化策略
- 在linux下开启FTP服务方法介绍
- Linux中gpio接口的使用方法示例
- Three.js教程(1):初识three.js
- 解决Electron安装报错问题
- Linux端口映射转发的方法
- Centos7如何备份和还原Redis数据的方法
- linux contos6.8下部署kafka集群的方法