Standby-Namenode shutdown 이슈 발생
Standby-Namenode(mem 30G) 재시작 시, 8시간 동안 namespace image와 edit_log를 불러오다, GC를 반복히며 OOM(Out of Memory)으로 종료되는 상황
수집 및 적재 프로세스 변경 불가능
ODS 파일 삭제 불가능
이에 임시방편으로 Small Files를 Merge 시켜주는 (일회용) 쉘 개발 진행
일자별로 hdfs getmerge를 수행(일자별 파일을 하나의 파일로 합침)
merge된 file 사이즈와 원본 사이즈의 차이가 1000bites 이내면, 정상 merge됐다 판단하고 hdfs 파일 삭제 후 put hdfs 진행
Put된 hdfs 파일 사이즈를 체크하여 동일하면 로컬의 merge된 파일을 삭제
해당 수행 과정을 log 파일로 남김(tail -f로 확인하면서 수행할 수 있도록)
hdfs_directory.sh
#!/bin/bash
# 인자값이 1개가 아니면 Usage 출력
if [ $# != 1 ] ; then
echo "usage : ./hdfs_directory.sh [path]"
echo "example : ./hdfs_directory.sh /xxx/xxx/xxx/xxx/ods/xxx/xxx_ext"
fi
if [ $# == 1 ] ; then
path=$1
# 저장할 dir_name 가져오기 : 지정한 path의 가장 마지막 폴더 이름
# a/b/c/d라면 d_dir_list.txt로 저장됨
# list는 p_day를 포함한 directory만을 대상으로 나열됨
# p_day=$$/*로 일자별 getmerge를 수행하기 위함임
dir=`echo $path | rev | cut -d "/" -f 1 | rev`
echo "`sudo -u hdfs hdfs dfs -ls -R ${path} | grep -E '^d' | awk '{print $8}' | grep -e 'p_day'`" > "${dir}_dir_list.txt"
fi
hdfs_merge.sh
실제 merge 작업을 수행하는 쉘스크립트
getmerge의 -skip-empty-file의 경우 hadoop2.7.4 version에서는 동작 불가
#!/bin/bash
#add_log(arg1=merge_filename, arg2 = process_name)
#log를 hdfs_merge.log에 기록
#merge_filename과 process_name을 표시하여, 구분하기 쉽게 처리
#error 시, [ERROR]로 표시, 성공정보는 [INFO]로 표시 흐름을 알기 위해 시간 표기
add_log() {
if [ $? -eq 0 ] ;then
/bin/bash -c "echo $(date +"%Y-%m-%d_%H:%M:%S") $1 [INFO] sucess $2 >> hdfs_merge.log 2>&1"
else
/bin/bash -c "echo $(date +"%Y-%m-%d_%H:%M:%S") $1 [ERROR] $2 Caused by ... >> hdfs_merge.log 2>&1"
exit 9
fi
}
if ! [ $# == 2 ] ;
then
# 확장자는 자동으로 찾도록 함
echo "usage : hdfs_merge.sh [dir_list_file] [filename_prefix]"
echo "example : ./hdfs_merge.sh xxx_ext_dir_list.txt xxx_ext"
else
while read FILE_PATH; do
# dir_list_file을 한 줄 씩 읽으며 getmerge 수행
# {8자리date}_{filename_prefix}.{extension}으로 저장됨
# extension이 없는 경우, 빈 문자열이 되어 filename만으로 merge_file_name 생성
extension=`sudo -u hdfs hdfs dfs -ls $FILE_PATH | awk '/\./' | sed -n '1p' | cut -d '.' -f 2`
if ! [[ -z $extension ]] ;
then
extension=.$extension
fi
#FILENAME이 정해지지 않은 채 ERROR 발생시, FILE_PATH을 그대로 가져와서 log 기록
add_log $FILE_PATH make_extension_variable
# =(equal) 문자 이후 다음 숫자를 가져와서 date 변수 생성
merge_file_date=`echo "$FILE_PATH" | grep -Eo '[^0-9][=][0-9]{1,4}' | sed 's/[^0-9]//g' | tr -d '\n'`
add_log $FILE_PATH make_merge_file_date_variable
merge_filename="${merge_file_date}$2$extension"
add_log $FILE_PATH make_merge_filename_variable
# hdfs getmerge 진행
/bin/bash -c "sudo -u hdfs hdfs dfs -getmerge $FILE_PATH/* ./$merge_filename"
add_log $merge_filename getmerge
hdfs_size=`sudo -u hdfs hdfs dfs -du -s $FILE_PATH | awk '{print $1}'`
add_log $merge_filename make_hdfs_size_variable
add_log "hdfs_size="$hdfs_size
local_size=`ls -al $merge_filename | awk '{print $5}'`
add_log $merge_filename make_local_size_variable
add_log "local_size="$local_size
diff_size=$((hdfs_size-local_size))
add_log $merge_filename diff_size_variable
add_log "diff_size="$diff_size
/bin/bash -c "rm -f .${merge_filename}.crc"
add_log $merge_filename delete_merge_file_crc
if [[ $diff_size -lt 1000 && $diff_size -gt -1000 ]] ;
then
# merge되지 않은 hdfs_files 삭제
/bin/bash -c "sudo -u hdfs hdfs dfs -rm -f -skipTrash $FILE_PATH/* >> hdfs_merge.log 2>&1"
add_log $merge_filename delete_hdfs_files
# merge된 local_file을 hdfs에 적재
/bin/bash -c "sudo -u hdfs hdfs dfs -put $merge_filename $FILE_PATH >> hdfs_merge.log 2>&1"
add_log $merge_filename diff_local_file
# put된 hdfs_file_size와 local_size 비교하여 1000이하면 local_merge_file 삭제
after_hdfs_size=`sudo -u hdfs hdfs dfs -du -s $FILE_PATH | awk '{print $1}'`
add_log $merge_filename make_after_hdfs_size_variable
add_log "local_size="$local_size
add_log "after_hdfs_size="$after_hdfs_size
after_diff_size=$((local_size-after_hdfs_size))
add_log "after_diff_size="$after_diff_size
add_log $merge_filename make_after_diff_size_variable
if [[ $after_diff_size -lt 1000 && $after_diff_size -gt -1000 ]];
then
/bin/bash -c "rm -f $merge_filename"
add_log $merge_filename delete_local_merge_file
else
add_log $merge_filename delete_local_merge_file
/bin/bash -c "echo [ERROR] $merge_filename after_diff_size exceed 1000!! >> hdfs_merge.log 2>&1"
fi
else
add_log $merge_filename delete_local_merge_file
/bin/bash -c "echo [ERROR] $merge_filename diff_size exceed 1000!! >> hdfs_merge.log 2>&1"
fi
# 완료됐으면, 기존 dir_list_file에서 완료된 라인 삭제 처리 ==> 재처리시 편하게
/bin/bash -c "sed -i 's|${FILE_PATH}||g' $1"
/bin/bash -c "sed -i '/^$/d' $1"
add_log $merge_filename dir_list_file_delete_FILE_PATH
done < $1
fi
./hdfs_directory.sh /xxx/xxx/xxx/xxx/ods/xxx/xxx_ext
./hdfs_merge.sh /xxx/xxx/xxx/xxx/ods/xxx/xxx_ext_dir_list.txt xxx_ext
tail -f hdfs_merge.log