Azure Service Fabric 可靠集合和内存

14

假设我正在5个D1类(1核心,3.5GB RAM,50GB SSD)虚拟机上运行Service Fabric集群,并且在该集群上运行2个可靠的服务,一个是无状态的,一个是有状态的。让我们假设副本目标是3。

  1. 如何计算我的可靠收集可以容纳多少数据?

  2. 假设我添加了一个或多个有状态的服务。由于我不知道框架如何分配服务,我是否需要采取最保守的方法,并假定一个节点可能在单个节点上运行所有有状态的服务,而它们的累积内存需求低于单台机器上可用的RAM?


https://azure.microsoft.com/zh-cn/documentation/articles/service-fabric-reliable-services-reliable-collections/ 中提到了一个提示:“实际上,今天您受限于盒子上的内存量”。 - tymtam
问题1是:“它们最多能容纳多少?” - masnider
@masnider 是的,归根结底就是这样。 - tymtam
1个回答

28
TLDR - 估计集群的预期容量是一部分艺术,一部分科学。你可以得到一个较好的下限,并尽可能将其提高,但总体上,在工作负载条件下部署、运行和收集数据是回答这个问题的最佳方式。
1)通常,给定计算机上的集合受可用内存量或节点上可用磁盘空间量的限制,以较低的值为准。今天,我们将所有数据保存在内存中,并将其持久化到磁盘中。因此,整个集群中集合可以容纳的最大数量通常为(集群中可用内存量)/(目标副本集大小)。
请注意,“可用内存”是其他代码在计算机上运行时剩余的内存,包括操作系统。但是,在上述示例中,您没有在所有节点上运行——您只能获得其中的3个。因此,(不切实际地)假设这些其他因素没有任何开销,您可以期望在运行它的节点上放入约3.5 GB的数据,然后内存就会耗尽。集群中仍有2个节点为空。
让我们再举一个例子。假设与上面的示例大致相同,但在这种情况下,您设置了分区状态服务。假设您选择了5个分区。因此,现在每个节点都有一个主副本和来自其他分区的2个次要副本。在这种情况下,每个分区最多只能容纳约1.16 GB的状态,但现在总体上您可以将5.83 GB的状态打包到集群中(因为现在所有节点都可以完全利用)。顺便说一句,只是为了证明数学是正确的,那是(3.5 GB每个节点* 5个节点在集群中)[17.5] /(目标副本集大小为3)= 5.83。
在所有这些示例中,我们还假设所有分区和所有副本的内存消耗相同。大多数情况下,这可能不成立(至少暂时不成立)——某些分区可能会有更多或更少的工作量,因此会有不均匀的资源消耗。我们还假设次要副本始终与主副本相同。在状态量的情况下,可能公平地假设它们会相当平均,尽管对于其他资源消耗可能不是这样(这只是要记住的事情)。在资源消耗不均匀的情况下,这确实是Service Fabric的其余集群资源管理帮助的地方,因为我们可以了解不同副本的消耗并将它们有效地打包到集群中以利用可用空间。与状态相关的资源消耗的自动报告是我们正在关注的,也是我们想要做的事情,因此在未来,这将是自动的,但今天您必须自己报告此消耗。

2) 默认情况下,我们将根据默认指标平衡服务(有关指标的更多信息在此处)。所以默认情况下,两个不同服务的不同副本可能会出现在同一台机器上,但是在您的示例中,您将得到4个节点,每个节点上有1个来自一个服务的副本,然后1个节点上有两个来自两个不同服务的副本。这意味着每个服务(每个服务都有1个分区,与您的示例相符)在每个服务中只能使用1.75 GB的内存,总共在集群中使用3.5 GB。这再次少于集群的可用内存,因为您没有利用一些节点的部分。

请注意,这是最大可能的消耗,并假设没有超出服务本身的消耗。将其作为最大值不可取。您需要出于几个原因而将其减少,但最实际的原因是确保在升级和故障的情况下集群中有足够的可用容量。例如,假设您有5个升级域和5个故障域。现在假设在升级域中进行升级时,一个故障域的节点失败了。这意味着您的集群容量中约有40%可能会随时消失,您可能希望在剩余节点上留下足够的空间。这意味着如果您的集群先前可以容纳5.83 GB的状态(根据我们之前的计算),那么实际上您可能不想将更多的状态放入其中,因为过多的状态可能导致服务无法恢复到100%的健康状态(还要注意,我们不会立即构建替代副本,因此在遇到此情况之前节点必须处于关机状态超过ReplicaRestartWaitDuration时间)。在此文章中,介绍了有关指标、容量、缓冲容量(可用于确保为故障情况留下节点的空间)、故障和升级域的更多信息。

还有一些其他实际限制您能够存储的状态量。您需要执行以下几项任务:

  • 估计数据大小。通过计算对象所持有的每个字段的大小,您可以事先合理地估计数据的大小。请务必考虑64位引用。这将给您一个下限起点。
  • 存储开销。您在集合中存储的每个对象将带有一些存储该对象的开销。在可靠集合中,取决于收集和当前正在进行的操作(复制、枚举、更新等),此开销可以在每个项目(行)存储在集合中的100到700字节之间变化。还要知道我们一直在寻找减少引入的开销量的方法。
我们强烈建议您运行服务并通过性能计数器测量实际的资源消耗,以一定时间内模拟真实负载并测量您关心的指标的实际使用情况将为您提供很好的服务。我们之所以特别推荐这样做,是因为您将能够看到来自诸如CLR对象堆之类的消耗,您的对象最终放置在哪里,垃圾收集(GC)运行的频率如何,是否存在泄漏或其他影响您实际可利用的内存量的因素。
我知道这是一个很长的回答,但我希望您会觉得它有用且完整。

感谢您提供详细的答案。您对如何清理字典中的旧数据有什么建议? - George Gkionis
2
你需要弄清楚在数据和服务的上下文中,“stale”是什么意思,然后将其删除(通常还要将其存档到其他地方,如DocDB)。通常这是另一个字典,它将时间戳(数据修改时间)作为键,将字典中数据的键作为值。然后定期运行任务并将数据保存到冷存储中,然后删除原始字典中的数据。标记和清除是这些操作的良好模式。在决定删除某些内容并使其重新变得新鲜之间,请注意竞争条件。希望对你有所帮助。 - masnider
@masnider ReliableQueue和ReliableConcurrentQueue是否与其他可靠集合以相同的方式利用RAM和磁盘?我希望当ReliableConcurrentQueue增长时(因为它无法被快速消耗),StateManager会跳过写入RAM并直接写入磁盘?如果不是这种情况,我想我需要手工制作“标记和清除”但是针对队列而不是集合,然后在队列深度降低时将这些消息反向放回队列中? - Oliver Tomlinson
是的,您必须这样做。所有集合都以相同的方式使用资源。它们都会将数据写入内存记录和磁盘。 - masnider
这个答案在2018年4月还有效吗?或者有什么变化吗?如果我考虑三个节点,每个节点一个副本,每个节点16GB内存和50GB磁盘 - 我应该认为所有可靠集合的最大容量是16GB减去系统开销吗? - Kuba Wyrostek
答案大部分相同。集合中有一些缓存(特别是ReliableDictionary),根据数据是否“最近”使用过进行缓存,但它不可调整(正在改进中)。磁盘空间是真正的上限,但根据数据访问模式(即:如果所有键和值都很热,则不会将任何内容刷新出内存),您可能无法使用它。今天,所有键始终存储在内存中。简而言之:考虑内存作为上限并进行性能/密度测试仍然是最好的计划。 - masnider

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接