Linux下利用文件描述符恢复的成功失败实验

 

 

数据误删除是作为初级运维人员常常遇到的“低级错误”,一些有经验的老手有时也在疲劳、不冷静的情况下“马失前蹄”。一旦误删除数据文件,尽快采用影响最小、最迅速的手段恢复数据库是第一要务。

恢复数据的方法很多,比如冷热备份、闪回数据库等等,如果是直接从操作系统OS层面删除数据文件,在Linux/Unix环境下,有一些优选手段可以使用。其中之一就是文件描述符(File Description)。

 

1、聊聊File Description

 

不同的操作系统,在实现CPU管理、内存管理和存储文件管理的时候,采用不同的方式手段。

在Linux和Unix里面,采用文件描述符进行文件管理。一个进程要打开文件,是调用操作系统内核功能,内核返回一个文件描述符。对文件的读写操作也通过这个描述符进行操作。操作系统删除一个文件的时候,是要确定文件所有文件描述符都是释放掉之后,才会最后删除。

我们的误操作,如果是发生在正在运行的数据库系统中,文件虽然在操作系统上删除不可见了。但是数据库Oracle进程中还会保有一些存在的文件描述符,借用这些文件描述符,我们是可能找到文件信息,来恢复数据文件的。

所以,一旦发生了误删除动作,切忌三点:心态冷静、断开应用、维护现场不关库。

但是,在实际中,这种可以快速恢复的技术,并不是百分之百成功的。使用文件描述符恢复数据需要数据库不能关闭、数据库进程不能“自动剔除”数据文件等。本文从两个实验着手,介绍一下操作方法和前提。

 

2、实验环境搭建

 

我们选择Linux 2.6内核和Oracle 11g进行试验。注意:在生产环境下,绝对不能进行这样的实验。进行试验的时候,也需要完备的备份。

 

[oracle@bspdev ~]$ uname -a

Linux bspdev.localdomain 2.6.18-308.el5 #1 SMP Tue Feb 21 20:05:41 EST 2012 i686 i686 i386 GNU/Linux

 

SQL> select * from v$version;

BANNER

--------------------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

PL/SQL Release 11.2.0.1.0 - Production

CORE 11.2.0.1.0 Production

TNS for Linux: Version 11.2.0.1.0 - Production

NLSRTL Version 11.2.0.1.0 – Production

 

创建专门的表空间、用户和数据表,用于进行试验。

 

SQL> create tablespace rmdtest datafile '/u01/oradata/WILSON/datafile/rmdtest01.dbf' size 1000m

  2  extent management local uniform size 1m

  3  segment space management auto;

 

Tablespace created

 

SQL> create user rmtest identified by rmtest default tablespace rmdtest;

User created

 

SQL> grant resource, connect to rmtest;

Grant succeeded

 

SQL> grant select any dictionary to rmtest;

Grant succeeded

 

SQL> create table rm_tab as select * from dba_objects;

Table created

 

SQL> insert into rm_tab select * from rm_tab;

72731 rows inserted

 

SQL> commit;

Commit complete

 

数据表T,在实验环境的表空间文件里面。

 

SQL> select tablespace_name, bytes/1024/1024 M from dba_segments where owner='RMTEST' and segment_name='RM_TAB';

TABLESPACE_NAME                         M

------------------------------ ----------

RMDTEST                                17

 

确保有一份好的备份!

 

RMAN> list backup;

 

List of Backup Sets

===================

BS Key  Type LV Size       Device Type Elapsed Time Completion Time

------- ---- -- ---------- ----------- ------------ ---------------

135     Full    1.39G      DISK        00:03:13     02-FEB-14     

        BP Key: 135   Status: AVAILABLE  Compressed: NO  Tag: TAG20140202T012300

(篇幅原因,有省略……)

        Piece Name:

        Piece Name: /u01/flash_recovery_area/WILSON/autobackup/2014_02_02/o1_mf_s_838430779_9gtckx4s_.bkp

  SPFILE Included: Modification time: 02-FEB-14

  SPFILE db_unique_name: WILSON

  Control File Included: Ckp SCN: 5370719      Ckp time: 02-FEB-14

 

