为什么我的 Service Fabric 参与者使用比预期更多的磁盘空间?

vee*_*ien 5 azure-service-fabric service-fabric-stateful service-fabric-actor

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

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

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

我试图理解的另一件事如下:

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

所以我的问题是:

  1. 我的期望是否正确?
  2. 什么可以解释我的观察?

mas*_*der 1

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

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

  1. Service Fabric 保留在节点上发生故障的副本的信息至少ReplicaRestartWaitDuration. 这样,如果可以进行本地恢复,节点上仍然存在必要的信息。例如,如果副本刚刚失败并且无法彻底删除,则此类文件可能会累积。如果有人“强制删除”单个副本,那么它们也可能存在,因为这会明确跳过干净关闭。这就是我们通常不建议在生产环境中使用此命令的部分原因。
  2. 还有一个称为“ UserStandbyReplicaKeepDuration ”的设置,它控制 SF 将当前不需要的旧副本保留多长时间,以备以后需要它们(因为从部分状态重建通常比从完整状态重建更便宜)。

    A。例如,假设某个副本所在的节点发生故障,并且保持关闭的时间比ReplicaRestartWaitDuration该服务的时间长。当这种情况发生时,SF 会构建一个替换副本来让您恢复到您的TargetReplicaSetSize.

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

    C。如果我们仍在该副本的 StandbyReplicaKeepDuration 内,则 SF 会将其保留在磁盘上。如果同时发生另一个故障,SF 通常会(取决于集群资源管理器设置、该节点是否是有效目标等)选择此部分副本并根据驱动器上剩余的内容重建替换副本。

    因此,您可以看到过去的副本,其信息仍然保留在驱动器上,但您通常不应该看到任何早于UserStandbyReplicaKeepDuration(默认情况下一周)的内容。如果需要,您可以随时缩短集群中的持续时间。

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

这有点令人费解。让我们回到我们期望在给定节点上的东西的数量。你说你有8万名演员。我猜你有TargetReplicaSetSize3 个演员,所以实际上更像是 24 万演员。每个参与者都有约 150K 的状态,因此集群的状态约为 34 GB。我们预计每个节点有 3.4 GB 的状态。(我认为你最初的估计忘记了复制。如果你实际上得到了TargetReplicaSetSize1,那么请告诉我,我们可以重新计算。)

~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(但这感觉不太可能)。