【问题标题】:Append to Azure Append Blob Using AppendTextAsync Results in Missing Data使用 AppendTextAsync 追加到 Azure Append Blob 会导致丢失数据
【发布时间】:2015-10-12 19:41:54
【问题描述】:

我正在尝试使用新的 Azure 附加 blob 和 Azure 存储 SDK 6.0.0 为 Azure 中的应用程序创建记录器。因此,我创建了一个快速测试应用程序,以更好地了解附加 blob 及其性能特征。

我的测试程序简单地循环 100 次并将一行文本附加到附加 blob。如果我使用同步 AppendText() 方法,一切正常,但是,它似乎仅限于每秒写入大约 5-6 个追加。所以我尝试使用异步AppendTextAsync()方法;但是,当我使用此方法时,循环运行得更快(如预期的那样),但附加 blob 丢失了大约 98% 的附加文本,而没有引发任何异常。

如果我添加一个Thread.Sleep 并在每次追加操作之间休眠 100 毫秒,我最终会得到大约 50% 的数据。睡眠 1 秒,我得到所有数据。

这似乎类似于在 v5.0.0 中发现但在 v5.0.2 中修复的问题:https://github.com/Azure/azure-storage-net/releases/tag/v5.0.2

如果您想尝试重现此问题,这是我的测试代码:

static void Main(string[] args)
{
    var accountName = "<account-name>";

    var accountKey = "<account-key>;

    var credentials = new StorageCredentials(accountName, accountKey);

    var account = new CloudStorageAccount(credentials, true);

    var client = account.CreateCloudBlobClient();

    var container = client.GetContainerReference("<container-name>");

    container.CreateIfNotExists();

    var blob = container.GetAppendBlobReference("append-blob.txt");

    blob.CreateOrReplace();

    for (int i = 0; i < 100; i++)
        blob.AppendTextAsync(string.Format("Appending log number {0} to an append blob.\r\n", i));

    Console.WriteLine("Press any key to exit.");

    Console.ReadKey();
}

有谁知道我在尝试将文本行附加到附加 blob 时是否做错了什么?否则,知道为什么这会丢失数据而不会引发某种异常吗?

我真的很想开始使用它作为我的应用程序日志的存储库(因为它主要是为此目的而创建的)。但是,如果日志记录的速率超过每秒 5-6 个日志,那么日志会在没有警告的情况下丢失,那将是非常不可靠的。

任何想法或反馈将不胜感激。

【问题讨论】:

    标签: azure azure-storage azure-blob-storage


    【解决方案1】:

    根据@ZhaoxingLu-Microsoft 提供的信息,我现在有了一个可行的解决方案。根据 API 文档,AppendTextAsync() 方法只能用于单写入程序场景,因为 API 内部使用 append-offset 条件头来避免重复块,这在多写入程序场景中不起作用。

    以下是指定此行为的文档是设计使然: https://msdn.microsoft.com/en-us/library/azure/mt423049.aspx

    所以解决方案是改用AppendBlockAsync() 方法。以下实现似乎可以正常工作:

    for (int i = 0; i < 100; i++)
    {
        var message = string.Format("Appending log number {0} to an append blob.\r\n", i);
    
        var bytes = Encoding.UTF8.GetBytes(message);
    
        var stream = new MemoryStream(bytes);
    
        tasks[i] = blob.AppendBlockAsync(stream);              
    }
    
    Task.WaitAll(tasks);
    

    请注意,我没有在此示例中显式处理内存流,因为该解决方案需要在 using 块内使用带有 async/await 的 using 块,以便在处理之前等待异步追加操作完成内存流...但这会导致完全不相关的问题。

    【讨论】:

    • 这是 Azure 存储客户端库 5.0.0 中的一个 bug,已在 5.0.2 中修复:blogs.msdn.com/b/windowsazurestorage/archive/2015/09/02/…,请更新到最新版本。
    • @Zhaoxing 我很欣赏升级到 6.0.0 的建议;但是,正如我在帖子的第一段中提到的,我已经在使用 6.0.0 版本。此外,我在第一篇文章中也说明了我已经研究了 5.0.0 中存在的 bug,该 bug 已在 5.0.2 中修复。因此,除非在 6.0.0 中重新引入了相同的错误,否则这似乎是由其他原因引起的。随意使用我上面的代码使用版本 6.0.0 重现该问题,以确认您是否愿意。同时,我可能会尝试降级到 5.0.2 版本,看看之前的版本是否存在问题。
    • CloudAppendBlob.AppendTextAsync() 的文档标头中提到:“此 API 应严格在单个编写器场景中使用,因为该 API 内部使用附加偏移量条件标头以避免重复块不起作用在多作家场景中。”我猜你遇到的问题是设计使然。
    • @ZhaoxingLu-Microsoft,这是我一直在寻找的缺失信息。这就解释了为什么这没有像我预期的那样工作。此外,它还确认该行为不是错误,而实际上是设计使然。我将更新解决方案以包含您的新信息,为您的帖子和 cmets 提供积分,在解决方案中归功于您,并将解决方案标记为已接受的答案。我还将更新我在 GitHub 上使用 Azure 存储 SDK 项目记录的问题。感谢您的所有帮助!
    【解决方案2】:

    您错误地使用了async 方法。 blob.AppendTextAsync() 是非阻塞的,但它在返回时并没有真正完成。在退出进程之前,您应该等待所有 async 任务。

    以下代码是正确用法:

    var tasks = new Task[100];
    for (int i = 0; i < 100; i++)
        tasks[i] = blob.AppendTextAsync(string.Format("Appending log number {0} to an append blob.\r\n", i));
    
    Task.WaitAll(tasks);
    
    Console.WriteLine("Press any key to exit.");
    
    Console.ReadKey();
    

    【讨论】:

    • 我按照指定尝试了您的解决方案;不幸的是,它抛出了一个带有内部异常消息的聚合异常:“远程服务器返回错误:(412) 未满足指定的附加位置条件。” 我同意你的看法,我需要等待异步任务完成,但我认为AppendTextAsync() 方法或我使用它的方式还有其他问题。
    猜你喜欢
    • 2022-08-02
    • 2013-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多