了解何时使用有状态服务以及何时依赖 Azure Service Fabric 中的外部持久性
Posted
技术标签:
【中文标题】了解何时使用有状态服务以及何时依赖 Azure Service Fabric 中的外部持久性【英文标题】:Understanding when to use stateful services and when to rely on external persistence in Azure Service Fabric 【发布时间】:2015-07-15 02:16:29 【问题描述】:我晚上都在评估 Azure Service Fabric 以替代我们当前的 WebApps/CloudServices 堆栈,并且有点不确定如何决定何时应该是有状态的服务/参与者是有状态参与者,什么时候应该是具有外部持久状态的无状态参与者(Azure SQL、Azure 存储和 DocumentDB)。我知道这是一个相当新的产品(至少对公众来说),所以可能还没有很多关于这方面的最佳实践,但我已经阅读了微软提供的大部分documentation,但没有找到一个明确的答案。
我正在处理的当前问题域是我们的事件存储;我们的部分应用程序基于事件溯源和 CQRS,我正在评估如何将此事件存储转移到 Service Fabric 平台。事件存储将包含大量时间序列数据,因为它是我们保存在那里的数据的唯一真实来源,所以它必须保持一致、复制并存储到某种形式的持久存储中。
我考虑过的一种方法是使用有状态的“EventStream”actor;使用事件源的聚合的每个实例都将其事件存储在一个隔离的流中。这意味着有状态的参与者可以跟踪它自己的流的所有事件,并且我已经满足了我对数据存储方式(事务性、复制性和持久性)的要求。但是,某些流可能会变得非常大(数十万,如果不是数百万,事件),这就是我开始不确定的地方。我想,当这些大型数据模型需要序列化到磁盘或从磁盘反序列化时,拥有大量状态的 actor 会对系统的性能产生影响。
另一种选择是让这些参与者保持无状态,让他们从 Azure SQL 等外部存储读取数据 - 或者只使用无状态服务而不是参与者。
基本上,演员/服务的状态量何时“过多”,您应该开始考虑其他处理状态的方式?
另外,Service Fabric Actors design pattern: Some anti-patterns 文档中的这一部分让我有点困惑:
将 Azure Service Fabric Actors 视为事务系统。 Azure Service Fabric Actors 不是提供 ACID 的基于两阶段提交的系统。如果我们不实现可选的持久性,并且actor正在运行的机器死亡,它的当前状态将随之而来。演员将很快出现在另一个节点上,但除非我们实现了支持持久性,否则状态将消失。但是,在利用重试、重复过滤和/或幂等设计之间,您可以实现高水平的可靠性和一致性。
“如果我们不实现可选的持久性”在这里表示什么?我的印象是,只要您修改状态的事务成功,您的数据就会被持久化存储并复制到至少一部分副本中。这一段让我想知道是否存在我的演员/服务中的状态会丢失的情况,如果这是我需要自己处理的事情。我从文档其他部分的有状态模型中得到的印象似乎抵消了这种说法。
【问题讨论】:
您对此有更新吗?我发现自己处于非常相似的位置,想知道您最终做了什么。干杯。 @Trond Nordheim 您决定使用 SF 的解决方案了吗?我有类似的要求,很想听听您的决定。 我们面临着同样的道路,我们也有同样的疑问,我们测试了许多 .NET 事件溯源工具(mementoFX、ncqrs 等),但我们对它们并不满意(也许这是我们的错)但我们仍在寻找替代方案。 【参考方案1】:您有一个选择是在参与者中保留“一些”状态(假设可以认为是需要快速可用的热数据)并将其他所有内容存储在“传统”存储基础架构上,例如如 SQL Azure、DocDB、.... 很难对过多的本地状态制定一般规则,但也许考虑一下热数据与冷数据会有所帮助。 Reliable Actors 还提供自定义 StateProvider 的能力,因此您还可以考虑使用特定策略实现自定义 StateProvider(通过实现 IActorStateProvider),以便更高效地满足数据量、延迟方面的要求, 可靠性等(注意:StateProvider 接口上的文档仍然非常少,但如果您想要这样做,我们可以发布一些示例代码)。
关于反模式:该说明更多地是关于在多个参与者之间实现事务。 Reliable Actors 为参与者边界内数据的可靠性提供了充分保证。由于 Actor 模型的分布式和松耦合性质,实现涉及多个 Actor 的事务并非易事。如果“分布式”事务是一个强需求,那么 Reliable Services 编程模型可能更适合。
【讨论】:
感谢您的回复,在这个级别上接近它是有道理的 - 至少在这种情况下,您处理的数据集可能会变得无法控制。非常感谢您在管道中准备的任何示例代码,我们正在根据我们当前的用例彻底调查 Service Fabric,以确定我们应该如何以及是否应该使用它 - 所以看到更多示例会很有趣在那里。 quote @clca > “(注意:StateProvider 接口上的文档仍然非常少,但如果您想要这样做,我们可以发布一些示例代码)”。我们也对您可以分享的一段代码非常感兴趣,从中获得灵感会很棒。提前致谢【参考方案2】:我知道这个问题已经得到解答,但最近发现自己在使用 CQRS/ES 系统时遇到了同样的困境,这就是我的解决方法:
-
每个聚合都是一个参与者,其中仅存储当前状态。
在命令中,聚合将影响状态更改并引发事件。
事件本身存储在 DocDb 中。
激活时,AggregateActor 实例从 DocDb 读取事件(如果可用)以重新创建其状态。这显然只在每个actor激活时执行一次。这解决了参与者实例从一个节点迁移到另一个节点的情况。
【讨论】:
【参考方案3】:回答@Trond 的次要问题,即“'如果我们不实现可选的持久性'在这里说明了什么?”
Actor 始终是一个有状态的服务,它的状态可以使用 Actor 类上的属性进行配置,以在以下三种模式中的一种模式下运行:
-
持续。状态被复制到所有副本实例,并且它
也写入磁盘。即使所有
副本被关闭。
易挥发。状态复制到所有
副本实例,仅在内存中。这意味着只要一个副本
实例处于活动状态,状态保持不变。但是当所有副本都
关闭状态已丢失且无法恢复
重新启动。
没有持久性。状态不会复制到其他
副本实例,也不到磁盘。这提供了最少的状态
保护。
该主题的完整讨论可以找到in the Microsoft documentation
【讨论】:
以上是关于了解何时使用有状态服务以及何时依赖 Azure Service Fabric 中的外部持久性的主要内容,如果未能解决你的问题,请参考以下文章
Flutter - 了解 Provider、Bloc 的生命周期以及何时处理流 [重复]