使用 AppendTextAsync 追加到 Azure Append Blob 会导致数据丢失
Append to Azure Append Blob Using AppendTextAsync Results in Missing Data
我正在尝试使用新的 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 条日志,如果日志在没有警告的情况下丢失,那将是非常不可靠的。
如有任何想法或反馈,我们将不胜感激。
您使用的 async
方法不正确。 blob.AppendTextAsync()
是非阻塞的,但是当它 returns 时并没有真正完成。在退出进程之前,您应该等待所有 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();
根据@ZhaoxingLu-Microsoft 提供的信息,我现在有了一个可行的解决方案。根据 API 文档,AppendTextAsync()
方法只能用于 single-writer 场景,因为 API 内部使用 append-offset 条件 header 以避免在 multiple-writer 场景中不起作用的重复块。
这是指定此行为是设计使然的文档:
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 块,在 using 块内有一个 async/await 以等待异步追加操作在处理内存流之前完成...但这会导致完全不相关的问题。
我正在尝试使用新的 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 条日志,如果日志在没有警告的情况下丢失,那将是非常不可靠的。
如有任何想法或反馈,我们将不胜感激。
您使用的 async
方法不正确。 blob.AppendTextAsync()
是非阻塞的,但是当它 returns 时并没有真正完成。在退出进程之前,您应该等待所有 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();
根据@ZhaoxingLu-Microsoft 提供的信息,我现在有了一个可行的解决方案。根据 API 文档,AppendTextAsync()
方法只能用于 single-writer 场景,因为 API 内部使用 append-offset 条件 header 以避免在 multiple-writer 场景中不起作用的重复块。
这是指定此行为是设计使然的文档: 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 块,在 using 块内有一个 async/await 以等待异步追加操作在处理内存流之前完成...但这会导致完全不相关的问题。