用于协调本地集群和网络集群的最佳.Net参与者/过程框架



我们有一个过程,包括加载一大块数据,对其应用一些转换,然后输出更改的内容。我们目前运行的web应用程序在同一CLR实例中处理这些大块数据的多个实例,这会导致垃圾收集混乱和OOM错误。

我们已经证明,在较长的运行过程中托管一些跟踪状态可以完美地解决我们的主要问题。我们现在面临的问题是,作为一个有状态的系统,我们需要托管它,并管理与系统其他部分的协调(以及更改跟踪实例)。

我目前正在评估Actors in Service Fabric和Akka,还有很多其他选择,但在我继续之前,我想让人们对这种方法有以下考虑:

  • 我们的系统中有一个自然的分区点(Authority),这意味着我们可以轻松地划分顶级数据集。每个分区将由一个顶级实例表示,该实例需要在自己的本地集群中组织几个子参与者,但我们希望单个主机能够运行多个集群。

  • 理想情况下,每个参与者的Authority Cluster都将托管在一台机器上,以受益于本地通信和一些共享本地资源的使用,从而绕过消息大小的限制。

  • 参与者本身应该是同一个盒子上的独立进程(Akka似乎在同一个CLR实例中运行本地参与者,这会使OOM上的一切崩溃-这是真的吗?),这将使我能够在不影响其他实例内存/GC的情况下旋转一个进程,通过它运行转换,发出结果并将其拆除。我理解硬件资源争用仍然是一个问题,但我预计这将是比CPU更密集的内存,所以预计RAM会很重。

  • 由于数据模型相当大,并且消息可以包含模型片段或对模型片段的更改,因此很难使用不变性。我们不想将每个消息有效负载克隆到内部状态并将其应用于模型,因此理想情况下,所使用的任何actor解决方案都将使我们能够使用原始消息有效负载。这可能会导致在恢复参与者状态时出现问题,因为它希望在唤醒时保存和回放这些状态,但由于我们在内部进行状态跟踪,我们只能在睡眠时存储由此产生的输出。

  • 我们需要一个能够启动权威集群实例的协调器。虚拟机/机器的数量和托管在其上的授权集群的数量需要有一定的弹性,并且需要处理这些集群的创建和销毁。

  • 我们有很多的.NET代码,我们所有的模型、转换和验证都在其中定义,需要大量重复使用。支持.Net 所需的任何解决方案

我的问题是:

虽然这感觉很适合演员,但我有所保留,想知道是否有更合适的东西?我所尝试的一切都回到了某种托管过程中。

如果演员是正确的选择,那么考虑到上述问题,哪个技术堆栈会让我最接近我试图实现的目标?

IMO(从JVM Akka的角度来看,因此我将akka标记更改为akka.net;我对CLR方面的知识不多),之间似乎不匹配

我们不想将每个消息有效负载克隆到内部状态并将其应用于模型,因此理想情况下,使用的任何actor解决方案都将使我们能够使用原始消息有效负载。

参与者本身应该是同一个盒子上的独立进程(Akka似乎在同一CLR实例中运行本地参与者,这会使OOM上的一切崩溃-这是真的吗?)

假设您谈论的是同一个操作系统进程,它们几乎肯定是相互不兼容的:交换消息强烈建议序列化,因此同构于复制操作。在操作系统进程之间使用共享内存的东西可能会起作用,但你可能必须选择哪个更重要。

同样地;传统的";(Erlang/Akka)风格的actor模型简单地为您提供了本地actor集群(由于它们在同一操作系统进程中运行,因此允许Akka优化,在您跨越操作系统进程边界之前不复制消息),而";虚拟演员";ServiceFabric或Orleans(或者,我认为是Cloudstate或Lagom)中的实现基本上假设分布。

从语义上讲,虚拟演员模型隐含地假设演员是永恒的(尽管他们永恒的本质可能并不总是化身)。对于您的用例,情况似乎并不一定如此。

我想是一群阿卡人。具有分片Authority参与者的网络实例最适合生成寿命较短的子参与者,假设您在尝试同时处理多个大块数据时遇到OOM问题。您必须自己实现实例放大/缩小逻辑。

我没有使用过Akka.net,所以我根本不能谈论它,但我很乐意谈论您在Service Fabric上下文中谈论的内容。

  • ServiceFabric对运行多个集群的概念没有任何问题。在其术语中,整个系统将被称为应用程序,并且在部署到SF集群时会有一个版本。如果你想创建它的多个实例,你所需要做的就是选择你想称之为部署的应用程序实例的东西,它会为你提供支持。

  • SF有一个放置约束、度量平衡和自定义规则的概念,如果你认为你可以比它的自动平衡更好地平衡各种资源(或者你需要用于网络DMZ目的),你可以使用这些概念。虽然我从未亲自将事情分组到一台机器上,但我经常将服务访问限制在单个VM规模集(我们在Azure中托管)。

  • 不过,到最后一点,您仍然有消息大小限制,但您也可以在一定程度上覆盖它们。在包含服务接口的项目中,只需在命名空间上方设置以下属性:[assembly:FabricTransportRemotingSettings(MaxMessageSize=<(long)new size in bytes>)],你可以走了。

  • 服务可以配置为使用共享或独占进程模型运行。

  • 关于你的状态要求,我不一定清楚你想做什么,但我认为你是在说,你的参与者存储任何状态并不重要,因为他们可以从某个集中提供的模型中工作。

然后您可能会看到易失性状态持久性,因为这意味着该状态会保存在内存中供参与者使用,但如果您丢失了副本,则不会向磁盘写入任何内容,因此会全部丢失。或者,如果您不在乎,并且可以将模型发送给任何工作的参与者,则可以将其配置为无状态。

  • 另一方面,如果您仍然希望在actor中保留状态,并且只是关心不变性,请放心,actor状态不是不可变的,可以简单地更新。你需要记住的只是操作顺序问题(例如,如果你检索状态、进行更改、保存它,1)你必须提交事务才能进行,2)如果你修改了状态但不保存,它显然不会持久存在-在新事务中提取新副本以进行任何修改)。这里有一大堆指南。

  • 假设您的协调器旨在保存某种状态,我可以推荐一个单例有状态服务吗。据推测,它并没有收到过多的使用量,所以一个实例就足够了,它可以很容易地保存状态(而不需要识别哪个状态在哪个分区上)。至于旋转服务,我在第一个项目符号中介绍了这一点,但使用内置FabricClient上的ApplicationManager来设置新的应用程序,并使用ServiceManager在每个应用程序中创建必要服务的实例。

Service Fabric从最新的8.0版本开始支持.NET Core 3.1到.NET 5,但请注意,.NET 5存在一些小的序列化问题,并提供了一个简单的解决方法。

如果您订阅了Azure支持,我鼓励您在"开发问题"下写信给团队,并分享您的担忧。或者,在每个月的第三个星期四太平洋标准时间上午10点,他们也会在欢迎您加入的团队上进行社区呼叫,您可以在这里找到过去的呼叫。

同样,我不能说这是否比Akka.NET更适合,但我们的堆栈是建立在Service Fabric之上的。虽然它有一些缺点(什么框架没有?),但它是一个用于分布式软件开发的优秀平台。

最新更新