为什么上传到Azure blob这么慢?

时间:2016-04-19 09:33:59

标签: c# performance azure azure-storage-blobs

我有一个自定义流,用于直接在页面云blob中执行写操作。

public sealed class WindowsAzureCloudPageBlobStream : Stream
{
    // 4 MB is the top most limit for page blob write operations
    public const int MaxPageWriteCapacity = 4 * 1024 * 1024;

    // Every operation on a page blob has to manipulate a value which is rounded up to 512 bytes
    private const int PageBlobPageAdjustmentSize = 512;

    private CloudPageBlob _pageBlob;

    public override void Write(byte[] buffer, int offset, int count)
    {
        var additionalOffset = 0;
        var bytesToWriteTotal = count;

        List<Task> list = new List<Task>();
        while (bytesToWriteTotal > 0)
        {
            var bytesToWriteTotalAdjusted = RoundUpToPageBlobSize(bytesToWriteTotal);

            // Azure does not allow us to write as many bytes as we want
            // Max allowed size per write is 4MB
            var bytesToWriteNow = Math.Min((int)bytesToWriteTotalAdjusted, MaxPageWriteCapacity);
            var adjustmentBuffer = new byte[bytesToWriteNow];
            ...
            var memoryStream = new MemoryStream(adjustmentBuffer, 0, bytesToWriteNow, false, false);
            var task = _pageBlob.WritePagesAsync(memoryStream, Position, null);
            list.Add(task);
        }

        Task.WaitAll(list.ToArray());
    }

    private static long RoundUpToPageBlobSize(long size) 
    { 
        return (size + PageBlobPageAdjustmentSize - 1) & ~(PageBlobPageAdjustmentSize - 1); 
    }

我的Write()效果不佳。例如:

Stopwatch s = new Stopwatch();
s.Start();
using (var memoryStream = new MemoryStream(adjustmentBuffer, 0, bytesToWriteNow, false, false))
{
      _pageBlob.WritePages(memoryStream, Position);
}

s.Stop();
Console.WriteLine(s.Elapsed); => 00:00:01.52 == Average speed 2.4 MB/s

如何改进算法? 如何使用Parallel.ForEach来加速这个过程?

为什么只有2.5 MB /秒,而不是official sitehttp://blogs.microsoft.co.il/applisec/2012/01/05/windows-azure-benchmarks-part-2-blob-write-throughput/

中的60 MB /秒

3 个答案:

答案 0 :(得分:10)

和你一样,我也有很多关于页面blob的性能问题 - 尽管它们不是很严重。看起来你已经完成了你的功课,我可以看到你在书中做了一切。

要检查的一些事项:

  • 确保您的虚拟机没有交换(您可以登录远程桌面)。例如,如果您问我,超小型768MB内存VM实际上太小,无法满足任何实际用途。
  • 设置您自己的连接限制,尤其是在您运行小型VM的情况下。 ServicePointManager.DefaultConnectionLimit
  • 较大的页面会为您提供更多性能。
  • 写入多个帖子(例如,使用Task s / async / await,特别是如果您有很多事情要做的话。)

哦,还有一件事:

  • 不要将模拟器用于这些事情。模拟器不是真实世界Azure的良好代表,绝对是wrt。基准。

您访问时间较慢的主要原因是因为您正在同步执行所有操作。 microsoft的基准测试可以访问多个线程中的blob,这将提供更多的吞吐量。

现在,Azure也知道性能是一个问题,这就是他们尝试通过本地缓存支持存储来缓解问题的原因。这里基本上发生的是他们将数据写入本地(f.ex.在文件中),然后将任务切成碎片然后使用多个线程将所有内容写入blob存储。数据存储运动库就是这样一个库。但是,在使用它们时,您应该始终牢记这些具有不同的持久性限制(它就像在本地PC上启用和写入缓存一样)并且可能会破坏您打算设置分布式的方式系统(如果您从多个VM读取和写入相同的存储空间)。

为什么...

你已经问过为什么&#39;。为了理解blob存储缓慢的原因,您需要了解它的工作原理。首先,我想指出Microsoft Azure中有this presentation解释了Azure存储的实际工作方式。

您应该意识到的第一件事是Azure存储由一组分布式(旋转)磁盘支持。由于耐用性和一致性的限制,他们还确保有多数投票权和#39;将数据写入稳定存储。对于性能,系统的几个级别将具有缓存,这些缓存主要是读取缓存(同样,由于持久性限制)。

现在,Azure团队并没有发布所有内容。幸运的是,5年前,我以前的公司在较小规模上创建了一个类似的系统。我们遇到类似Azure的性能问题,系统与我上面提到的演示文稿非常相似。因此,我想我可以解释和推测瓶颈在哪里。为清楚起见,我将部分标记为我认为合适的推测。

如果您将页面写入Blob存储,您实际上设置了一系列TCP / IP连接,将页面存储在多个位置,并且当收到多数投票时,您可以提供“确定”。回到客户端。现在,这个系统实际上存在一些瓶颈:

  1. 您必须在整个基础架构中设置一系列TCP / IP连接。设置这些将花费时间。
  2. 存储的端点必须执行磁盘搜索到正确的位置,然后执行操作。
  3. 地理复制当然比本地复制需要更多时间。
  4. [推测]我们还发现在缓冲期间花了很多时间。相。
  5. 这里的数字(1),(2)和(3)是众所周知的。这里的数字(4)实际上是(1)和(2)的结果。请注意,您不能仅向旋转磁盘抛出无限数量的请求;嗯...实际上你可以,但随后系统将停止运转。因此,为了解决这个问题,来自不同客户端的磁盘搜索通常以这样一种方式安排,即只要您知道自己也可以编写所有内容(以最大限度地减少昂贵的搜索)。但是,这里存在一个问题:如果你想提高吞吐量,你需要在拥有所有数据之前开始寻找 - 如果你没有足够快地获得数据,其他请求必须等待更长时间。这也是一个两难的问题:你可以为此进行优化(这有时会损害每个客户端的吞吐量并阻止其他所有人,特别是对于混合工作负载)或缓冲所有内容然后寻求&amp;一次写一切(这更容易,但为每个人增加了一些延迟)。由于Azure提供了大量客户端,我怀疑他们选择了最后一种方法 - 这为整个写周期增加了更多延迟。

    尽管如此,大部分时间可能会由(1)和(2)花费。实际的数据突发和数据写入非常快。为了粗略估计一下:here are some commonly used timings

    所以,这给我们留下了一个问题:为什么在多个线程中写东西的速度要快得多?

    其原因实际上非常简单:如果我们在多个线程中编写内容,那么我们很有可能将实际数据存储在不同的服务器上。这意味着我们可以改变我们的瓶颈,从而寻求+网络设置延迟&#34;到&#34;吞吐量&#34;。只要我们的客户端VM可以处理它,基础设施很可能也可以处理它。

答案 1 :(得分:4)

如果您不介意处理文件而不是流(或者这可能有流支持而且我不知道它),请查看Azure存储数据移动库。这是迄今为止我见过的最好的。

这是相对较新的(在撰写本文时),但非常好地支持以块的形式移动大型文件并最大化吞吐量(我将其用于夜间复制SQL备份,其中许多超过1GB)。

https://azure.microsoft.com/en-us/blog/announcing-azure-storage-data-movement-library-0-2-0/

使用非常简单。这是一个例子:

using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.WindowsAzure.Storage.DataMovement;


namespace BlobUploader
{
    public class Uploader
    {

        public string ConnectionString { get; set; }
        public string ContainerName { get; set; }
        public string BlobName { get; set; }

        public void UploadFile(string filePath) {

            CloudStorageAccount account = CloudStorageAccount.Parse(ConnectionString);
            CloudBlobClient blobClient = account.CreateCloudBlobClient();
            CloudBlobContainer blobContainer = blobClient.GetContainerReference(ContainerName);
            blobContainer.CreateIfNotExists();
            CloudBlockBlob destinationBlob = blobContainer.GetBlockBlobReference(BlobName);

            TransferManager.Configurations.ParallelOperations = 64;

            TransferContext context = new TransferContext();
            context.ProgressHandler = new Progress<TransferProgress>((progress) => {
                Console.WriteLine("Bytes uploaded: {0}", progress.BytesTransferred);
            });

            var task = TransferManager.UploadAsync(filePath, destinationBlob, null, context, CancellationToken.None);
            task.Wait();   
        }


    }
}

下面的预览博客文章提供了一些关于它是如何产生以及它如何处理一般事物的信息:

https://azure.microsoft.com/en-us/blog/introducing-azure-storage-data-movement-library-preview-2/

答案 2 :(得分:1)

要检查的一个简单快速的事情:确保您的blob存储位于运行VM或应用程序的同一Azure区域中。我们遇到的一个问题是我们的存储帐户位于我们应用程序的另一个区域。这导致我们在处理期间出现显着延迟。在我们意识到我们正在跨地区阅读和写作之前,我们正在摸不着头脑。我们的新秀错误了!