下面进行两次实验过程,模拟运行状态下数据文件被删除的场景。注意:由于操作系统差异性,Windows下是不会出现“运行打开的文件被删除”的场景的。所以,在Linux/AIX中,更容易出现误删除的情况。

 

3、一次“不成功”的实验

 

首先是一次不成功的实验。运维生产环境中,我们的原则永远是稳定。危险不确定的事情场景,一定要避免。哪怕不做、不修、不优化,也不要让业务系统的可用性去冒险。

实验环境中,我们总能够发现很多知识和现象。首先,我们尝试删除数据文件,确认文件位置。

 

[oracle@bspdev ~]$ cd /u01/oradata/WILSON/datafile/

[oracle@bspdev datafile]$ ls -l | grep rmdtest01.dbf

-rw-r----- 1 oracle oinstall 1048584192 Feb  2 02:14 rmdtest01.dbf

 

删除文件。

 

[oracle@bspdev datafile]$ rm rmdtest01.dbf

[oracle@bspdev datafile]$ ls -l

total 8121892

-rw-r----- 1 oracle oinstall   10493952 Feb  2 02:14 mvtbltest01.dbf

(篇幅原因,有省略……)

-rw-r--r-- 1 oracle oinstall   10493952 Feb  2 02:14 tts_simple01.dbf

 

注意:此时数据文件虽然从OS中删除,但是我们依然可以查询到数据!

 

SQL> select count(*) from rmtest.rm_tab;

  COUNT(*)

----------

    145462

 

对于这种现象,笔者认为两种可能性,一是buffer cache中的缓存数据信息,可以支持这种查询动作。另一种可能性,就是由于文件描述符的存在,让数据文件没有被真正删除,还以某种方式存在于系统中,支持dbwr查询。

 

证明两种猜想,对buffer cache进行清理。

 

SQL> alter system flush buffer_cache;

System altered

 

SQL> alter system flush shared_pool;

System altered

 

--依然可以查询结果

SQL> select count(*) from rmtest.rm_tab;

  COUNT(*)

----------

    145462

 

但是,如果数据库以某种方式,发现了文件被删除,比如check point动作,就会引起很多自动化动作出现。

 

SQL> alter system checkpoint;

System altered

 

--alert log中信息如下:

Sun Feb 02 02:27:51 2014

Beginning global checkpoint up to RBA [0x1ef.2532.10], SCN: 5374358

Errors in file /u01/diag/rdbms/wilson/wilson/trace/wilson_ckpt_4814.trc:

ORA-01171: datafile 11 going offline due to error advancing checkpoint

ORA-01116: error in opening database file 11

ORA-01110: data file 11: '/u01/oradata/WILSON/datafile/rmdtest01.dbf'

ORA-27041: unable to open file

Linux Error: 2: No such file or directory

Additional information: 3

Completed checkpoint up to RBA [0x1ef.2532.10], SCN: 5374358

Sun Feb 02 02:27:52 2014

Checker run found 1 new persistent data failures

 

Check Point是Oracle内部控制的一件大事。经过check point,Oracle要保证所有数据文件、控制文件SCN信息保持一致,和日志文件在恢复时间点(RBA+SCN)达成一致。这个过程就强制回去访问到数据文件,结果文件丢失被发现。

此后,查询出错。

 

SQL> select count(*) from rmtest.rm_tab;

select count(*) from rmtest.rm_tab

 

ORA-00376: 此时无法读取文件 11

ORA-01110: 数据文件 11: '/u01/oradata/WILSON/datafile/rmdtest01.dbf'

 

注意:如果放任不管,Oracle自动的incremental checkpoint也会有类似的效果。同时,周期性的Global Check也会发现“文件丢失了”。

