5

我试图理解为什么我们的演员服务使用的磁盘空间比预期的要多。我们的服务目前包含分布在 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. 我的预期正确吗?
  2. 什么可以解释我的观察?
4

1 回答 1

1

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

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

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

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

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

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

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

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

这有点令人费解。让我们不要回到我们期望在给定节点上的东西的数量。你说你有 80K 演员。我想你有TargetReplicaSetSize3 个,所以这更像是 240K 演员。每个参与者的状态约为 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(但感觉不太可能)。

于 2018-04-10T19:12:40.843 回答