【问题标题】:Service Fabric Reliable Dictionary parallel readsService Fabric 可靠字典并行读取
【发布时间】:2019-01-08 21:32:41
【问题描述】:

我有一个跨 7 个节点的集群分区的可靠字典。 [60 个分区]。我已经设置了这样的远程监听器:

var settings = new FabricTransportRemotingListenerSettings
        {
            MaxMessageSize = Common.ServiceFabricGlobalConstants.MaxMessageSize,
            MaxConcurrentCalls = 200
        };

        return new[]
        {
            new ServiceReplicaListener((c) => new FabricTransportServiceRemotingListener(c, this, settings))
        };

我正在尝试进行负载测试,以证明 Reliable Dictionary“读取”性能在负载下不会降低。我有一个像这样的字典方法“读取”:

using (ITransaction tx = this.StateManager.CreateTransaction())
        {
            IAsyncEnumerable<KeyValuePair<PriceKey, Price>> items;
            IAsyncEnumerator<KeyValuePair<PriceKey, Price>> e;

            items = await priceDictionary.CreateEnumerableAsync(tx,
                (item) => item.Id == id, EnumerationMode.Unordered);                
            e = items.GetAsyncEnumerator();

            while (await e.MoveNextAsync(CancellationToken.None))
            {
                var p = new Price(
                    e.Current.Key.Id,
                    e.Current.Key.Version, e.Current.Key.Id, e.Current.Key.Date,
                    e.Current.Value.Source, e.Current.Value.Price, e.Current.Value.Type,
                    e.Current.Value.Status);

                intermediatePrice.TryAdd(new PriceKey(e.Current.Key.Id, e.Current.Key.Version, id, e.Current.Key.Date), p);
            }
        }
return intermediatePrice;

每个分区有大约 500,000 条记录。字典中的每个“键”大约是 200 个字节,“值”大约是 600 个字节。当我直接从浏览器调用这个“读取”[调用 REST API 进而调用有状态服务]时,需要 200 毫秒。 如果我通过负载测试运行此程序,假设 16 个并行线程访问 same partitionsame record,则每次调用平均需要大约 600 毫秒。如果我将负载测试并行线程数增加到 24 或 30,则每次调用大约需要 1 秒。 我的问题是,Service Fabric Reliable Dictionary 能否处理并行“读取”操作,就像 SQL Server 可以处理并行并发读取一样,而不影响吞吐量?

【问题讨论】:

  • priceDictionary 中的项目是否唯一?

标签: c# azure-service-fabric reliable-dictionary


【解决方案1】:

如果您查看关于Reliable Dictionary CreateEnumerableAsync Method 的备注,您可以看到它被设计为并发工作,因此并发不是问题。

返回的枚举器可以安全地与读取和并发使用 写入可靠字典。它代表一个快照一致 查看

问题在于并发并不意味着

当您以这种方式进行查询时,它将:

  1. 必须在开始处理之前拍摄集合的快照,否则您将无法在处理时对其进行写入。
  2. 您必须浏览集合中的所有值才能找到您要查找的项目,并在返回任何内容之前记下这些值。
  3. 如果尚未在内存中加载数据,则从磁盘加载数据,只有 Keys 保存在内存中,值在不需要时保存在磁盘中,并且可能会被分页以释放内存。
  4. 以下查询可能(我不确定,但我假设)不会重用前一个查询,您的集合可能自上次查询以来已更改。

当您有大量以这种方式运行的查询时,会出现许多因素:

  • 磁盘:将数据加载到内存中,
  • CPU:比较值和调度线程
  • 内存:存储要处理的快照

使用 Reliable Dictionary 的最佳方法是通过键检索这些值,因为它确切地知道特定键的数据存储在哪里,并且不会增加这种额外的开销来查找它。

如果您真的想以这种方式使用它,我建议您将其设计为 Index Table,您将按 id 索引的数据存储在一个字典中,另一个字典的键是搜索值,值是主要词典的关键。这会快得多。

【讨论】:

  • 拥有双字典无法达到目的,因为我现在必须执行 1 次查询以获取与我的谓词匹配的所有键,并在循环中对检索到的值执行 TryGetAsync 并确保性能将是比在单个查询中检索要慢。我正在考虑将内存中的字典作为“并发字典”,并在更新底层字典时使用可靠的字典通知来添加/更新/删除内存中的并发字典。希望对并发字典的内存中并行查询比对 ReliableDictionaries 的异步查询更快。
  • 键查找是一种内存操作,不需要您加载整个集合来查找项目,一旦您获得项目的键,您只需再查找另一个字典.您会对差异感到惊讶。
  • 并发字典肯定会更快,因为整个集合都在内存中,并且还避免了可靠集合的开销。
  • 我使用“可靠字典”通知并使用基于键的字典查找构建内存二级索引,而不是使用“createenumerableasync”进行枚举。这允许延迟消失,因为基于“键”的查找要快得多。不利的一面是,每次重建分区时,都必须重建内存索引,并且我们需要大量的 RAM。
【解决方案2】:

根据我看到的代码,您读取的所有内容都是在 primary 副本上执行的 - 因此您有 7 个节点和 60 个处理请求的服务实例。如果我做对了,会有 60 个副本处理请求。

您有 7 个节点和 60 个副本 - 因此,如果我们想象它们在节点之间或多或少平均分布,我们每个节点有 8 个副本节点。

我不确定每个节点的物理配置,但如果我们假设每个节点有 4 个 vCPU,那么您可以想象,当您在同一个节点上发出 8 个并发请求时,所有这些请求现在都应该使用4 个虚拟 CPU。这种情况会导致工作线程争夺资源 - 保持简单会显着减慢处理速度。

这种效果在这里如此明显的原因是因为您正在扫描IReliableDictionary,而不是像应该的那样使用TryGetValueAsync 按键获取项目。

您可以尝试更改您的代码以使用TryGetValueAsync,差异会非常明显。

【讨论】:

  • 我在我的问题中提到所有“读取”都将进入 same 分区,因此是同一个节点。事实上,我每次都要求相同的记录。我希望以这种方式确保这个单个分区可以处理并发请求。我还提到,如果我从浏览器手动执行此查询,则需要 200 毫秒。 TryGetValueAsync 在我的情况下不起作用,因为我需要根据谓词过滤键。可以看到我的“Key”是一个实现了 IComparable 和 IEquatable 的 C# 对象
  • @teeboy 节点的硬件能力如何?您通过浏览器执行了多少并行请求?
  • 8 核,16 GB RAM。来自浏览器的只有 1 个请求。
  • @teeboy 这正是我所说的。当您仅从浏览器发出一个请求时,节点上不涉及并发处理 - 您的请求是它唯一忙于处理的事情。当您提出多个请求时,这些请求不会同时使用 HDD (SSD)、内存和 CPU,这就是它们每个都变慢的原因。要自己尝试,您可以修改负载测试以执行 2、4、8 和 16 和 32 个并行请求。当您有
  • 当然,我明白了。关键是,Service Fabric 被宣传为用于读写的低延迟平台。您不会谈论没有并行处理的低延迟。即使客户端负载测试中有 16 个并行线程,响应时间也从 200 毫秒变为 600 毫秒。
猜你喜欢
  • 2018-12-06
  • 2017-03-20
  • 1970-01-01
  • 2017-12-08
  • 2020-04-05
  • 2016-10-12
  • 2017-03-28
  • 2018-04-11
  • 2017-01-28
相关资源
最近更新 更多