8

(かなり大きな) ファイルを Azure BLOB ストレージに並行してアップロードする (かなり大きな) Azure アプリケーションがあります。

アップロードの数パーセントで、例外が発生します。

The specified block list is invalid.

System.Net.WebException: The remote server returned an error: (400) Bad Request.

これは、かなり無害に見えるコードを実行して、BLOB を並行して Azure ストレージにアップロードする場合です。

    public static void UploadBlobBlocksInParallel(this CloudBlockBlob blob, FileInfo file) 
    {
        blob.DeleteIfExists();
        blob.Properties.ContentType = file.GetContentType();
        blob.Metadata["Extension"] = file.Extension;

        byte[] data = File.ReadAllBytes(file.FullName);

        int numberOfBlocks = (data.Length / BlockLength) + 1;
        string[] blockIds = new string[numberOfBlocks];

        Parallel.For(
            0, 
            numberOfBlocks, 
            x =>
        {
            string blockId = Convert.ToBase64String(Guid.NewGuid().ToByteArray());
            int currentLength = Math.Min(BlockLength, data.Length - (x * BlockLength));

            using (var memStream = new MemoryStream(data, x * BlockLength, currentLength))
            {
                var blockData = memStream.ToArray();
                var md5Check = System.Security.Cryptography.MD5.Create();
                var md5Hash = md5Check.ComputeHash(blockData, 0, blockData.Length);

                blob.PutBlock(blockId, memStream, Convert.ToBase64String(md5Hash));
            }

            blockIds[x] = blockId;
        });

        byte[] fileHash  = _md5Check.ComputeHash(data, 0, data.Length);
        blob.Metadata["Checksum"] = BitConverter.ToString(fileHash).Replace("-", string.Empty);
        blob.Properties.ContentMD5 = Convert.ToBase64String(fileHash);

        data = null;
        blob.PutBlockList(blockIds);
        blob.SetMetadata();
        blob.SetProperties();
    }

すべてが非常に神秘的です。ブロックリストを計算するために使用しているアルゴリズムは、すべて同じ長さの文字列を生成するはずだと思います...

4

3 に答える 3

6

同様の問題に遭遇しましたが、ブロック ID を指定しておらず、どこでもブロック ID を使用していませんでした。私たちの場合、次のものを使用していました。

using (CloudBlobStream stream = blob.OpenWrite(condition))
{
   //// [write data to stream]

   stream.Flush();
   stream.Commit();
}

これによりThe specified block list is invalid.、並列化された負荷でエラーが発生します。UploadFromStream(…)データをメモリにバッファリングしながらメソッドを使用するようにこのコードを切り替えると、問題が修正されました。

using (MemoryStream stream = new MemoryStream())
{
   //// [write data to stream]

   stream.Seek(0, SeekOrigin.Begin);
   blob.UploadFromStream(stream, condition);
}

メモリにバッファリングされるデータが多すぎると、明らかにメモリに悪影響が及ぶ可能性がありますが、これは単純化したものです。注意すべきことの 1 つは、場合によっては をUploadFromStream(...)使用Commit()することですが、追加の条件をチェックして、使用する最適な方法を決定することです。

于 2018-10-29T21:59:26.480 に答える