上亿文件PB级数据治理
Date: Jun 4, 2021
背景介绍
平台提供了专门的训练存储给用户进行日常训练使用;
随着用户数据量的增加,存储虽然经历了几次扩容依然不够用;
分析用户数据,发现有很多数据是训练的中间产物,不过很少有用户及时删除,直到配额满了影响现有任务后才会想着删除数据;
根据这种情况,平台定期执行了自动清理数据策略;
自19年11月至今已有效删除文件数9亿+;文件量1.7PB+
近期整理里下相关内容,现分享出来,与大家共同交流
1、规则制定
从背景可以看出,任务的重点是找到用户的临时数据并删除;
由于数据是训练数据,可以由原始数据再次生成,因此为了后续清理的便捷,需要用户区分出存储中的非训练数据,如原始数据、训练工具等;并将这类数据转移至对应存储上
与用户沟通,普遍反映,训练数据保留2-3个月即可,部分用户有些文件可能需要长期保存
最终定下的清理规则如下:
1、平台检索出训练存储中用户2个月未访问的文件,并将文件列表和目录列表公示给用户
2、用户根据平台给出的文件、目录列表,区分出重要数据反馈平台
3、平台根据用户反馈,更新文件列表
4、公示阶段结束,平台根据最终的文件列表,将文件移动到待删除区,并发送邮件给用户做最后的检查,如果有数据是需要的,从待删除区自行mv回原来对应的目录下;并给出最终时间点,和用户沟通后定为3天
5、用户最终确认阶段结束后,平台先检索出待删除区各个用户的文件数、文件总量、整体的文件数、文件总量;之后执行删除操作;删除操作完成后发送最终总结邮件给用户,包括哪些人参加了清理、每个用户清理的数据量是怎样的。
6、计划每个月执行一次
2、实际操作
规则制定完成后,需要根据规则完成各个阶段的代码编写,需要保证效率及正确性,还需要考虑到部分用户的特殊需求
2-1、检索阶段
第一个拦路虎就是检索阶段,由于训练存储达到了PB级别,文件数有几十亿个,如果仅仅使用find命令,时间上不允许。
经过几个月的调研,最终决定使用mpifileutils;现在来看完全是个神器;这个后续会另写一篇详细介绍;整个自动清理用到了这个工具集中的dfind(检索阶段)、dwalk(统计阶段)、drm(删除阶段)
整体思路:
- 使用dfind生成每个用户的文件索引数据库;
- dfind读取数据库,生成文件列表和目录列表
- 发送自动清理启动邮件,检索阶段结束(对应规则中的1号规则)
下面给下各个阶段的代码(非原代码):
1、dfind 生成数据库:(find_tmp_create,.sh)
#!/bin/bash
# host: xx.xx.xx.xx #这个是执行dfind的主节点,dfind需要结合mpi使用,开启多进程加速整个检索过程
mkdir /storage/delete_2mouth/group/dfind_tmp #这里的storage就是训练存储,dfind_tmp存储放的是这个组内所有人的文件索引数据库
echo `date +%F-%T` >> log
for user in `ls /storage/group` # 这个目录是用户数据存放目录
do
echo $user >> log
mpirun --allow-run-as-root -machinefile /root/dfind/hostf -mca btl_tcp_if_include netdev --oversubscribe -np 150 dfind \
--type f --atime +60 --size +50KB /storage/group/$user -o /storage/delete_2mouth/group/dfind_tmp/$user"_tmp" >> log
done
# 这里的netdev是指定主节点和子节点交互时使用的网卡名,需要根据实际指定
2、dfind读取数据库,生成文件列表和目录列表(qfind.sh username)
mkdir /storage/delete_2mouth/group/check_xxxxxxx #根据检索的日期创建check目录
cd /storage/delete_2mouth/group/check_xxxxxxx
执行方法:
mkdir /storage/delete_2mouth/group/check_xxxxxxx #根据检索的日期创建check目录
cd /storage/delete_2mouth/group/check_xxxxxxx
for user in `ls /storage/group`
do
qfind $user
done
qfind.sh:
#!/bin/bash
#start load environment 加载mpi环境,执行过程中可能需要使用到dfind
echo "[`date +%F-%T`] start load environment"
module load /opt/tool/modulefiles/spack/spack # 这里将mpifiutils装在了opt中并配置了module (module的使用后续再另写文章)
. /opt/tool/spack/share/spack/setup-env.sh
spack load mpifileutils
module load /opt/tool/modulefiles/mpi/openmpi-3.1.1
#config
multinum=`lscpu | grep '^CPU(s):' | awk '{print $2}'`
echo $multinum
#find filelist
echo "[`date +%F-%T`] start find $1 file"
mkdir $1
echo "[`date +%F-%T`] start find $1 file" >> $1/$1"_checklist"
echo >> $1/$1"_checklist"
if [[ ! -f /storage/delete_2mouth/group/dfind_tmp/$1"_tmp" ]];then #如果索引库中没有索引
days=60
echo "start to dfind $1 $days ago files"
mpirun --allow-run-as-root --oversubscribe -np $multinum dfind --type f --atime +60 --size +50KB /storage/group/$1 \
-o /storage/delete_2mouth/group/dfind_tmp/$1"_tmp" >> $1/$1"_checklist" 2> $1/$1"_errlist"
fi
if [[ ! -f /storage/delete_2mouth/group/dfind_tmp/$1"_tmp" ]];then #再次判断,当用户文件中没有匹配的文件,索引库不会生成
> $1/$1"_filelist"
> $1/$1"_filelist_tmp"
else
dfind -i /storage/delete_2mouth/group/dfind_tmp/$1"_tmp" --type f --atime +60 --print |grep -v "] Read" |sed 's#\\#\\\\#g' > $1/$1"_filelist_tmp"
fi # 这里sed是对特殊的目录名或文件名做处理,比如中文的(、?等
#check link file
# 这里把link文件检索出来,不处理
if [[ -s $1/$1"_filelist_tmp" ]];then #再次判断,当用户文件中没有匹配的文件,索引库不会生成
echo "$1/$1'_filelist_tmp' is not empty ,start to check "
dfind -i /storage/delete_2mouth/group/dfind_tmp/$1"_tmp" --type l --atime +60 --print |grep -v "] Read" |sed 's#\\#\\\\#g' > $1/$1"_filelist_tmp_line"
fi # 这里sed是对特殊的目录名或文件名做处理,比如中文的(、?等
if [[ -s $1/$1"_filelist_tmp_line" ]];then # 如果link存在,需要结合tmp去重
cat $1/$1"_filelist_tmp_line" $1/$1"_filelist_tmp" | sort | uniq -c | grep '^[ \t ]*1' | sed 's/[ \t ]//g' |grep -v "用户需要保留的文件目录" \
> $1/$1"_filelist"
esle #如果没有链接文件,则从tmp中去除用户需要保留的文件
cat $1/$1"_filelist_tmp" | sort | uniq -c | grep '^[ \t ]*1' | sed 's/[ \t ]//g' |grep -v "用户需要保留的文件目录" > $1/$1"_filelist"
fi
#dirlist create #这里根据用户文件列表生成目录列表,以便用户查看
echo >> $1/$1"_checklist"
cat $1/$1"_filelist" | awk -F '/' '{for (i=1;i<NF;i++){printf ("%s",$i"/")}{ print '\n' }}' |sort -u > $1/$1"_dirlist" 2> $1/$1"_errlist"
chown -R $1:group $1 #修改目录权限,让用户查看或修改
3、发送自动清理启动邮件,检索阶段结束
2-2、移动阶段(规则4)
这个阶段就是根据上个阶段生成的文件列表进行移动操作,由于代码较多,这里懒得打字改截图了 0.0!
2-3、删除阶段
这个阶段就简单了,先dwalk统计下数据,在drm删除就行了
查看删除总量:
这里可以看到最新一次删除的数据有160T左右
删除过程中,对存储造成了较大压力,减少并行度后有所缓解
3、待优化点
整个过程中还有一些待优化的点,目前没有找到好的解决办法:
- 单个用户文件过多,检索时长过大;目前文件数在一个亿以内的检索时间还可以接受,但是部分用户数据量达到了十几亿,这种目前只能让用户自己管理
- mv操作时最后的mvscript是将所有单个目录的移动操作放到一个脚本里后台执行,目前负载最多能hold 1万左右;更多的话就不行了,另外这种才做比较low,后续得想办法优化;比如加个判断,如果目录下所有文件都需要mv,则mv整个目录;这个现在还没想好怎么弄
- 整个流程还不够自动化,后续可以考虑进行封装