我有一个可靠的字典,分布在由7个节点组成的群集中。 [60个分区]。我已经设置了像这样的远程侦听器:
var settings = new FabricTransportRemotingListenerSettings
{
MaxMessageSize = Common.ServiceFabricGlobalConstants.MaxMessageSize,
MaxConcurrentCalls = 200
};
return new[]
{
new ServiceReplicaListener((c) => new FabricTransportServiceRemotingListener(c, this, settings))
};
我正在尝试进行负载测试,以证明可靠的字典“读取”性能在负载下不会降低。我从这样的字典方法中读取了一个信息:
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个并行线程达到相同分区和相同记录)运行此操作,则每次调用平均需要花费600毫秒。如果将负载测试并行线程数增加到24或30,则每个调用大约需要1秒。 我的问题是,服务结构可靠字典可以像SQL Server一样处理并行并发读取,而又不影响吞吐量吗?
答案 0 :(得分:0)
根据代码,我看到的所有内容都是在主副本上执行的-因此,您有7个节点和60个处理请求的服务实例。如果一切正常,就会有 60 个副本处理请求。
您有 7 个节点和 60 个副本-因此,如果我们认为它们在节点之间或多或少地平均分布,则每个副本有 8 个副本节点。
我不确定每个节点的物理配置,但是如果暂时假设每个节点具有4个vCPU,那么您可以想象,当您在同一节点上发出8个并发请求时,现在所有这些请求都应使用4个vCPU。这种情况导致工作线程争夺来获取资源-保持简单会大大减慢处理速度。
此效果之所以如此明显,是因为您正在扫描 IReliableDictionary
,而不是像想象中的那样使用TryGetValueAsync通过按键获取项目。
您可以尝试将代码更改为使用TryGetValueAsync
,两者之间的区别将非常明显。
答案 1 :(得分:0)
如果您查看关于Reliable Dictionary CreateEnumerableAsync Method的备注,您会发现它被设计为可同时工作,因此并发不是问题。
返回的枚举数可以安全地与reads和 写入可靠字典。它表示快照一致 查看
问题在于, 同时 并不意味着 快速
以这种方式进行查询时,它将:
当您以这种方式运行大量查询时,许多因素都会发生:
使用“可靠字典”的最佳方法是通过“键”检索这些值,因为它确切知道特定键的数据存储在何处,并且不会增加查找这些键的额外开销。
如果您真的想以这种方式使用它,建议您像Index Table那样设计它,在其中将按id索引的数据存储在一个Dictionary中,另一把以关键字为搜索值的字典中存储,价值是主要数字的关键。这样会更快。