1、现象重现
1、tmp.txt文件正在写文件的过程中,此文件被删除。
2、使用lsof|grep delete 查看
可以看到在删除正在写入文件后,文件并未被真正的删除。而且在过程中还在不停的占用盘的空间,很容县出现磁盘空间不足,很多的时候只是时候发现被动处理,运维才会去介入。
注:本篇不对具体的原因做更多分析,大家可以自行查找,或者可以持续关注,也会在以后的分享中在专门分享这块内容。
2、如何解决
如果数据内容很重要怎么办?
使用cp命令恢复整个文件到cp命令使用时的数据。但是存在需要一直cp。
如何做到事前发现及时解决?
由于文件删除可能是误操作或者代码程序的bug导致误删除,很多时候发现都是系统的磁盘空间不足,导致运维告警,才去解决的。那么如何在第一时间发现以及解决这些问题才是关键。
我们知道linux中有epoll相关的函数(工作原理不做过多介绍),一般地我们使用其来做IO多路复用,来做网络高并发。起原理简单来说就是通过监控文件描述符的读写等事件,来回调到程序来进行相关的业务操作。但是在linux中一切皆文件,所以我们也可以借用其原理,通过内核机制获取文件的相关事件,以及联合Linux提供inotify机制,已允许应用程序监控文件事件。来第一时间进行相关的业务操作,避免后续的更大隐患。知道了具体的使用的方式,那就来看下如何实现吧,以下我们以go为例介绍使用方式;我们要import "github.com/fsnotify/fsnotify"
func WatchFile(logDir string, logName string) error {
// 创建文件/目录监听器
watcher, err := fsnotify.NewWatcher()
if err != nil {
.....
}
go func() {
for {
select {
case ev, ok := <-watcher.Events:
if !ok {
......
}
if ev.Op&fsnotify.Remove == fsnotify.Remove && ev.Name == logName {
//在这里获取到是否是自己关心的文件变化,根据具体情况进行相关业务实现。
//Op包括Create、Write、Rename、Chmod等操作可以根据业务选择
}
case _, ok := <-watcher.Errors:
if !ok {
.....
}
}
}
}()
// 监听文件目录
err = watcher.Add(logDir)
if err != nil {
......
}
return nil
}
以上就是go使用fsnotify的例子很简洁简单的使用。
在c/c++里面我们得自己借用epoll、inotify等,如下是简单的步骤,请参考指正。
// 初始化epoll和inotify
struct epoll_event ev;
int *epoll_fd = epoll_create1(0);
int *watch_fd = inotify_init();
ev.events = EPOLLIN;
ev.data.fd = *watch_fd;
epoll_ctl(*epoll_fd, EPOLL_CTL_ADD, *watch_fd, &ev)
// 新的监控项,也可以修改现有监控项。例如IN_DELETE_SELF | IN_ATTRIB | IN_MOVE_SELF事件
int *wd = inotify_add_watch(fd, file_name, IN_DELETE_SELF | IN_ATTRIB | IN_MOVE_SELF);
// 删除有wd所定义的监控项
int inotify_rm_watch(int fd, uint32_t wd);
//需要联合epoll_wait和read来判断文件的变化
struct epoll_event e_event;
struct inotify_event *i_event = NULL;
char *tmp = NULL;
epoll_wait(epoll_fd, &e_event, XX, XX);
if (e_event.data.fd == watch_fd) {
read_size = read(watch_fd, buf, sizeof(buf));
for (tmp = buf; tmp < buf + read_size; tmp += sizeof(struct inotify_event) + i_event->len) {
i_event = (struct inotify_event *)tmp;
if( (event->mask & IN_CREATE) && ( strcmp( event->name,"XXXX") == 0 ) )
if( (event->mask & IN_DELETE) && ( strcmp( event->name,"XXXX") == 0 ) )
.....
}
}
// event->mask 更多的mask请查看相关文档
总结
本篇我们介绍了删除正在写入文件的现象以及一些运维和使用监控手段解决相关的方案,有不妥之处欢迎批评指正。