下厨房事故认识Linux文件句柄(fd)

本文介绍了在误删除MySQL数据库文件后正确的紧急应对措施,并详细解释了如何通过文件描述符恢复被误删的数据文件。
以下内容摘自下厨房对公众的致歉信:
"
先使用了rm -f方式删除备份节点分区上的所有文件,5分钟后
发现刚才删除的是数据库主节点的分区,为防止硬盘继续写入,就马上把mysql进程停止了

"
第一时间停止MySQL防止硬盘继续写入这个应急措施是错误的!
正常如果进程没有被关闭,进程所打开的文件是不会被删除的
可以通过从/proc文件系统拷贝的方式恢复出当前仍然打开的文件
诸如rm,drop...等存在误删除风险的命令,意识到之后的第一反应该是:

哪些进程依旧打开了这些文件,如果有,立即从其文件描述符恢复,recovering files from /proc 从fd中恢复误删的ibdata


但是,"Every coin has two sides",以上是fd的优点,不过这也给Linux用户造成一个现象:
为啥有时候df -h看磁盘剩余空间很小,而du -shc看具体目录大小,又没有占用那么多呢?
也就是说,文件删除后,空间并没有得到释放
这很可能是有的文件删除了,但是还被某些进程占用着文件句柄
lsof | grep delete 看看,是不是有进程占用了被删除的文件句柄
重启下这些进程kill -HUP释放文件句柄即可
删除文件后应该释放文件句柄才能释放空间


至于名字,windows上叫文件句柄,Linux上叫文件描述符,英文缩写是fd
每个进程至少都会打开三个文件:标准输入,标准输出,标准错误输出
他们对应的文件句柄是:0,1,2
涉及到文件句柄,有2个命令比较常用:ulimit和lsof
感兴趣的朋友可以参考我之前写的文章:

lsof:lsof 应用实例分享以及Oracle 数据文件删除恢复测试

ulimit:Linux ulimit和动态修改MySQL最大线程数限制


有些服务器上跑了MySQL,Apache,Oracle,,,,比较夸张,这时就很有必要对打开的文件数作修改

而且,直接或间接使用mysqld_safe启动MySQL时,其实是在启动mysqld之前,调用了ulimit -n $open_files来实现文件描述符的限制

有2个层面上的修改:

/etc/security/limits.conf针对单个应用程序,如MySQL

/proc/sys/fs/file-max针对整个Linux系统,比如MySQL+Oracle+Apache代数和

对于单个应用程序,例子如下:

cat /etc/security/limits.conf
* soft nofile 1048576
* hard nofile 1048576 


而对于永久修改整个Linux系统打开文件数的限制

可以往/etc/sysctl.conf追加一个值:fs.file-max=1048567然后sysctl -p

再sysctl fs.file-max做确认



参考文章:

http://cherry.world.edoors.com/CPZKoGkpxfbQ
http://www.hackinglinuxexposed.com/articles/20020507.html
http://tech.xiachufang.com/?p=18
http://www.orczhou.com/index.php/2013/07/how-to-recover-data-from-mysql-innodb-data-file-ibd-file/


By 迦夜
2013-10-3
Good Luck

### 如何在 Linux 中保留文件句柄不关闭文件描述符 在 Linux 系统中,当通过 `fork` 创建子进程时,默认情况下父子进程会共享打开的文件描述符。这意味着如果父进程打开了某个文件,在创建子进程之后,该文件也会保持打开状态,并且两个进程可以独立操作这个文件[^1]。 为了确保某些特定的文件描述符不会因为其他原因而意外关闭,可以通过设置文件描述符标志来实现这一点。具体做法是在调用 `open()` 或者 `dup2()` 函数获取到文件描述符后立即使用 `fcntl()` 来修改其属性,特别是清除 `FD_CLOEXEC` 标志位。这样即使执行了 `execve()` 类型的系统调用来加载新程序也不会自动关闭这些文件描述符[^3]。 下面是具体的代码示例: ```c #include <unistd.h> #include <fcntl.h> int main(){ int fd; // 打开文件并获得文件描述符 fd = open("example.txt", O_RDWR); if (fd >= 0){ // 清除 FD_CLOEXEC 标记以防止 exec 后关闭此文件描述符 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) & ~FD_CLOEXEC); pid_t child_pid = fork(); if(child_pid == 0){ // 子进程中继续使用相同的文件描述符而不必重新打开它 execlp("/bin/cat", "cat", NULL); // 这里假设 cat 命令能够读取已有的文件描述符 _exit(EXIT_FAILURE); } wait(NULL); close(fd); } return 0; } ``` 在这个例子中,`fcntl()` 被用于移除了默认添加给所有新建文件描述符上的 `FD_CLOEXEC` 标识。这使得即便后续发生了 `execlp()` 的调用,指定的文件描述符仍然会被保留下来供新的可执行映像继承和使用[^4]。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值