记一次线上删除海量文件的思路和方法

问题详情:

  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

 

 

  

 

posted @ 2017-04-12 12:29  hjqjk  阅读(644)  评论(0编辑  收藏  举报