S3から大量のファイルを削除する
S3からファイルを削除する方法はいくつかある。
簡単なのはダッシュボードから削除する方法。これは手軽にできる反面、せいぜい数十万枚程度のファイルしか消せないし、実行中のタブを離れることができない。
CLIで削除する方法もある。簡単なものとしては aws s3 rm s3://your-bucket-name --exclude "*" --include "*" --recursive
というワンライナー。これを実行すると指定したbucket配下の全ファイルを削除していく。ただしこれもそれほど速くない(GUIよりは遥かにマシ)。
で、一番良いのは何かというとdelete-objects — AWS CLI 1.33.33 Command Referenceを使ってbulk deleteをする方法。bulk deleteでは1度のリクエストで最大1000件指定できる。ワンライナーとしては下記。
aws s3api list-objects-v2 --bucket your-bucket-name --prefix "images/$PREFIX" --output text --query 'Contents[].[Key]' | \
grep -v -e "'" | \
tr '\n' '\0' | \
xargs -0 -P2 -n500 bash -c \
'aws s3api delete-objects --bucket your-bucket-name --delete "Objects=[$(printf "{Key=%q}," "$@")],Quiet=true"' _
で、これは確かに速く実行できて最高だが、結構な頻度でInternalError
という謎エラーが発生してこけるということがわかった(大体はおそらくセッション切れ)。自分の場合は数億枚以上のファイルを削除してたので失敗もそれなりにあるわな〜と思うのだがスクリプトが止まると結構困るのでエラーが起きたら少し間を空けてまた実行してくれるようなスクリプトを書いた。
#!/bin/bash
if [ $# -ne 1 ]; then
echo "Usage: $0 <PREFIX>"
exit 1
fi
PREFIX=$1
execute() {
aws s3api list-objects-v2 --bucket your-bucket-name --prefix "$PREFIX" --output text --query 'Contents[].[Key]' | \
grep -v -e "'" | \
tr '\n' '\0' | \
xargs -0 -P2 -n500 bash -c \
'aws s3api delete-objects --bucket your-bucket-name --delete "Objects=[$(printf "{Key=%q}," "$@")],Quiet=true"' _
}
while true; do
if execute; then
echo "Command executed successfully."
break
else
sleep 10
echo "An error occurred. Retrying..."
fi
done
これをdelete_s3_files.sh
みたいな名前で保存して実行権限を与え、./delete_s3_files.sh images/hoge
という感じで削除したいbucket配下のprefix名を与えるとあとは大量削除をやってくれる。
削除が終わるまで無限に実行されるマッチョ実装になってるから回数制限付きの再実行処理とかは必要に応じて入れてほしい。
自分の場合はこれをTerminalで9タブくらい開いてimages/1
,images/2
..images/9
みたいな感じで9並列で実行させることで数億枚のファイルを1日以内で削除できた。
ちなみに終わった後に発見したがライフサイクルを1日にして期限切れで削除にするというのが一番楽っぽい。が、削除されるのは1日後なので1日以内で終わらせたいならAPIでbulk deleteの方が良いかも。
参考
amazon web services - Cheapest way to delete 2 billion objects from S3 IA - Stack Overflow
Discussion