Service Fabric -(达到 MaxReplicationMessageSize)可靠字典中的大量数据
Service Fabric - (reaching MaxReplicationMessageSize) Huge amount of data in a reliable dictionary
编辑 问题总结:
- 我想公开一个端点,它将能够通过某些查询参数返回部分 xml 数据。
- 我有一个全状态服务(将转换为 DTO xml 的数据保存到可靠的字典中)
- 我使用单个命名分区(我只是无法通过传递的查询参数判断哪个分区保存数据,所以我无法实施一些更智能的分区策略)
- 我正在使用服务远程处理在无状态 WEBAPI 服务和有状态服务之间进行通信
- XML 数据可能达到 500 MB
- 当 XML 只有大约 50 MB
时一切正常
- 当数据变大时,我的 Service Fabric 抱怨 MaxReplicationMessageSize
我的几个问题总结如下:如何将大量数据存储到可靠的字典中?
TL DR;
显然,我遗漏了一些东西...
- 我想解析并加载到一个可靠的字典中,巨大的 XMLs 供以后查询。
- 我正在使用一个命名分区。
我有一个 XML 数据有状态服务,它通过这段代码和平将此 xml 加载到其 运行 异步方法中的可靠字典中:
var myDictionary = await this.StateManager.GetOrAddAsync<IReliableDictionary<string, List<HospitalData>>>("DATA");
using (var tx = this.StateManager.CreateTransaction())
{
var result = await myDictionary.TryGetValueAsync(tx, "data");
ServiceEventSource.Current.ServiceMessage(this, "data status: {0}",
result.HasValue ? "loaded" : "not loaded yet, starts loading");
if (!result.HasValue)
{
Stopwatch timer = new Stopwatch();
timer.Start();
var converter = new DataConverter(XmlFolder);
List <Data> data = converter.LoadData();
await myDictionary.AddOrUpdateAsync(tx, "data", data, (key, value) => data);
timer.Stop();
ServiceEventSource.Current.ServiceMessage(this,
string.Format("Loading of data finished in {0} ms",
timer.ElapsedMilliseconds));
}
await tx.CommitAsync();
}
我有一个无状态 WebApi 服务,它通过 service remoting 与上述有状态服务通信,并通过以下代码查询字典:
ServiceUriBuilder builder = new ServiceUriBuilder(DataServiceName);
DataService DataServiceClient = ServiceProxy.Create<IDataService>(builder.ToUri(),
new Microsoft.ServiceFabric.Services.Client.ServicePartitionKey("My.single.named.partition"));
try
{
var data = await DataServiceClient.QueryData(SomeQuery);
return Ok(data);
}
catch (Exception ex)
{
ServiceEventSource.Current.Message("Web Service: Exception: {0}", ex);
throw;
}
当 XML 不超过 50 MB 时效果很好。
- 之后我得到如下错误:
System.Fabric.FabricReplicationOperationTooLargeException: The replication operation is larger than the configured limit - MaxReplicationMessageSize ---> System.Runtime.InteropServices.COMException
问题:
- 我几乎可以肯定是分区策略的问题,我需要使用更多的分区。但是如何在有状态服务的 运行Async 方法的上下文中引用特定分区? (有状态服务是通过 WebApi 中的 RPC 调用的,我在其中明确指出了一个分区,因此如果使用 Ranged 分区策略,我可以在其中轻松地在分区之间进行选择 - 但是如何在 运行 异步方法)
我的这些想法是否正确:有状态服务中的代码在单个分区上运行,因此大量数据的加载和数据的分区应该发生在有状态服务之外(就像在演员中一样)。然后,在确定分区键后,我只是通过 RPC 调用有状态服务并将其指向这个特定分区
实际上这完全是一个分区问题,什么(在哪里,谁)定义了复制消息的大小?即分区策略是否影响复制消息大小?
将加载逻辑摘录到有状态的 Actor 中会有任何帮助吗?
对于这方面的任何帮助 - 非常感谢!
问题是您试图将大量数据添加到单个字典记录中。当 Service Fabric 尝试将该数据复制到服务的其他副本时,它遇到了复制器的配额 MaxReplicationMessageSize
,它确实默认为 50MB(已记录 here)。
您可以通过指定 ReliableStateManagerConfiguration
:
来增加配额
internal sealed class Stateful1 : StatefulService
{
public Stateful1(StatefulServiceContext context)
: base(context, new ReliableStateManager(context,
new ReliableStateManagerConfiguration(new ReliableStateManagerReplicatorSettings
{
MaxReplicationMessageSize = 1024 * 1024 * 200
}))) { }
}
但我强烈建议您改变存储数据的方式。当前的方法不会很好地扩展,也不是可靠集合的使用方式。
相反,您应该将每个 HospitalData
存储在单独的字典项中。然后您可以查询字典中的项目(有关如何使用 LINQ 的详细信息,请参阅 )。您将不需要更改上述配额。
PS - 您不一定非要对 500MB 的数据使用分区。但是关于你的问题——即使你不能从查询中导出键,你也可以使用分区,只需查询所有分区然后组合数据。
编辑 问题总结:
- 我想公开一个端点,它将能够通过某些查询参数返回部分 xml 数据。
- 我有一个全状态服务(将转换为 DTO xml 的数据保存到可靠的字典中)
- 我使用单个命名分区(我只是无法通过传递的查询参数判断哪个分区保存数据,所以我无法实施一些更智能的分区策略)
- 我正在使用服务远程处理在无状态 WEBAPI 服务和有状态服务之间进行通信
- XML 数据可能达到 500 MB
- 当 XML 只有大约 50 MB 时一切正常
- 当数据变大时,我的 Service Fabric 抱怨 MaxReplicationMessageSize
我的几个问题总结如下:如何将大量数据存储到可靠的字典中?
TL DR;
显然,我遗漏了一些东西...
- 我想解析并加载到一个可靠的字典中,巨大的 XMLs 供以后查询。
- 我正在使用一个命名分区。
我有一个 XML 数据有状态服务,它通过这段代码和平将此 xml 加载到其 运行 异步方法中的可靠字典中:
var myDictionary = await this.StateManager.GetOrAddAsync<IReliableDictionary<string, List<HospitalData>>>("DATA"); using (var tx = this.StateManager.CreateTransaction()) { var result = await myDictionary.TryGetValueAsync(tx, "data"); ServiceEventSource.Current.ServiceMessage(this, "data status: {0}", result.HasValue ? "loaded" : "not loaded yet, starts loading"); if (!result.HasValue) { Stopwatch timer = new Stopwatch(); timer.Start(); var converter = new DataConverter(XmlFolder); List <Data> data = converter.LoadData(); await myDictionary.AddOrUpdateAsync(tx, "data", data, (key, value) => data); timer.Stop(); ServiceEventSource.Current.ServiceMessage(this, string.Format("Loading of data finished in {0} ms", timer.ElapsedMilliseconds)); } await tx.CommitAsync(); }
我有一个无状态 WebApi 服务,它通过 service remoting 与上述有状态服务通信,并通过以下代码查询字典:
ServiceUriBuilder builder = new ServiceUriBuilder(DataServiceName); DataService DataServiceClient = ServiceProxy.Create<IDataService>(builder.ToUri(), new Microsoft.ServiceFabric.Services.Client.ServicePartitionKey("My.single.named.partition")); try { var data = await DataServiceClient.QueryData(SomeQuery); return Ok(data); } catch (Exception ex) { ServiceEventSource.Current.Message("Web Service: Exception: {0}", ex); throw; }
当 XML 不超过 50 MB 时效果很好。
- 之后我得到如下错误:
System.Fabric.FabricReplicationOperationTooLargeException: The replication operation is larger than the configured limit - MaxReplicationMessageSize ---> System.Runtime.InteropServices.COMException
问题:
- 我几乎可以肯定是分区策略的问题,我需要使用更多的分区。但是如何在有状态服务的 运行Async 方法的上下文中引用特定分区? (有状态服务是通过 WebApi 中的 RPC 调用的,我在其中明确指出了一个分区,因此如果使用 Ranged 分区策略,我可以在其中轻松地在分区之间进行选择 - 但是如何在 运行 异步方法)
我的这些想法是否正确:有状态服务中的代码在单个分区上运行,因此大量数据的加载和数据的分区应该发生在有状态服务之外(就像在演员中一样)。然后,在确定分区键后,我只是通过 RPC 调用有状态服务并将其指向这个特定分区
实际上这完全是一个分区问题,什么(在哪里,谁)定义了复制消息的大小?即分区策略是否影响复制消息大小?
将加载逻辑摘录到有状态的 Actor 中会有任何帮助吗?
对于这方面的任何帮助 - 非常感谢!
问题是您试图将大量数据添加到单个字典记录中。当 Service Fabric 尝试将该数据复制到服务的其他副本时,它遇到了复制器的配额 MaxReplicationMessageSize
,它确实默认为 50MB(已记录 here)。
您可以通过指定 ReliableStateManagerConfiguration
:
internal sealed class Stateful1 : StatefulService
{
public Stateful1(StatefulServiceContext context)
: base(context, new ReliableStateManager(context,
new ReliableStateManagerConfiguration(new ReliableStateManagerReplicatorSettings
{
MaxReplicationMessageSize = 1024 * 1024 * 200
}))) { }
}
但我强烈建议您改变存储数据的方式。当前的方法不会很好地扩展,也不是可靠集合的使用方式。
相反,您应该将每个 HospitalData
存储在单独的字典项中。然后您可以查询字典中的项目(有关如何使用 LINQ 的详细信息,请参阅
PS - 您不一定非要对 500MB 的数据使用分区。但是关于你的问题——即使你不能从查询中导出键,你也可以使用分区,只需查询所有分区然后组合数据。