记一次线上删除海量文件的思路和方法
问题详情:
web1 是整个架构的唯一web前端服务器,非常不好运的是,因为忘记定期清理每天产生的session文件,导致该web服务器的/home挂载点inode用光了。
/home挂载点下不能继续生成文件,负载也因此飙到400,Nginx 、php-fpm 服务不可用,网站全部无法访问,严重影响线上业务。
$ df -i Filesystem Inodes IUsed IFree IUse% Mounted on /dev/sda2 6553600 109654 6443946 2% / tmpfs 4105528 1 4105527 1% /dev/shm /dev/sda1 128016 45 127971 1% /boot /dev/sda4 236511232 236500000 11232 100% /home
/home/session 为session存放目录,子目录分为两层,即/home/session/{0,1,2...u}/{0,1,2...u}/ 下存放session文件。
临时解决方法:
1、借助其他服务器的inode。
在另外一台服务器上共享nfs文件目录,挂载到web前端服务器上,用作session文件存放目录。
将原/home/session改名为/home/session-bak,nfs目录挂载到/home/session。
2、在共享nfs的服务器上,做定时任务,每15分钟扫一次session目录,删除180分钟以前的session文件。
避免session单个子目录出现文件数超100万的情况,该情况下,无论何种删除文件的方法,都会非常缓慢。
接下来就是如何快速删除前端web服务器上的海量文件了。
问题解决思路探索:
1、利用rm或rsync命令删除海量文件
# rm -rf /home/session-bak # mkdir /home/blank # rsync -a --delete-before -H -v --progress --stats /home/blank /home/session-bak
反馈:因/home/session-bak目录下有超过1亿的海量文件,两种方法效果对比并不明显。而且两种方法非常占用IO的,导致web前端服务器IO被占光,负载又飙到400多,业务大大受影响,不能这样删除海量文件。
2、增加进程运行优先级,只有系统空闲的时候,才执行相应的删除操作
# nice -n 19 rm -rf /home/session-bak # mkdir /home/blank # nice -n 19 rsync -a --delete-before -H -v --progress --stats /home/blank /home/session-bak
反馈:线上业务IO正常,负载正常,但删除文件的速度太慢了。因/home/session-bak目录下有超过1亿的小文件,单次删除的文件数过大,单是构建删除列表就耗费相当久的时间。
3、增加进程优先级,减少每次删除的文件数
因/home/session-bak下有两层子目录,为了提升删除的速度,避免构建删除列表耗费过长的时间,可以每次删除第二层子目录里边的文件。
用Python写个循环删除的脚本(上一个删除命令正常执行完了,才会执行下一个删除命令),放在后台慢慢跑。
#!/usr/bin/env python # _*_ coding:utf8 _*_ import os # 基本路径信息 base_path = "/home/session-bak" postfix = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v'] paths = [] path_temp = '' # 组合路径 for i in postfix: for j in postfix: path_temp = base_path + '/' + i + '/' + j paths.append(path_temp) # 初始状态 stats = 0 it = iter(paths) # 建立迭代器 while stats == 0: # 循环的条件: 上一个命令正常执行完,才能执行下一个命令 try: path = it.next() # 迭代下一个值 stats = os.system("nice -n 19 rm -rf %s" % path) # 当命令正常执行完,会返回0 except StopIteration: print '删除成功' stats = 1