【问题标题】:Executing queries being timing out after having performed many queries在执行了许多查询后执行查询超时
【发布时间】:2019-07-26 23:42:18
【问题描述】:

我在一个表上异步执行查询,有一段时间一切都很好,但突然之间查询开始超时。

简而言之,我有一个包含多个 ID 的文本文件,对于每个 ID,我想在表中执行查询。查询本身不应该花费很长时间,少于 5 秒,但是在成功执行许多查询后,应用程序突然开始每次超时。如果我然后重新启动我的应用程序并重新运行超时的 ID,它们现在可以完美运行而没有问题。

假设我有一个 1000 个 ID 的列表,然后它在处理并成功执行 200 个 ID 后开始超时。

我已尝试插入一个 MaximumExecutionTime 并将其设置为远高于标准的 5 秒,但它仍然超时。我试过不共享 CloudTableClients,只是让每个“线程”创建一个新实例。

代码是一个较大项目的一部分,因此我将在此处包含相关部分并省略一些其他代码。我首先创建一个 CloudTableClient,它在不同的任务之间共享,好像我理解正确一样,可以共享它。然后我有一个 ActionBlock,我将 ID 发布到。我将 MaxDegreeOfParallelism 限制为我有多少个处理器,我在这方面有最好的体验。

CloudStorageAccount cloudStorage = CloudStorageAccount.Parse(_ParsedConnectionString);
CloudTableClient tableClient = cloudStorage.CreateCloudTableClient();

var block = new ActionBlock<int>(
  async id =>
  {
    // Do stuff
    var res = await executeQuery(id, tableClient);
    // Do more stuff
  },
  new ExecutionDataflowBlockOptions
  {
    MaxDegreeOfParallelism = Environment.ProcessorCount
  }
);

StreamReader file = new StreamReader(someFile);
string line;
while ((line = file.ReadLine()) != null)
{
  block.Post(Convert.ToInt32(line));
}
block.Complete();
block.Completion.Wait();

而在executeQuery函数中:

CloudTable table = tableClient.GetTableReference(_someTable);

var tableQuery = new TableQuery<SomeEntity>
{
  FilterString = "some query"
};

TableContinuationToken continuationToken = null;
TableRequestOptions options = new TableRequestOptions
{
  MaximumExecutionTime = new TimeSpan(0, 2, 0)
};
OperationContext context = new OperationContext();

do
{
  var tableQueryResult = await table.ExecuteQuerySegmentedAsync(tableQuery, continuationToken, options, context);
  continuationToken = tableQueryResult.ContinuationToken;
  // Do stuff
}
while (continuationToken != null);

查询很好,就好像我使用之前超时的 ID 重新运行应用程序一样,它按预期运行。

The client could not finish the operation within specified timeout.
at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.EndExecuteAsync[T](IAsyncResult result) in c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Core\Executor\Executor.cs:line 51
   at Microsoft.WindowsAzure.Storage.Core.Util.AsyncExtensions.<>c__DisplayClass2`1.<CreateCallback>b__0(IAsyncResult ar) in c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Core\Util\AsyncExtensions.cs:line 69
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at App.Parser.<executeQuery>d__25.MoveNext()`

【问题讨论】:

    标签: c# async-await task-parallel-library azure-storage


    【解决方案1】:

    根据您获得的异常,您的查询正在针对 AzureStorage 运行。存储上的某些操作受到数量/分钟配额的限制。

    基本上读/写几乎是无限的,但管理是。

    例如,如果在您的每个请求中您首先尝试获取存储密钥,那么您可能会达到限制,然后 azure 会限制您(这可能会导致超时,因为限制是每分钟)。

    【讨论】:

    • 但如果是这样,那为什么重新运行应用程序会解决这个问题呢?有没有办法让我在不重新运行应用程序的情况下达到相同的效果?
    • 如果我没记错上次遇到这个问题,节流大约是 800/分钟。如果您有 1000 个元素,那么您可能可以在第一批中完成大部分并在第二批中完成。尝试将您的列表分成多个块(比如说 100 个)并运行每个块,然后在每个块之间等待 30 秒。如果这样可以解决问题,那么您可能需要查看客户端内部以了解哪个请求受到限制。
    • 谢谢。我最终通过将我的列表分成块然后一起查询它们来解决这个问题。这需要付出更多的努力,但这是值得的。
    【解决方案2】:

    CloudStorageAccountCloudTableClientCloudTable 都不是线程安全的。

    仍在记录CloudTableClient 的少数参考文献,例如CloudTableClient.ListTables Method (),都有以下免责声明:

    这种类型的任何公共静态(在 Visual Basic 中为 Shared)成员都是线程安全的。不保证任何实例成员都是线程安全的。

    您的 cloudStoragetableClient 实例可能会被线程破坏,这就是重新启动进程修复它的原因。

    【讨论】:

      猜你喜欢
      • 2019-01-01
      • 2013-07-23
      • 2018-10-24
      • 1970-01-01
      • 2012-04-02
      • 1970-01-01
      • 2017-08-04
      • 1970-01-01
      • 2016-02-26
      相关资源
      最近更新 更多