这个时候,我们进行修复操作。使用文件描述符恢复文件的方法,第一步找到一个Oracle后台进程,最典型的就是dbwr。

 

[oracle@bspdev datafile]$ ps -ef | grep dbw

oracle    4806     1  0 02:12 ?        00:00:00 ora_dbw0_wilson

oracle    9076  4491  0 02:29 pts/0    00:00:00 grep dbw

 

使用lsof –p命令,找出dbwr进程对应的文件描述符信息。

 

[root@bspdev datafile]# lsof -p 4806

COMMAND  PID   USER   FD   TYPE DEVICE   SIZE/OFF      NODE NAME

oracle  4806 oracle  cwd    DIR  253,0       4096  10574090 /u01/oracle/dbs

oracle  4806 oracle  rtd    DIR  253,0       4096         2 /

oracle  4806 oracle  txt    REG  253,0  173515991  10579756 /u01/oracle/bin/oracle

(篇幅原因,有省略……)

racle  4806 oracle   33uW  REG  253,0   10493952   2978999 /u01/oradata/WILSON/datafile/mvtbltest01.dbf

oracle  4806 oracle   34uW  REG  253,0   30416896    524875 /u01/oradata/WILSON/datafile/o1_mf_temp_7xt46489_.tmp

oracle  4806 oracle   35r   REG  253,0    1074176  10595009 /u01/oracle/rdbms/mesg/oraus.msb

 

里面包括了dbwr打开的所有文件描述符,我们没有能看到删除的文件rmdtest01.dbf。文件描述符目录也没有相应的FD内容。说明:由于一些情况,Oracle进程将文件描述符删除了!

 

此时,我们检查文件状态。

 

SQL> select online_status from dba_data_files where file_id=11;

 

ONLINE_STATUS

-------------

RECOVER

 

文件已经被offline,强制剔除文件体系了。仔细想起来,这个过程是check point的一个结果。

Check Point的最终效果,是所有数据文件在文件头标注相同的SCN记录,之前脏块被写入到数据文件中。如果一个数据文件实体不存在了,这个操作一定不能完成。Oracle选择了一种方法,就是强制将这个文件“剔除”。所以我们在日志中,看到了下面一段内容。

 

ORA-01171: datafile 11 going offline due to error advancing checkpoint

 

被剔除的文件,Oracle关闭文件描述符也是可以理解的了。

这个实验失败,告诉我们一个道理:使用文件描述符进行数据恢复,并不是100%有效。如果时间很长,或者进行过很多特殊操作,这个微弱的文件描述符是会消失的!

下面我们进行一次成功的实验。

 

4、一次“成功”的实验

 

我们借助RMAN备份,恢复到实验前的状态。

 

[root@bspdev datafile]# ls

mvtbltest01.dbf               o1_mf_temp_7xt46489_.tmp

o1_mf_example_7xt46m9x_.dbf   o1_mf_undotbs1_7xt3yzl5_.dbf.bak

o1_mf_jpatest_87y6v8qc_.dbf   o1_mf_undotbs1_92l5b0v4_.dbf

o1_mf_nbscommo_820frtg1_.dbf  o1_mf_users_805nxydh_.dbf

o1_mf_nbscommo_820ft5y5_.dbf  rmdtest01.dbf

o1_mf_sysaux_7xt3yzkb_.dbf    tts_simple01.dbf

o1_mf_system_7xt3yzhj_.dbf

 

删除数据文件。

 

[root@bspdev datafile]# rm rmdtest01.dbf

