

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# Amazon DocumentDB 中的垃圾回收
<a name="garbage-collection"></a>

Amazon DocumentDB 实现了多版本并发控制（MVCC）数据库架构，可为每次更新操作创建新版本的文档和索引条目。该架构提供了事务隔离，防止一笔交易的更改出现在另一笔交易中。

**Topics**
+ [了解 Amazon DocumentDB 中的垃圾收集](#understanding-garbage-collection)
+ [垃圾回收过程](#garbage-collection-process)
+ [存储架构和扩展存储](#storage-architecture)
+ [监控垃圾回收](#monitoring-garbage-collection)
+ [collStats 输出示例](#example-collstats-output)
+ [常见问题](#garbage-collection-faq)

## 了解 Amazon DocumentDB 中的垃圾收集
<a name="understanding-garbage-collection"></a>

垃圾回收（GC）是一个自动化后台过程，可在 Amazon DocumentDB 中维持最佳的系统性能和可用性。与许多现代数据库一样，Amazon DocumentDB的MVCC架构在每次更新时都会创建新的文档和索引版本。每次写入操作都会从有限的计数器中消耗一个唯一的 MVCC ID。这些 ID 标识文档版本属于哪个事务以及该版本是否已提交或已回滚。随着时间的推移，这些旧版本及其 MVCC ID 会累积，需要进行清理以防止性能下降。

### 垃圾回收的功能
<a name="w2aac61c15b7b5"></a>

垃圾回收器有三个基本功能：
+ **回收存储空间**：将移除活动查询不再需要的过时文档和索引版本，从而为将来的写入操作释放空间。
+ **防止 MVCC ID 溢出**：通过管理 MVCC ID 的有限计数器来防止 MVCC ID 溢出。如果没有这种管理，计数器最终将达到其限制，从而迫使数据库进入临时只读模式，直至 ID 被回收利用。
+ **维持查询性能**：通过消除失效的文档版本来维持最佳的查询性能，否则这些文档版本会累积并拖慢查询处理速度。

## 垃圾回收过程
<a name="garbage-collection-process"></a>

垃圾回收过程对每个集合进行操作，并且可以在不同的集合上并发运行多个过程。此过程包括四个连续阶段：

1. **识别**：系统识别活动事务或查询不再引用的文档和索引版本。

1. **内存加载**：如果旧文档和索引条目尚未存在于内存中，则会将其加载到内存中。

1. **删除**：永久删除过时版本以回收存储空间。

1. **MVCC ID 回收**：系统将从已删除的版本中回收 MVCC ID 以用于新操作。

当垃圾回收完成对旧文档版本的处理后，会从系统中移除最旧的 MVCC ID。这种清理对于通过回收 MVCC ID 来防止 MVCC ID 溢出至关重要，使 MVCC ID 可用于整个集群中的新写入操作。若无此回收过程，系统最终将耗尽其有限的 MVCC ID 计数器并进入只读状态。

### 垃圾回收调度
<a name="w2aac61c15b9b9"></a>

垃圾回收会定期在后台自动运行。时间和频率会根据系统负载、可用资源、写入量和 MVCC ID 消耗水平进行动态调整。在高写入活动期间，垃圾回收过程将更频繁地执行以管理数量激增的文档版本。

## 存储架构和扩展存储
<a name="storage-architecture"></a>

Amazon DocumentDB 使用复杂的存储架构，将文档存储分成两个不同的部分：

### 基础存储分段
<a name="w2aac61c15c11b5"></a>

基本存储段包含主要文档数据和元数据。该区段存储：
+ 符合标准页面大小 (8 KB) 的文档内容。
+ 文档元数据和结构信息。
+ 主索引及其条目。
+ Collection-level 统计和配置。

### 扩展存储段
<a name="w2aac61c15c11b7"></a>

扩展存储段利用专门的大型文档对象存储，该存储区旨在处理超过标准存储页面大小的文档。该部分提供：
+ **高效的大型文档处理 ** — 大于基本存储阈值的文档会自动移至扩展存储段。
+ **优化的存储布局 ** — 该分段使用针对大型对象进行了优化的不同存储格式，从而减少了碎片化并改善了访问模式。
+ **独立垃圾收集 ** — 扩展存储段有自己的垃圾收集流程，可以独立于基础存储清理运行。
+ **透明访问 ** — 应用程序无缝访问大型文档，无需知道哪个存储段包含数据。

扩展存储区段特别有益于：
+ 包含包含大型嵌入式数组的文档的集合。
+ 具有大量嵌套结构的文档。
+ 存储二进制数据或大型文本字段的集合。
+ 文档大小混合的应用程序，其中一些文档明显超过平均大小。

## 监控垃圾回收
<a name="monitoring-garbage-collection"></a>

### 集群级别指标
<a name="w2aac61c15c13b3"></a>

**`AvailableMVCCIds`**
+ **位置 ** —亚马逊 CloudWatch
+ **描述 ** — 一个计数器，显示剩余的可用写入操作的数量，最大上限为 18 亿个。当此计数器达到零时，您的集群将进入只读模式，直至 ID 被回收并循环利用。计数器会在每次写入操作后递减，并在垃圾回收利用旧的 MVCC ID 后递增。
+ **建议 ** — 当亚马逊DocumentDB 5.0及更高版本的价值低于9亿美元时，或在亚马逊DocumentDB 3.6和4.0上低于13亿美元时，设置警报。此预警可让您采取稍后讨论的建议步骤。

**`LongestActiveGCRuntime`**
+ **位置 ** —亚马逊 CloudWatch
+ **描述**：最长活动垃圾回收过程的持续时间（以秒为单位）。每分钟更新一次，仅跟踪活动操作，不包括在一分钟时段内完成的进程。
+ **建议 ** — 与`gcRuntimeStats`历史数据进行比较以确定异常的垃圾收集行为，例如批量删除期间的运行时间延长。

### 回收级别指标
<a name="w2aac61c15c13b5"></a>

**`MVCCIDStats: MVCCIdScale`**
+ **位置**：数据库 collStats 命令
+ **描述**：以 0 到 1 的等级衡量 MVCC ID 使用期限，其中 1 表示集群进入只读状态前的最长使用期限。将此指标与 `AvailableMVCCIds` 结合使用，以识别包含使集群老化的最旧 MVCC ID 的集合。
+ **建议**：将每个集合的值维持在 0.3 以下。

**`gcRuntimeStats`**
+ **位置**：数据库 collStats 命令
+ **描述**：提供两个月的垃圾回收指标历史记录，包括总运行次数、平均持续时间和最长持续时间。仅包括持续时间超过五分钟的垃圾回收操作，以确保有意义的统计数据。

**`storageSizeStats`**
+ **位置**：数据库 collStats 命令
+ **描述 ** — 提供不同存储段的存储利用率的详细分类：
  + `storageSegmentBase`— 基本存储段用于标准文档的存储
  + `storageSegmentExtended`— 扩展存储段用于存储大型文档的存储空间
+ **用法 ** — 帮助识别具有大量大型文档存储空间的馆藏，并了解存储分配模式。

**`unusedStorageSize`**（集合级别）
+ **位置**：数据库 collStats 命令
+ **描述**：根据抽样统计数据估算集合中未使用的存储空间。包括已删除文档和空分段所占用的空间。该指标提供合并总数和每个分段的细分信息：
  + 合并`unusedBytes`并`unusedPercent`跨越所有存储分段
  + `storageSegmentBase`— 未使用的空间，特别是基础存储段中的未使用空间
  + `storageSegmentExtended`— 未使用的空间，特别是扩展存储段中的未使用空间

**`documentFragmentStats`**
+ **位置**：数据库 collStats 命令
+ **描述 **-提供有关文档片段和集合中失效数据的详细信息。文档片段代表数据库引擎使用的内部存储单元，无效片段表示无法访问但尚未回收的数据。该指标包括：
  + `totalDocFragmentsCount`— 集合中文档片段的总数
  + `deadDocFragmentsCount`— 包含失效（无法访问）数据的片段数量
  + `deadDocFragmentsPercent`— 包含无效数据的片段的百分比
  + `deadDocFragmentBytes`— 失效文档片段消耗的估计字节数
  + Per-segment `storageSegmentBase`和的分解 `storageSegmentExtended`
+ **使用情况 ** — 监控此指标以了解垃圾收集的有效性，并确定可能受益于维护操作的垃圾回收活动。失效碎片的百分比很高表明垃圾回收可能落后了，或者垃圾收集将受益于优化。

### 索引级别指标
<a name="w2aac61c15c13b7"></a>

**`unusedStorageSize`**（索引级别）
+ **位置**：数据库 indexStats 命令
+ **描述**：根据抽样统计数据估算索引中未使用的存储空间。包括过时的索引条目和空分段所占用的空间。
+ **建议**：使用 `reIndex` 命令在不停机的情况下重建索引并回收未使用的空间。有关更多详细信息，请参阅“管理索引”。

## collStats 输出示例
<a name="example-collstats-output"></a>

以下示例显示了包含垃圾收集和存储指标的典型`collStats`输出：

```
{
    "ns" : "Mvcc_consumption_test_db.mvcc_test_collection",
    "MVCCIdStats" : {
        "MVCCIdScale" : 0.03
    },
    "gcRuntimeStats" : {
        "numRuns" : 1,
        "historicalAvgRuntime" : 3295,
        "historicalMaxRuntime" : 3295,
        "lastRuntime" : 3295,
        "lastRuntimeStart" : ISODate("2025-06-24T08:47:14Z")
    },
    "documentFragmentStats" : {
        "totalDocFragmentsCount" : 45000000,
        "deadDocFragmentsCount" : 2250000,
        "deadDocFragmentsPercent" : 5.0,
        "deadDocFragmentBytes" : 98304000,
        "storageSegmentBase" : {
            "totalDocFragmentsCount" : 30000000,
            "deadDocFragmentsCount" : 1500000,
            "deadDocFragmentsPercent" : 5.0,
            "deadDocFragmentBytes" : 65536000
        },
        "storageSegmentExtended" : {
            "totalDocFragmentsCount" : 15000000,
            "deadDocFragmentsCount" : 750000,
            "deadDocFragmentsPercent" : 5.0,
            "deadDocFragmentBytes" : 32768000
        }
    },
    "collScans" : 14,
    "count" : 30000000,
    "size" : 1320000000,
    "avgObjSize" : 44,
    "storageSize" : 6461497344,
    "storageSizeStats" : {
        "storageSegmentBase" : 4307664896,
        "storageSegmentExtended" : 2153832448
    },
    "capped" : false,
    "nindexes" : 2,
    "totalIndexSize" : 9649553408,
    "indexSizes" : {
        "_id_" : 1910661120,
        "c_1" : 7738892288
    },
    "unusedStorageSize" : {
        "unusedBytes" : 4201881600,
        "unusedPercent" : 65.05,
        "storageSegmentBase" : {
            "unusedBytes" : 2801254400,
            "unusedPercent" : 65.05
        },
        "storageSegmentExtended" : {
            "unusedBytes" : 1400627200,
            "unusedPercent" : 65.05
        }
    },
    "cacheStats" : {
        "collBlksHit" : 171659016,
        "collBlksRead" : 754061,
        "collHitRatio" : 99.5627,
        "idxBlksHit" : 692563636,
        "idxBlksRead" : 1177921,
        "idxHitRatio" : 99.8303
    },
    "idxScans" : 41823984,
    "opCounter" : {
        "numDocsIns" : 0,
        "numDocsUpd" : 20911992,
        "numDocsDel" : 0
    },
    "lastReset" : "2025-06-24 05:57:08.219711+00",
    "ok" : 1,
    "operationTime" : Timestamp(1750968826, 1)
}
```

## 常见问题
<a name="garbage-collection-faq"></a>

### 如何识别垃圾回收效率低下？
<a name="w2aac61c15c17b3"></a>

监控以下表明垃圾回收效率低下的警告信号：
+ **集合膨胀过大 ** — 在大量写入或批量删除期间，`unusedStorageSize`指标稳步增加，尤其是对于大型索引。
+ **高死亡碎片百分比 ** — `documentFragmentStats` 显示持续较高的`deadDocFragmentsPercent`数值（高于 10-15%）。
+ **查询延迟降级 **-由于累积的失效文档导致查询延迟增加。
+ **延长了 GC 持续时间 ** — 垃圾收集操作所花费的时间比历史平均值长`gcRuntimeStats`。
+ **GC 处理能力提高 ** — 高`LongestActiveGCRuntime`表示垃圾回收器无法满足系统需求。

### 垃圾回收会影响我的数据库性能吗？
<a name="w2aac61c15c17b5"></a>

正常情况下，垃圾回收对性能的影响微乎其微。但是，当垃圾回收滞后时，您可能会遇到：
+ 累积的失效文件增加了存储成本。
+ 由于索引条目过时，查询性能较慢。
+ 如果 MVCC ID 已用尽，则使用临时只读模式。
+ 在密集收集运行期间，尤其是在较小的实例上，资源使用量更高。
+ 大型文档的扩展存储段操作效率降低。

### 我是否可以手动触发垃圾回收？
<a name="w2aac61c15c17b7"></a>

不可以，无法手动触发 Amazon DocumentDB 中的垃圾回收。作为内部维护操作的一部分，系统会自动管理垃圾回收。

### 作为操作最佳实践，我应该设置哪些警报？
<a name="w2aac61c15c17b9"></a>

在集群和集合级别设置监控，以确保您的 Amazon DocumentDB 系统的最佳性能。

要进行集群级监控，首先为该指标创建亚马逊 CloudWatch 警报，在亚马逊DocumentDB 5.0及更高版本上，该`AvailableMVCCIds`指标的阈值为9亿，在亚马逊DocumentDB 3.6和4.0上的阈值为13亿。这使您有足够的时间在指标达到零（届时您的集群将进入只读模式）之前采取措施。请记住，该指标可能会根据您的特定使用模式而波动——一些客户看到该指标已降至阈值以下，然后随着垃圾收集工作的完成而恢复到15亿以上。

通过亚马逊监控该`LongestActiveGCRuntime`指标也很重要 CloudWatch。此指标与 `gcRuntimeStats` 一起可帮助您了解整个系统中垃圾回收的执行效率。

要进行馆藏级监控，请重点关注以下关键指标：
+ `MVCCIdScale`— 注意值的增大，这表明 MVCC ID 正在老化，可能需要注意。
+ `gcRuntimeStats`— 确定耗时异常长或持续数天的垃圾收集过程。
+ `documentFragmentStats`— 监控`deadDocFragmentsPercent`值-持续较高的百分比（高于 10-15%）可能表明垃圾回收落后了。
+ `storageSizeStats`和 `unusedStorageSize` — 跟踪存储利用模式，确定任一存储段中包含大量未使用空间的集合。

需要特别注意具有频繁写入操作的集合，因为其会增加垃圾收集器的工作。对于写入活动繁重的集合，更频繁地检查这些指标，以确保垃圾收集与您的工作负载保持同步。

请注意，这些监控建议仅作为起点。随着您对系统行为越来越熟悉，您可能需要调整这些阈值以更好地匹配您的具体使用模式和要求。

### 如果我的`可用 MVCCID` 低于警报阈值，我该怎么做？
<a name="w2aac61c15c17c11"></a>

如果您的`AvailableMVCCIds`指标降至警报阈值以下，请立即采取措施防止您的集群进入只读模式。首先，扩大您的实例大小，为垃圾收集器提供更多的计算资源。这使您的应用程序能够继续正常运行，同时为垃圾回收器提供跟上节奏所需的额外能力。

如果单独向上扩展并不能改善这种情况，请考虑减少写入操作。使用 `MVCCIdScale` 指标识别哪些特定集合包含需要注意的较旧 MVCC ID。此外，还`documentFragmentStats`要进行监控，以识别失效碎片百分比高的集合，这些集合可能导致垃圾收集效率低下。

确定这些集合后，可能需要暂时减少对它们的写入操作，以允许垃圾收集赶上。在恢复期间，密切监控`AvailableMVCCIds`指标，确保您的行为达到预期的效果。`AvailableMVCCIds` 值恢复到 15 亿或更高后，您的集群就会被视为运行状况良好。

请记住，这些步骤属于预防性措施，旨在帮助系统在达到紧急状态前恢复。在看到指标降至阈值以下后，越早采取行动，就越有可能避免对写入操作造成任何影响。

### 批量操作会影响 MVCC ID 消耗率吗？
<a name="w2aac61c15c17c13"></a>

可以。由于在单个原子事务中执行的批次仅消耗一个 MVCC ID，因此将写入分组为批次会降低 MVCC ID 的消耗速率。最佳做法是，`updateMany`尽可能使用`insertMany`和，以最大限度地减少 MVCC ID 消耗并减少垃圾收集的负担。

### 为什么 ava `ilableMvcIDS 在达到一定阈值之前无法`恢复？
<a name="w2aac61c15c17c15"></a>

对于以`AvailableMVCCIds`写入为主的工作负载，如果尚未消耗足够的 MVCC ID 来触发垃圾收集回收周期，预计会暂时稳步下降，无法恢复。当满足以下任何条件时，就会触发垃圾回收：集合中的某一部分文档过时、插入新文档的特定部分或`AvailableMVCCIds`降至回收阈值以下。

除非`AvailableMVCCIds`降至回收阈值以下，否则不会发生强制回收。一旦发生，回收`AvailableMVCCIds`就会触发并恢复。但是，即使在达到阈值之后，长时间运行的事务和打开的游标也会固定回收期限，并阻止回收。