これまでバックアップ先にAmazon S3を使っていた部分をAzureストレージに置き換えたのでメモ。BLOBストレージを使用。
ファイルサイズ制限
BLOBストレージは64MBまでのファイルならば一つのファイルとしてアップロードすることができるけど、それよりも大きい場合は最大4MBのブロックとしてアップロードしてからコミットしなければならない。
今回対象となるファイルは800MBくらいあるのでブロックとしてアップロードする必要がある。
Gemfile
GemfileにSDKを追加。
gem 'aws-sdk'
Azureストレージとの接続
Azureストレージの管理画面下のアクセスキーの管理ボタンで作成したアクセスキーを使う。
ActiveDirectoryを使えばAmazonIAMみたいに局所的な権限の割当とかできるんですかね。
require 'azure'
Azure.storage_account_name = "<STORAGE_ACCOUNT_NAME>"
Azure.storage_access_key = "<STORAGE_ACCESS_KEY>"
実装
ファイルを開いて4MB読み出し毎にブロックの作成のAPIを叩くだけの単純な実装。
File.open(file, 'rb') do |f|
i = 0
block_ids = []
loop do
# 4MBずつ処理
content = f.read(4 * 1024 * 1024)
break if content.nil?
# ブロックIDの生成
i += 1
block_id = "%07d"%[i]
block_ids << [block_id]
# ブロックのアップロード
Azure.blobs.create_blob_block(container_name, blob_name, block_id, content)
end
# アップロードしたブロックのコミット
Azure.blobs.commit_blob_blocks(container_name, blob_name, block_ids)
end
ブロックの残骸?
ある時から、アップロードしようとすると The specified blob or block content is invalid なるエラーが出るようになってしまった。どうも、途中で中断をして未コミットのブロックが残った状態になると、同名のBLOBをアップロードしようとするとエラーになるっぽい。
ということでアップロード前に削除することにした。ファイルの存在確認をしようかとも思ったけど、面倒だったので強制削除でファイルがない例外の場合は無視するようにした。
既存のアップロードファイルを上書きする場合は削除したもののアップロードも失敗するということも起こりえるのでサーバ側でリネームしておくなりの対応が必要。
# 同名のファイルを削除しておく
begin
Azure.blobs.delete_blob(container_name, blob_name)
rescue ::Azure::Core::Http::HTTPError => e
# 同名のファイルがない場合は無視
raise e if e.type != "BlobNotFound"
end
感想
AmazonS3みたいに自動で期限切れに出来ないのつらい。
分割アップロードに対応してくれるのは良いけどSDK側で勝手にやってほしい。