Azure Service Fabric 中的有状态服务和外部持久性之间的转换

Posted

技术标签:

【中文标题】Azure Service Fabric 中的有状态服务和外部持久性之间的转换【英文标题】:Transition between stateful service and external persistence in Azure Service Fabric 【发布时间】:2015-07-16 21:12:50 【问题描述】:

Azure Service Fabric 似乎专注于所有数据都可以放入 RAM 并且持久性用作后备存储的场景。 Reliable Services 旨在将信息存储在 Reliable Collections 中,它使用 log-checkpoint system 将记录的信息写入 RAM。同时,对于 Reliable Actors,default actor state provider 是“Service Fabric 平台提供的分布式键值存储”。这似乎表明同样的限制也适用。

但是,在某些情况下,您可能希望将 Service Fabric 用于“热数据”,但将“冷数据”写入某种形式的永久存储。处理这种过渡的最佳做法是什么?

在奥尔良,这似乎是使用 Azure 表等持久性存储自动处理的。但似乎 Service Fabric 和 Reliable Collections 的主要设计目的是避免需要外部服务,从而增强数据局部性。当前的文档预计将数据移动到disaster recovery and analytics 的某个永久存储中的可能性,但它没有讨论在持久支持的内存中参与者和更永久的存储形式之间来回移动数据的可能性。

一个可能的答案是 Service Fabric 已经这样做了。也许 Reliable Dictionary 有一些内置机制,用于在持久支持的内存存储和永久存储之间切换。

或者,也许答案是必须自己管理。一种方法可能是让 Actor 跟踪它的“热”程度并根据需要切换其持久性存储。但这牺牲了 Actor 模型的好处之一,即 Actor 的自动分配和释放。类似地,我们可能会定期从 Reliable Dictionary 中删除项目并将其添加到其他一些持久性存储中,然后再将它们添加回来。不过,这同样需要了解何时进行过渡是有意义的。

几个例子可能有助于明确这一点:

(1) 假设我们正在实现一个包含许多不同“房间”的多人游戏。我们不需要一次将所有房间都保存在内存中,但我们需要将它们移动到内存中,并在玩家加入后使用本地持久性作为备份。

(2) 假设我们正在实现一个仅附加的 B-Tree 作为数据库的一部分。诱惑是让每个 B-Tree 节点成为有状态的参与者。我们希望热 b-trees 保留在内存中,但当然整个索引不能在内存中。似乎这是一个核心场景,已经为 DocumentDB 之类的东西实现了,但我从文档中不清楚如何做到这一点。

我发现的一个相关问题是here。但这个问题集中在何时使用 Azure Service Fabric 与外部服务。我的问题是是否需要在它们之间进行转换,或者 Azure Service Fabric 是否已经具备此处所需的所有功能。

【问题讨论】:

【参考方案1】:

键值存储状态提供程序确实要求将所有内容保存在内存中。这个提供者实际上将所有参与者的状态存储在本地磁盘上,并且状态也复制到其他节点上的本地磁盘上。所以 KVS 存储被认为是持久可靠的存储。

除此之外,activeactor 的状态也存储在内存中。当一个演员有一段时间没有被使用时,它会被停用并被垃圾收集。发生这种情况时,内存中的副本被释放,只保留磁盘上的副本。当actor再次被激活时,状态会从磁盘中获取,并且只要actor处于活动状态就一直保留在内存中。

此外,KVS 不是唯一的内置状态提供程序。我们还有 VolatileActorStateProvider (http://azure.microsoft.com/en-gb/documentation/articles/service-fabric-reliable-actors-platform/#actor-state-provider-choices)。这是将所有内容保存在内存中的状态提供程序。

【讨论】:

感谢您的澄清。因此,KVS 存储与可靠集合的不同之处在于它不会一直将所有状态都保存在内存中。 (或者也许可靠的集合有时也会在内存中分页进出,尽管文档似乎另有说明?)这更有意义。当然,在某些时候 KVS 存储会耗尽磁盘上的内存,但我认为可以通过监控来避免这种情况。 可靠集合也将它们的状态保存在磁盘上。此页面上的文档明确提及它。 azure.microsoft.com/en-us/documentation/articles/…。 “持久化:数据被持久化到磁盘上,以防止大规模中断(例如,数据中心断电)。”。文档中是否有其他建议? 另外,为了解决磁盘空间不足的问题,您可以阅读有关可扩展性的文章 (azure.microsoft.com/en-us/documentation/articles/…),了解扩展服务并避免这种情况的策略。正如您已经指出的那样,监控也是一个好主意。 文档清楚地表明键值存储和可靠的集合将数据持久化到磁盘。但这似乎暗示可靠的集合也总是在内存中:“[E]每个状态更改都记录在磁盘上,并且只应用于内存......[当]可靠状态管理器需要截断其日志以使新记录的空间[,我将请求可靠集合检查它们的内存状态。”我错误地推断状态将始终保存在内存中。该文档没有解释状态如何在垃圾收集中幸存下来。 来自azure.microsoft.com/en-gb/documentation/articles/…:“存储在可靠集合中的对象在您的服务中保存在本地内存中”【参考方案2】:

KvsActorStateProvider 确实将 Actor 状态存储在 KeyValueStore 中,它与 ReliableDictionary 的结构类似。

我要问的第一个问题是您是否需要将旧演员状态降级为冷库?将所有内容保存在内存中的限制并不限制您的参与者总数,而是每个副本的总数。因此,您必须首先考虑分区策略,以便您的参与者分布在许多不同的副本中。随着您的需求增长,您可以将更多机器添加到集群中,ServiceFabric 将协调将副本移动到新机器。有关 Actor 服务分区的更多信息,请参阅http://azure.microsoft.com/en-gb/documentation/articles/service-fabric-reliable-actors-platform/

如果您确实想在一段时间后使用冷藏库,那么您有几个选择。首先,您可以使用自定义的ActorStateProviderAttribute 来装饰您的演员,该ActorStateProviderAttribute 返回您自己的 IActorStateProvider 实现,该实现可以根据您的决定处理持久性。

或者,您可以完全在您的 Actor 实现中处理它。挂接到Actor Lifecycle 和 OnDeactivateAsync 中,这样当实例被垃圾收集时,或在将来的某个指定时间使用Actor Reminder 时,序列化状态并存储在冷存储(如 blob 或表存储)中并清空国家财产。然后可以使用 ActivateAsync 覆盖从离线存储中检索此状态并进行反序列化。

【讨论】:

这很有帮助。让我感到困惑的是,为什么 Reliable Actors 框架包含垃圾收集,但随后使用 KvsActorStateProvider 作为默认(我相信,仅包含)存储提供程序。如果 KvsActorStateProvider 有效地将所有内容保存在 RAM 和磁盘上,那难道不会抵消垃圾收集的好处吗?当然,在节点之间移动 actor 也有好处,但通常我们认为垃圾回收是为了释放 RAM 内存。 存储在 KVS 中的是有状态 Actor 的状态。 Actor 对象本身位于内存中,并且可以具有局部变量,当 Actor 被垃圾回收时,这些局部变量将从内存中释放。

以上是关于Azure Service Fabric 中的有状态服务和外部持久性之间的转换的主要内容,如果未能解决你的问题,请参考以下文章

Azure Service Fabric - 固定时间作业

Service Fabric - 如何修复失败的有状态应用程序

Azure Service Fabric 中的 NodeType 和 ScaleSet 有啥区别

Azure DevOps 中的 Service Fabric 生成的输出不正确

Azure Service Fabric 中的可扩展工作线程

Service Fabric Actors 或 Azure Functions