为啥我的 Service Fabric 参与者使用的磁盘空间比预期的要多?

Posted

技术标签:

【中文标题】为啥我的 Service Fabric 参与者使用的磁盘空间比预期的要多?【英文标题】:Why are my Service Fabric actors using more disk space than expected?为什么我的 Service Fabric 参与者使用的磁盘空间比预期的要多? 【发布时间】:2018-02-06 21:27:51 【问题描述】:

我试图了解为什么我们的 actor 服务使用的磁盘空间比预期的要多。我们的服务目前包含分布在 10 个分区上的大约 80,000 个演员。每个参与者存储大约 150Kb 的状态。

查看我们集群中的一个(共 10 个)节点,我希望看到:

用于大约 3 个分区的磁盘空间(一个作为主分区,两个作为辅助分区) 这和预期的一样 深入到一个分区文件夹,我希望只看到一个副本 ID 与预期不同: 我看到了预期的一个(与 Service Fabric Explorer 中节点部分下列出的副本匹配的那个)。副本 ID 以 R_ 为前缀 在同一个分区文件夹中,我看到其他 3 个文件夹的副本 ID 以前缀 S_ 开头。这些副本 ID 与“应用程序”节点下 Service Fabric Explorer 中列出的任何值都不匹配。 查看以 R_ 开头的副本文件夹,我希望该文件夹包含的大小不会超过 8000 个演员的大小,每个演员占用大约 150 Kb,因此大约 1.14 Gb 的数据。 与预期不同: 文件夹包含一个文件ActorStateStore,其大小为5.66Gb

我想了解的另一件事是:

我们的应用程序版本 1 没有清理未使用的演员。正如您所料,我们看到每个节点上的磁盘使用量都在稳步增长。 我们的应用程序版本 2 开始删除未使用的演员。由于这个新代码将超过一半的活动参与者,我在部署后的预期是总体使用的磁盘大小会显着下降。 没有发生,增长停止但使用量没有减少。

所以我的问题是:

    我的预期正确吗? 什么可以解释我的观察结果?

【问题讨论】:

【参考方案1】:

深入到一个分区文件夹,我希望看到 一个副本ID

如果事情已经运行了一段时间,我希望看到不止一个。这是因为两件事:

    Service Fabric 至少在 ReplicaRestartWaitDuration 的节点上保留故障副本的信息。这样一来,如果可以进行本地恢复,节点上仍有必要的信息。例如,如果副本刚刚失败并且无法完全删除,则这些文件可能会累积。如果有人“ForceRemoved”单个副本,它们也可能存在,因为这明确跳过了干净关闭。这就是为什么我们通常不建议在生产环境中使用此命令的部分原因。

    还有一个称为“UserStandbyReplicaKeepDuration”的设置,它控制 SF 将旧副本保留多长时间现在,以防以后需要它们(因为它通常更便宜从部分状态而不是完整状态重建)。

    一个。例如,假设某个副本的某个节点出现故障,并且比该服务的ReplicaRestartWaitDuration 停留的时间更长。发生这种情况时,SF 会构建一个替换副本以让您恢复到您的 TargetReplicaSetSize

    b.假设一旦构建了该副本,失败的节点就会回来。

    c。如果我们仍然在该副本的 StandbyReplicaKeepDuration 内,那么 SF 将把它留在磁盘上。如果同时发生另一个故障,SF 通常会(取决于Cluster Resource Manager 设置,此节点是否为有效目标等)选择此部分副本并从驱动器上剩余的内容重建替换。

    因此您可以看到过去的副本,其信息仍保留在驱动器上,但您通常不会看到比 UserStandbyReplicaKeepDuration 更早的任何内容(默认为一周)。如果需要,您始终可以缩短集群中的持续时间。

我希望文件夹包含的大小不超过 8000 个演员每个占用大约 150 Kb,因此大约 1.14 Gb 的数据。 与预期不同:该文件夹包含一个文件 ActorStateStore 及其 大小为 5.66Gb

这有点令人费解。让我们不要回到我们期望在给定节点上的东西的数量。你说你有 80K 演员。我想你的TargetReplicaSetSize 是 3,所以这更像是 240K 演员。每个参与者的状态约为 150K,因此集群的状态约为 34 GB。每个节点我们预计 3.4 GB 的状态。 (我认为您最初的估计忘记了复制。如果您的 TargetReplicaSetSize 实际上是 1,请告诉我,我们可以重新计算。)

~3.4gb 更接近您对~5.7gb 的观察,但还不够接近。需要记住的其他一些事项:

序列化开销:actor 框架一般使用 NetDataContractSerializer 来序列化你的actor状态中的数据。您可能想测试一下这是否会导致您的 150K 状态增加 60%(这将是很多开销,但并非闻所未闻)

“剩余”演员。如果您要动态创建副本,要记住的一件事是,在您告诉 SF 删除它们之前,它们不会被完全删除

var serviceUri = ActorNameFormat.GetFabricServiceUri(typeof(IMyActor), actorAppName); var actorServiceProxy = ActorServiceProxy.Create(actorId.GetPartitionKey(), serviceUri); await actorServiceProxy.DeleteActorAsync(actorId, cancellationToken);

增长停止,但使用量并未减少。

这可能只是在未重新打包/回收的数据存储级别分配的空间。我们需要查看实际仍在占用空间的内容以了解情况。其中一些取决于实际的持久性存储(ESE/KVS 与基于字典的状态提供程序)。作为升级的一部分,您生成的 ActorId 也可能发生了某种变化,因此新代码无法引用“旧” ActorId(但这感觉不太可能)。

【讨论】:

感谢您解释ReplicaRestartWaitDuration 部分。现在说得通了。 对于 ActorStateStore 的大小,结果表明 8000 是 预期的演员数量,而不是实际数量。删除它们的逻辑中存在错误,还有更多错误。 为了在修复 actor 删除错误后回收磁盘空间,我们确实必须应用 CompactionThresholdInMB 设置以再次将存储缩小到常规大小。 很高兴这一切都解决了! 我们也看到了这个问题,@veertien 你是如何使用 CompactionThresholdInMB 的?我找不到任何有用的文档。

以上是关于为啥我的 Service Fabric 参与者使用的磁盘空间比预期的要多?的主要内容,如果未能解决你的问题,请参考以下文章

Service Fabric,确定是不是存在特定参与者

Service Fabric 中的 actorevent 都有哪些限制?

Service Fabric 对无状态服务的远程调用未返回、卡住

Azure Service Fabric 可靠参与者与可靠服务

为啥我的 Service Fabric 代码会锁定自己的 PDB?

Service Fabric 参与者中的静态对象