C#
Azure
ASP.NET
AzureStorage
ASP.NET_Core

Azure Blobストレージのアップロード・ダウンロード時にはチェックサム確認処理が必須


何故、チェックサム確認処理が必要か

 とあるシステムでMicrosoft Azure Storage Libraries for .NETを使ってAzure Blobストレージからファイルをダウンロードしていたのですが、


  • クライアントライブラリの処理としては正常に完了しているのに、ファイルが破損している

という事象が発生しました。

傾向を調べてみるとファイルサイズが大きくなると発生頻度が上がるようで、特に100GBytesを超えるファイルでは50%を超える頻度で問題が発生していました。

 最終的に原因はライブラリのバグで、高速化のための並列ダウンロード中に通信エラーが起きるとデータ破損が発生するというもので、ライブラリのアップデートにより、問題は収束しました。1

 この件ではダウンロード後にファイル変換処理があったおかげで問題が顕在化しましたが、例えばダウンロード後にどこか別のストレージに保存して終了という場合はすぐに問題が発覚せず、後々に大きな問題になってしまうかもしれません。処理コストとのバランスは必要ですが、ライブラリを100%信用するのではなく、ダウンロードされたファイルはアップロード前のファイルと同一のものなのか、チェックする処理は必要と思います。


Azure Blobは自動でMD5を計算してくれる

Azure BlobストレージはMD5のハッシュ値を自動で計算してくれます。


しばやん雑記:Azure Blob Storage へのアップロード時にファイルの MD5 を同時に計算して保存する


上記の記事ではリクエストオプションで指定が必要とありますが、現在ではデフォルトでこの機能がオンになっているようです。

この機能を使えば、アップロード前のファイルとダウンロード後のファイルが一致するかどうかが簡単にチェックできます。

ただし、このAzure BlobのContentMD5はあくまでAzure Blobにアップロードされたファイルに対して計算されるため、クライアント側による暗号化2を利用している場合はうまく検出できません。


解決策:独自にハッシュ値を計算してメタデータとして設定する

Azure Blobストレージでは、ファイル単位で独自のメタデータを設定することができます。3


実装例

public static async Task AddMetadataAsync(CloudBlockBlob blob,string checkSum)

{
blob.Metadata.Add("RawContentMD5", checkSum);
await container.SetMetadataAsync();
}

public static async Task<string> GetMetadataAsync(CloudBlockBlob blob)
{
await blob.FetchAttributesAsync();
string checkSum = null;
if (block.Metadata.TryGetValue("RawContentMD5", out checkSum))
{
return checkSum;
}
else
{
// 例外処理
}
}


ここに、事前に独自に計算したチェックサムを設定しておけば、少なくとも


  • アップロードする前のファイルとダウンロード後のファイルが一致するか

の確認はできます。

ただし、この方法だとファイルの暗号化はライブラリ内で行われるため、正しくアップロードされたかはダウンロードしてみないと確認できません。


まとめ

もしもの場合を考慮をし始めると、事前に計算したチェックサムは正しいのか?など、この手の問題は際限ありません。

ただ、Microsoft Azure Storage Librariesに関しては、2018年10月14日時点で最新版であるv9.3.2でもダウンロード中のファイル破損のバグ修正が入っており、ファイルのチェックは入れておくべきと思います。