【问题标题】:Service Fabric - (reaching MaxReplicationMessageSize) Huge amount of data in a reliable dictionaryService Fabric -(达到 MaxReplicationMessageSize)可靠字典中的大量数据
【发布时间】:2016-10-12 06:31:17
【问题描述】:

编辑问题摘要:

  • 我想公开一个端点,它能够通过一些查询参数返回部分 xml 数据。
  • 我有一个全状态服务(将转换为 DTO 的 xml 数据保存到可靠的字典中)
  • 我使用单个命名分区(我只是无法通过传递的查询参数来判断哪个分区保存数据,因此我无法实现一些更智能的分区策略)
  • 我正在使用远程服务进行无状态 WEBAPI 服务和有状态服务之间的通信
  • XML 数据可能达到 500 MB
  • 当 XML 只有大约 50 MB 时一切正常
  • 当数据变大时,我 Service Fabric 抱怨 MaxReplicationMessageSize

以及我下面几个问题的总结:如何将大量数据存储到可靠的字典中?

TL 博士;

显然,我错过了什么......

  • 我想解析巨大的 XML 并将其加载到可靠的字典中,以便以后对其进行查询。
  • 我正在使用单个命名分区。
  • 我有一个 XMLData 有状态服务,它通过这种代码的和平将这个 xmls 加载到其 RunAsync 方法中的可靠字典中:

    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:复制操作大于配置的限制 - MaxReplicationMessageSize ---> System.Runtime.InteropServices.COMException

问题:

  • 我几乎可以肯定这是关于分区策略的,我需要使用更多的分区。但是如何在有状态服务的 RunAsync 方法的上下文中引用特定的分区呢? (有状态服务,通过 WebApi 中的 RPC 调用,其中我明确指出了一个分区,因此如果使用 Ranged 分区策略,我可以轻松地在分区中进行选择 - 但是在运行时初始加载数据时如何做到这一点异步方法)
  • 我的这些想法是否正确:有状态服务中的代码在单个分区上运行,因此大量数据的加载和该数据的分区应该发生在有状态服务之外(如在 Actor )。然后,在确定分区键后,我只需通过 RPC 调用有状态服务并将其指向这个特定分区

  • 实际上,这根本就是一个分区问题吗?是什么(在哪里,谁)定义了复制消息的大小?即分区策略是否会影响复制消息的大小?

  • 将加载逻辑摘录到有状态的 Actor 中是否有帮助?

对于这方面的任何帮助 - 非常感谢!

【问题讨论】:

    标签: azure azure-service-fabric


    【解决方案1】:

    问题是您试图将大量数据添加到单个字典记录中。当 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
                }))) { }
    }
    

    但我强烈建议您更改存储数据的方式。当前的方法不能很好地扩展,也不是 Reliable Collections 的本意。

    相反,您应该将每个 HospitalData 存储在单独的字典项中。然后您可以查询字典中的项目(有关如何使用 LINQ 的详细信息,请参阅this answer)。您将不需要更改上述配额。

    PS - 您不必为 500MB 的数据使用分区。但是关于您的问题 - 即使您无法从查询中派生密钥,您也可以使用分区,只需查询所有分区然后组合数据。

    【讨论】:

    • 感谢您的帮助!我实际上开始考虑对数据进行分区,将每个医院 XML 放入一个单独的分区中。现在我看到它不需要,而是我可以使用相同分区的字典,但只是将每个医院 XML 放入该字典中的单独键中。只是出于好奇-如果我想使用分区,最佳实践是什么-如何查询所有分区?我的意思是-这是在有状态服务本身的上下文中完成的,还是应该在外部完成,在调用者,即获取所有分区的调用者,逐个查询它们等。再次 - 非常感谢!
    • 外部 - 您可以使用无状态聚合器服务。您可以使用FabricClient 获取服务分区和密钥的列表。如果您想了解详细信息,请提出另一个问题:)
    • 哦,是的,一定会问! :) 将组织我的问题并在其中放入一些代码。然后将使用指向它的链接更新此评论
    • 这里是 question 枚举所有分区 :) :这次决定让它尽可能短
    • 我有一种情况,我试图将 120k+ 条记录与子记录一起存储,并且也超出了这个限制。我遇到的问题是不能单独存储每条记录,因为我需要通过 groupId 批量检索它们,而可靠的字典要求每个键都是唯一的,因此我不能使用 groupId 作为键。我查看了 github.com/jessebenson/service-fabric-indexing 库,它试图将单独的索引存储在另一个可靠的集合中,但是当我尝试遍历 120k 记录并回滚事务时遇到错误。
    猜你喜欢
    • 2019-01-08
    • 2018-12-06
    • 2017-03-20
    • 1970-01-01
    • 2017-12-08
    • 2018-04-11
    • 2017-03-28
    • 2020-04-05
    • 2016-07-23
    相关资源
    最近更新 更多