【问题标题】:Why upload to Azure blob so slow?为什么上传到 Azure blob 这么慢?
【发布时间】:2018-03-13 20:15:55
【问题描述】:

我有一个自定义流,用于直接对页面云 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/ 中的 60MB/秒

【问题讨论】:

  • 如果你还没有检查,你可以检查how to efficiently upload and download page blobs
  • 谢谢,但已经检查了
  • 您没有提供完整的实现(例如,您在 Write 中使用的 Read 方法在哪里?)。另外,为什么你只测量单个语句 (_pageBlob.WritePages) 的性能,却询问整个解决方案的弱点?
  • @Evk 问题已更新

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


【解决方案1】:

和你一样,我也遇到了很多关于页面 blob 的性能问题——尽管它们并没有那么严重。看来您已经完成了作业,我可以看到您正在按部就班地做所有事情。

需要检查的几件事:

  • 确保您的 VM 没有交换(您可以签入远程桌面)。例如,如果你问我,768MB 内存的超小虚拟机对于任何实际用途来说都太小了。
  • 设置您自己的连接限制,尤其是在您运行小型 VM 时。 ServicePointManager.DefaultConnectionLimit
  • 页面越大,性能越好。
  • 在多个线程中写入(例如,使用 Tasks / async / await,尤其是当你有很多事情要做时)。

还有一件事:

  • 不要将模拟器用于这类事情。模拟器不能很好地代表真实世界的 Azure,当然可以。基准。

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

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

为什么...

您已询问“为什么”。为了理解为什么 blob 存储很慢,您需要了解它是如何工作的。首先,我想指出 Microsoft Azure 的 this presentation 解释了 Azure 存储的实际工作原理。

您应该意识到的第一件事是,Azure 存储由一组分布式(旋转)磁盘支持。由于持久性和一致性约束,它们还确保将数据写入稳定存储有“多数票”。出于性能考虑,系统的多个级别将具有缓存,其中大部分是读取缓存(同样,由于持久性限制)。

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

如果您将页面写入 blob 存储,您实际上会设置一系列 TCP/IP 连接,将页面存储在多个位置,当收到多数票时,您会向客户端返回“ok”。现在,这个系统实际上存在一些瓶颈:

  1. 您必须在整个基础架构中设置一系列 TCP/IP 连接。设置这些将花费时间。
  2. 存储的端点必须执行磁盘查找到正确的位置,并执行操作。
  3. 地理复制当然会比本地复制花费更多时间。
  4. [推测] 我们还发现在“缓冲”阶段花费了大量时间。

这里的数字 (1)、(2) 和 (3) 是众所周知的。这里的数字 (4) 实际上是 (1) 和 (2) 的结果。请注意,您不能只向旋转磁盘抛出无限数量的请求;嗯......实际上你可以,但是系统将停止运行。因此,为了解决这个问题,通常会安排来自不同客户端的磁盘查找,以便您仅在知道您也可以编写所有内容时才查找(以最大程度地减少昂贵的查找)。然而,这里有一个问题:如果你想提高吞吐量,你需要在获得所有数据之前开始寻找——如果你没有足够快地获取数据,其他请求必须等待更长时间。这里也存在一个难题:您可以为此进行优化(这有时会损害每个客户端的吞吐量并拖延其他所有人,尤其是在混合工作负载的情况下)或缓冲所有内容,然后一次查找和写入所有内容(这更容易,但增加了一些每个人的延迟)。由于 Azure 服务的客户端数量众多,我怀疑他们选择了最后一种方法——这会增加整个写入周期的延迟。

尽管如此,但大部分时间可能会花在 (1) 和 (2) 上。实际的数据突发和数据写入非常快。给你一个粗略的估计:here are some commonly used timings.

那么,这给我们留下了 1 个问题:为什么在多个线程中写东西要快得多?

原因其实很简单:如果我们在多个线程中编写内容,我们很有可能将实际数据存储在不同的服务器上。这意味着我们可以将瓶颈从“搜索 + 网络设置延迟”转移到“吞吐量”。只要我们的客户端虚拟机可以处理它,基础设施很可能也可以处理它。

【讨论】:

  • 谢谢!你能解释更多关于ensure that your VM is not swapping的信息吗?我是否需要更改要转移到 Azure blob 存储的 VM 设置(添加更多内存)?
  • @Anatoly (1) 与普通 PC 一样,如果没有足够的内存,您的虚拟机将会停止运行。 XS VM 只有 768 MB - 勉强足以运行 Windows - 更不用说做点什么了。所以是的,一个简单的方法是添加更多内存,看看它是否有帮助。 (2) 是的,你做对了;我以为我注意到了,但显然我在校对答案时删除了它。
  • 你有任何关于如何Write in multiple threads 的实际示例的链接,因为我不认为将WritePages() 更改为WritePagesAsync() 可以提高我的表现。我说的对吗?
  • @Anatoly 实际上不 - 这正是我要开始的地方。 :-) 但是,它更复杂,因为您还必须等待所有内容。
  • 是的,我的代码同:_pageBlob.WritePagesAsync(memoryStream, Position).Wait();
【解决方案2】:

如果您不介意使用文件而不是流(或者这可能支持流,但我不知道),请查看 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/

【讨论】:

  • @Anatoly - 我没有专门对它进行基准测试,但我想说它就在附近。它非常快。我认为我的限制可能在 VM 的网络上,但我猜如果不是 40,至少 30MB/s。当然比 2.4 好得多。 (试一试,这是一个十分钟的设置和测试,真的)
【解决方案3】:

要检查一件简单而快速的事情:确保您的 Blob 存储位于运行 VM 或应用程序的同一 Azure 区域中。我们遇到的一个问题是我们的存储帐户位于我们应用程序的另一个区域中。这导致我们在处理过程中出现了很大的延迟。我们一直在摸索,直到我们意识到我们正在跨地区阅读和写作。我们的菜鸟失误!

【讨论】:

  • 我在乌克兰的申请。我上传到西欧
猜你喜欢
  • 2021-02-28
  • 2012-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多