rm: remove regular file `rmdtest01.dbf'? y

[root@bspdev datafile]# ls

mvtbltest01.dbf               o1_mf_system_7xt3yzhj_.dbf

o1_mf_example_7xt46m9x_.dbf   o1_mf_temp_7xt46489_.tmp

o1_mf_jpatest_87y6v8qc_.dbf   o1_mf_undotbs1_7xt3yzl5_.dbf.bak

o1_mf_nbscommo_820frtg1_.dbf  o1_mf_undotbs1_92l5b0v4_.dbf

o1_mf_nbscommo_820ft5y5_.dbf  o1_mf_users_805nxydh_.dbf

o1_mf_sysaux_7xt3yzkb_.dbf    tts_simple01.dbf

 

删除之后,借助文件描述符,我们还是可以查询的。

 

SQL> select count(*) from rmtest.rm_tab;

 

  COUNT(*)

----------

    145462

 

查找dbwr进程,确定进程编号。

 

[root@bspdev datafile]# ps -ef | grep dbw

oracle    9405     1  0 02:45 ?        00:00:00 ora_dbw0_wilson

root      9716  4466  0 02:56 pts/0    00:00:00 grep dbw

 

使用lsof –p确定文件描述符信息。

 

[root@bspdev datafile]# lsof -p 9405

COMMAND  PID   USER   FD   TYPE DEVICE   SIZE/OFF      NODE NAME

oracle  9405 oracle  cwd    DIR  253,0       4096  10574090 /u01/oracle/dbs

(篇幅原因,有省略……)

oracle  9405 oracle   29uW  REG  253,0  209723392    525165 /u01/oradata/WILSON/datafile/o1_mf_nbscommo_820frtg1_.dbf

oracle  9405 oracle   30uW  REG  253,0  104865792    525166 /u01/oradata/WILSON/datafile/o1_mf_nbscommo_820ft5y5_.dbf

oracle  9405 oracle   31uW  REG  253,0  104865792    525484 /u01/oradata/WILSON/datafile/o1_mf_jpatest_87y6v8qc_.dbf

oracle  9405 oracle   32uW  REG  253,0   10493952    525541 /u01/oradata/WILSON/datafile/tts_simple01.dbf

oracle  9405 oracle   33uW  REG  253,0   10493952   2978999 /u01/oradata/WILSON/datafile/mvtbltest01.dbf

oracle  9405 oracle   34uW  REG  253,0   30416896    524875 /u01/oradata/WILSON/datafile/o1_mf_temp_7xt46489_.tmp

oracle  9405 oracle   35r   REG  253,0    1074176  10595009 /u01/oracle/rdbms/mesg/oraus.msb

oracle  9405 oracle   36uW  REG  253,0 1048584192   2979001 /u01/oradata/WILSON/datafile/rmdtest01.dbf (deleted)

 

注意:lsof是描述文件描述符最好的工具,其中包括FD列。我们从dbwr的连接中,找到了rmdtest01.dbf的信息行。其中FD=36uw。这个36就表示了连接文件的名称。

 

联合dbwr的进程编号9405,我们在目录/proc/9405/fd中找到所有的文件符。

 

 

[root@bspdev datafile]# cd /proc/9405/fd

[root@bspdev fd]# ls

0  10  12  14  16  18  2   21  23  25  27  29  30  32  34  36  5  7  9

1  11  13  15  17  19  20  22  24  26  28  3   31  33  35  4   6  8

 

Ls命令也可以列出信息。

 

 

[root@bspdev fd]# ls -l

total 0

lr-x------ 1 oracle oinstall 64 Feb  2 02:56 0 -> /dev/null

l-wx------ 1 oracle oinstall 64 Feb  2 02:56 1 -> /dev/null

lrwx------ 1 oracle oinstall 64 Feb  2 02:56 10 -> /u01/oracle/dbs/lkinstwilson (deleted)

lrwx------ 1 oracle oinstall 64 Feb  2 02:56 34 -> /u01/oradata/WILSON/datafile/o1_mf_temp_7xt46489_.tmp

lr-x------ 1 oracle oinstall 64 Feb  2 02:56 35 -> /u01/oracle/rdbms/mesg/oraus.msb

lrwx------ 1 oracle oinstall 64 Feb  2 02:56 36 -> /u01/oradata/WILSON/datafile/rmdtest01.dbf (deleted)

l-wx------ 1 oracle oinstall 64 Feb  2 02:56 9 -> /home/oracle/oradiag_oracle/diag/clients/user_oracle/host_1437849207_76/trace/ora_9293_3085993664.trm

 

这个36对应的文件还存在,就是已经被删除的那个rmdtest01.dbf文件。进行拷贝出来。

 

[root@bspdev fd]# cp 36 /u01/oradata/WILSON/datafile/rmdtest01res.dbf

[root@bspdev fd]#

 

拷贝出来之后,最好进行一定转换。先将其offline,之后进行控制文件中的rename动作,最后recover和online操作。具体流程常见笔者专门的文章(http://blog.itpub.net/17203031/viewspace-773628/)。

 

SQL> alter database datafile 11 offline;

Database altered

 

Rename操作。

 

--报错

SQL> alter database rename file '/u01/oradata/WILSON/datafile/rmdtest01.dbf' to '/u01/oradata/WILSON/datafile/rmdtest01res.dbf';

 

alter database rename file '/u01/oradata/WILSON/datafile/rmdtest01.dbf' to '/u01/oradata/WILSON/datafile/rmdtest01res.dbf'

 

ORA-01511: 重命名日志/数据文件时出错

ORA-01141: 重命名数据文件 11 时出错 - 未找到新文件 '/u01/oradata/WILSON/datafile/rmdtest01res.dbf'

ORA-01110: 数据文件 11: '/u01/oradata/WILSON/datafile/rmdtest01.dbf'

ORA-27041: 无法打开文件

Linux Error: 13: Permission denied

Additional information: 9

 

究其原因,是拷贝权限为root,需要手工修改所有权信息。

 

[root@bspdev datafile]# ls -l | grep rmd

-rw-r----- 1 root   root     1048584192 Feb  2 03:01 rmdtest01res.dbf

[root@bspdev datafile]# chown oracle:oinstall rmdtest01res.dbf

[root@bspdev datafile]# ls -l | grep rmd

-rw-r----- 1 oracle oinstall 1048584192 Feb  2 03:01 rmdtest01res.dbf

 

Rename文件。

 

 

SQL> alter database rename file '/u01/oradata/WILSON/datafile/rmdtest01.dbf' to '/u01/oradata/WILSON/datafile/rmdtest01res.dbf';

Database altered

 

SQL> recover datafile 11;

Media recovery complete.

SQL> alter database datafile 11 online;

 

Database altered.

 

使用rman中的recovery advisor工具,来判断错误是否存在。

 

[oracle@bspdev ~]$ rman nocatalog

 

Recovery Manager: Release 11.2.0.1.0 - Production on Sun Feb 2 03:06:43 2014

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

RMAN> connect target /

 

connected to target database: WILSON (DBID=3906514064)

using target database control file instead of recovery catalog

 

RMAN> list failure;

no failures found that match specification

 

恢复完成,实验成功。

 

5、结论

 

本篇文章的书写,有一半目的是揭示文件内部的运行机制,另一半是记录下Linux下使用文件描述符FD来恢复数据的方法。我们说,从运维角度看,直接绕过数据库对OS进行文件操作是非常不成熟的做法,无论是出于什么目的。很多致命的错误都是一系列的rm造成的。愿文章描述的场景永不会在所有运维生产系统中出现!

 

时间: 2024-08-29 03:17:39

Linux下利用文件描述符恢复的成功失败实验的相关文章

简介Linux下的文件描述符

在C程序中,文件由文件指针或者文件描述符表示.ISO C的标准I/0库函数(fopen, fclose, fread, fwrite, fscanf, fprintf等)使用文件指针,UNIX的I/O函数(open, close, read, write, ioctl)使用文 件描述符.下面重点来说下,文件描述符是如何工作的. 文件描述符相当于一个逻辑句柄,而 open,close等函数则是将文件或者物理设备与句柄相关联.句柄是一个整数,可以理解为进程特定的文件描述 符表的 索引.先介绍下面三个

linux exec和文件描述符妙用技巧(转)

  最近在看<精通unix shell脚本编程>时,看到exec<$1 exec 1>$OUTFILE,一下看的我就蒙了.网上看了大半天,终于搞定,记录如下.对于 Linux 而言,所有对设备和文件的操作都使用文件描述符来进行的.文件描述符是一个非负的整数,它是一个索引值,并指向内核中每个进程打开文件的记录表.当打开一个现存文件或创建一个新文件时,内核就向进程返回一个文件描述符;当需要读写文件时,也需要把文件描述符作为参数传递给相应的函数.通常,一个进程启动时,都会打开 3 个文件

使用LINUX dup2 复制文件描述符到标准输出STDOUT_FILENO

  7    8 #include<stdio.h>   9 #include <sys/types.h>  10 #include <sys/stat.h>  11 #include <fcntl.h>  12 #include <stdlib.h>  13 #include <unistd.h>  14   15   16   17 int main(int argc,char *argv[])  18 {  19     int

更改linux的最大文件描述符限制

To ensure good server performance, the total number of client connections, database files, and log files must not exceed the maximum file descriptor limit on the operating system (ulimit -n). By default, the directory server allows an unlimited numbe

[性能分析]linux文件描述符(转)

1.什么是文件和文件描述符   Linux中文件可以分为4种:普通文件.目录文件.链接文件和设备文件.1.普通文件是用户日常使用最多的文件,包括文本文件.shell脚本.二进制的可执行和各种类型的数据.ls -lh 来查看某个文件的属性,可以看到有类似 -rw-r--r-- ,值得注意的是第一个符号是 - ,这样的文件在Linux中就是普通文件.这些文件一般是用一些相关的应用程序创建,比如图像工具.文档工具.归档工具... .... 或 cp工具等.这类文件的删除方式是用rm 命令:2.目录文件

文件句柄(file handles) &amp;amp; 文件描述符(file descriptors)

1.概述 在实际工作中会经常遇到一些bug,有些就需要用到文件句柄,文件描述符等概念,比如报错: too many open files, 如果你对相关知识一无所知,那么debug起来将会异常痛苦.在linux操作系统中,文件句柄(包括Socket句柄).打开文件.文件指针.文件描述符的概念比较绕,而且windows的文件句柄又与此有何关联和区别?这一系列的问题是我们不得不面对的. 博主通过翻阅相关资料,并采用了一些demo来验证相关观点.如果文中有理解偏差,欢迎指正,对linux内核不是很熟,

【MySQL】文件描述符导致报警一则

下午收到报警: xxxxxx:[didb..,][master,slave]/home used:94% free:0.6G 2014-01-12 16:42:40 DutyReceived! [现象] 登陆机器查看: [root@xxxxx /root] #df -h Filesystem            Size  Used Avail Use% Mounted on /dev/sda2              92G  4.2G   83G   5% / /dev/sda6    

Linux下利用Lsof恢复误删文件的方法

  原理:在Linux系统的/proc 分区下保存着进程的目录和名字,包含fd(文件描述符)和其下的子目录(进程打开文件的链接),那么如果删除了一个文件,还存在一个 inode的引用:/proc/进程号/fd/文件描述符.我们只要知道当前打开文件的进程pid和文件描述符fd就能利用lsof工具列出进程打开的文件. 一.将 ls 的手册过滤掉主要控制符后重定向到文件ls.txt 中,并用more查看,CTRL + Z 暂停查看操作 1: [root@localhost script]# man l

并发时-修改Linux系统下的最大文件描述符限制

通常我们通过终端连接到linux系统后执行ulimit -n 命令可以看到本次登录的session其文件描述符的限制,如下: $ulimit -n 1024 当然可以通过ulimit -SHn 102400 命令来修改该限制,但这个变更只对当前的session有效,当断开连接重新连接后更改就失效了. 如果想永久变更需要修改/etc/security/limits.conf 文件,如下: vi /etc/security/limits.conf * hard nofile 102400 * sof