Ruby
S3
NiftyCloud
NIFCLOUD

溜まったアレをごっそり年末に掃除する話

この記事は

富士通クラウドテクノロジーズ Advent Calendar 2018 の12日目です。  
昨日は @pachicourse さんの「0知識からのAnsible 詰まった所&覚えておきたいと思ったところ列挙編」でした。

年末大掃除

早いもので、平成最後の年末ももうすぐやってきそうですね。
さて、年末といえば大掃除ですが、みなさまアレはちゃんとキレイにしましたか?
アレとは、そう「マルチパートアップロードのゴミ」です。

マルチパートアップロードとは

マルチパートアップロードとは、S3や互換系のオブジェクトストレージなどで実装されているAPIで
大容量オブジェクトでも分割してアップロードでき、またアップロードが途中で失敗しても続きからやり直してができたりする便利な機能です。※当然ニフクラでも利用できます。
ですが、罠というか忘れがちな仕様がありまして、

  • アップロードされたの分割ファイルは、クライアントからComplete Multipart UploadまたはAbort Multipart Uploadのメッセージが来ないとストレージ上のリストに反映されない
  • アップロードされた分割ファイルは、自動では削除されない。※バケットライフサイクル適用時を除く

という振る舞いを持っているのです。
詳細はこちら

つまりどういうことかというと

マルチパートアップロードを途中でエラーやハングなどで中断した場合、その中途半端なファイルがストレージに残ることになります。
しかもアップロード中の分割ファイルに対するストレージ使用量もバッチリ課金対象となるため、そのまま放置するのは完全に無駄です。そのうちタイムアウトできれいに消えるということもありません。
SDKなど利用してると普段はマルチパートの煩雑な手順を意識することもないので、そもそもゴミが溜まってしまうことも忘れがちですが、
アップロード時のリトライ方式などによっては意外と溜まってしまうものなので年に一度くらい(本当は適宜)、確認して掃除するといいでしょう。

ゴミの探し方

List Multipart Uploads アクションをリクエストします。 

aws cliなどが入っていれば手軽にすぐ確認できます。
導入方法などはこちらをご覧ください。

[root@Test1 ~]#aws s3api list-multipart-uploads --bucket bucketname --endpoint-url https://jp-east-2.storage.api.nifcloud.com | egrep "UploadId|Key"
            "UploadId": "2~kRX-o16c-2XAyiLMLb_dAkT_VVhGRa7",
            "Key": "tempfile",
[root@Test1 ~]#

上記はニフクラオブジェクトストレージに対してリクエストを投げた例ですが、s3でも当然同じです。
ここでアップロード中の分割ファイルを消すためには UploadId 及び Key が必要になります。

ゴミの消し方

マルチパートを完了させるには Complete Multipart UploadAbort Multipart Upload を発行する必要があります。だいたいこのような形で観測される情報はゴミなので、基本的には Abort Multipart Upload を発行していきます。
aws cliでは以下のようになります。

[root@Test1 ~]#aws s3api abort-multipart-upload --bucket bucketname --upload-id 2~kRX-o16c-2XAyiLMLb_dAkT_VVhGRa7 --key tempfile --endpoint-url https://jp-east-2.storage.api.nifcloud.com
[root@Test1 ~]#aws s3api list-multipart-uploads --bucket bucketname --endpoint-url https://jp-east-2.storage.api.nifcloud.com | egrep "UploadId|Key"
[root@Test1 ~]#

いっぱいある場合

たくさんある場合はコマンドラインでちまちまやるにはきついので、スクリプトを組むといいでしょう。
以下はニフクラオブジェクトストレージに対して掃除する場合のサンプル(Ruby)です。

matsui_stick_gossori.rb
require 'aws-sdk'

@bucket = "bucketname"

options = {
  access_key_id: ENV[ACCESS_KEY_ID],
  secret_access_key: ENV[SECRET_ACCESS_KEY],
  region: "jp-east-2",
  endpoint: "https://jp-east-2.storage.api.nifcloud.com"
}

client = Aws::S3::Client.new( options )

begin
   resp = client.list_multipart_uploads({
      bucket: @bucket
   })
   exit unless resp.to_h.has_key?(:uploads)
   resp.to_h[:uploads].each do |upload|
      client.abort_multipart_upload({
         bucket: @bucket,
         key: upload[:key],
         upload_id: upload[:upload_id]
      })
      puts "deleted key:#{upload[:key]}"
   end
rescue => ex
   puts ex.message
end
exit

最後に

退避(バッチ処理など)中やテスト実行時など、エラーを繰り返すと意外と溜まるゴミなので、
職務上、オブジェクトストレージを担当していたこともあり、
しかたがないので、趣味でこっそり裏からチームのゴミを削除してたりします(笑)
まあいい加減飽きてきたのと、年末ということでメモを残します。
すこやかに来年を迎えましょう!良いお年を!

明日は

@blue271828さんの「なにか」です!
なんだろう!