了解何时使用有状态服务以及何时依赖 Azure Service Fabric 中的外部持久性

Understanding when to use stateful services and when to rely on external persistence in Azure Service Fabric

我晚上都在评估 Azure Service Fabric 作为我们当前 WebApps/CloudServices 堆栈的替代品,并且对于如何决定何时 services/actors with state 应该是有状态的参与者感到有点不确定,以及何时它们应该是具有外部持久状态的无状态参与者(Azure SQL、Azure Storage 和 DocumentDB)。我知道这是一个相当新的产品(至少对一般 public 而言),因此可能还没有很多关于此的最佳实践,但我已经通读了大部分 documentation Microsoft 在没有找到明确答案的情况下提供。

我正在处理的当前问题域是我们的事件存储;我们的部分应用程序基于事件溯源和 CQRS,我正在评估如何将此事件存储移至 Service Fabric 平台。事件存储将包含大量时间序列数据,因为它是我们持久保存数据的唯一真实来源,所以它必须一致、复制并存储到某种形式的持久存储中。

我考虑过的一种方法是使用有状态 "EventStream" actor;使用事件源的聚合的每个实例都将其事件存储在一个独立的流中。这意味着有状态 actor 可以跟踪其自己的流的所有事件,并且我已经满足了我对数据存储方式的要求(事务性、复制性和持久性)。然而,一些流可能会变得非常大(数十万,如果不是数百万,事件),这就是我开始不确定的地方。我想,当这些大数据模型需要序列化到磁盘或从磁盘反序列化时,拥有一个具有大量状态的 actor 会对系统性能产生影响。

另一种选择是让这些参与者保持无状态,让他们只从一些外部存储(如 Azure)读取数据 SQL - 或者只使用无状态服务而不是参与者。

基本上,actor/service "too much" 的状态量是什么时候,您应该开始考虑其他处理状态的方法?

此外,Service Fabric Actors design pattern: Some anti-patterns 文档中的这一部分让我有些困惑:

Treat Azure Service Fabric Actors as a transactional system. Azure Service Fabric Actors is not a two phase commit-based system offering ACID. If we do not implement the optional persistence, and the machine the actor is running on dies, its current state will go with it. The actor will be coming up on another node very fast, but unless we have implemented the backing persistence, the state will be gone. However, between leveraging retries, duplicate filtering, and/or idempotent design, you can achieve a high level of reliability and consistency.

这里的"if we do not implement the optional persistance"是什么意思?我的印象是,只要您修改状态的事务成功,您的数据就会持久保存到持久存储中,并至少复制到副本的一个子集。这一段让我想知道是否存在 actors/services 中的状态会丢失的情况,这是否是我需要自己处理的事情。我从文档其他部分的有状态模型中得到的印象似乎抵消了这一说法。

您的一个选择是在 actor 中保留 'some' 状态(假设什么可以被认为是需要快速可用的热数据)并将其他所有内容存储在 'traditional' 存储基础设施,例如 SQL Azure、DocDB,.... 很难对过多的本地状态制定一般规则,但考虑热数据与冷数据可能会有所帮助。 Reliable Actors 还提供自定义 StateProvider 的能力,因此您还可以考虑使用您需要的特定策略来实现自定义的 StateProvider(通过实现 IActorStateProvider),以便更有效地满足您在数据量、延迟方面的要求、可靠性等(注意:StateProvider 接口上的文档仍然非常少,但如果您想要实现这一点,我们可以发布一些示例代码)。

关于反模式:该注释更多地是关于跨多个参与者实现交易。 Reliable Actors 为参与者范围内数据的可靠性提供了充分的保证。由于 Actor 模型的分布式和松耦合性质,实现涉及多个 actor 的事务并非易事。如果 'distributed' 事务是一项强烈要求,那么 Reliable Services 编程模型可能更适合。

我知道这个问题已经得到解答,但最近发现自己在使用 CQRS/ES 系统时遇到了同样的困境,我是这样处理的:

  1. 每个聚合都是一个只存储当前状态的参与者。
  2. 根据命令,聚合会影响状态更改并引发事件。
  3. 事件本身存储在 DocDb 中。
  4. 激活时,AggregateActor 实例从 DocDb 读取事件(如果可用)以重新创建其状态。这显然只在每个 actor 激活时执行一次。这处理了 actor 实例从一个节点迁移到另一个节点的情况。

回答@Trond 的次要问题,即“'if we do not implement the optional persistance' 在这里表示什么?”

actor 始终是有状态服务,可以使用 actor 上的属性配置其状态 class,以三种模式之一运行:

  1. 坚持了。状态被复制到所有副本实例,并且它 也写入磁盘。这个状态即使全部保持 副本被关闭。
  2. 易挥发。状态被复制到所有 副本实例,仅在内存中。这意味着只要一个副本 实例处于活动状态,状态得以维持。但是当所有副本都 关机状态丢失,关机后无法恢复 重新启动。
  3. 没有坚持。状态不会复制到其他 副本实例,也不到磁盘。这提供了最少的状态 保护。

可以找到对该主题的完整讨论in the Microsoft documentation