

# 排查 S3 批量操作问题
<a name="troubleshooting-batch-operations"></a>

Amazon S3 批量操作可让您对 Amazon S3 对象执行大规模操作。本指南有助于排查您可能遇到的常见问题。

要排查 S3 批量复制的问题，请参阅[对复制进行问题排查](replication-troubleshoot.md)。

导致批量操作错误的失败主要有两种类型：

1. **API 失败**：所请求的 API（例如 `CreateJob`）执行失败。

1. **作业失败**：初始 API 请求获得成功但作业失败，例如，由于清单或在清单中指定的对象的权限存在问题。

## NoSuchJobException
<a name="nosuchjobexception"></a>

**类型：**API 失败

当 S3 批量操作找不到指定的作业时，就会发生 `NoSuchJobException`。除了简单的作业到期之外，还可能在多种情况下发生此错误。常见原因包括以下各项：

1. **作业到期**：作业在达到终止状态（`Complete`、`Cancelled` 或 `Failed`）的 90 天后自动被删除。

1. **作业 ID 不正确**：`DescribeJob` 或 `UpdateJobStatus` 中使用的作业 ID 与 `CreateJob` 返回的 ID 不匹配。

1. **错误的区域**：尝试访问的作业所在的区域与创建该作业的区域不同。

1. **账户错误**：使用其它 Amazon 账户中的作业 ID。

1. **作业 ID 格式错误**：作业 ID 中存在拼写错误、多余字符或格式不正确。

1. **计时问题**：在完全注册作业之前，在创建后立即检查作业状态。

相关错误消息包括以下各项。

1. `No such job`

1. `The specified job does not exist`

### 防止 `NoSuchJobException` API 失败的最佳实践
<a name="nosuchjobexception-prevention"></a>

1. **立即存储作业 ID**：在进行后续的 API 调用之前，先保存 `CreateJob` 响应中的作业 ID。

1. **实现重试逻辑**：在创建作业后立即检查作业状态时添加指数回退。

1. **设置监控**：创建 CloudWatch 警报以跟踪作业在 90 天到期之前的完成情况。有关详细信息，请参阅《Amazon CloudWatch 用户指南》中的[使用 Amazon CloudWatch 警报](https://docs.amazonaws.cn/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html)。

1. **使用一致的区域**：确保所有作业操作使用与创造作业相同的区域。

1. **验证输入**：在进行 API 调用之前检查作业 ID 格式。

### 作业何时到期
<a name="nosuchjobexception-jobs-expire"></a>

处于终止状态的作业将在 90 天后被自动删除。为避免丢失作业信息，请考虑以下事项。

1. **在到期前下载完成报告**：有关检索和存储作业结果的说明，请参阅[ 完成报告  在创建任务时，您可以请求完成报告。只要 S3 批量操作成功调用至少一项工作，Amazon S3 便会在任务完成运行工作、失败或被取消后生成完成报告。可对完成报告进行配置，以包含所有任务或只包含失败的任务。 完成报告包含任务配置、状态以及每项工作的信息，包括对象键和版本、状态、错误代码以及有关任何错误的描述。完成报告提供了以合并格式查看任务结果的简单途径，且无需进行任何附加设置。完成报告使用具有 Amazon S3 托管式密钥的服务器端加密（SSE-S3）来进行加密。有关完成报告的示例，请参阅 [示例：S3 分批操作完成报告](batch-ops-examples-reports.md)。 如果您未配置完成报告，则仍可使用 CloudTrail 和 Amazon CloudWatch 监控并审计您的任务及其各项工作。有关更多信息，请参阅以下主题： ](batch-ops-job-status.md#batch-ops-completion-report.title)。

1. **在您自己的系统中归档作业元数据**：将关键的作业信息存储在数据库或监控系统中。

1. **设置 90 天截止日期之前的自动通知**：使用 Amazon EventBridge 创建在作业完成时触发通知的规则。有关更多信息，请参阅 [Amazon S3 事件通知](EventNotifications.md)。

### `NoSuchJobException` 故障排除
<a name="nosuchjobexception-troubleshooting"></a>

1. 使用以下命令验证作业是否存在于您的账户和区域中。

   ```
   aws s3control list-jobs --account-id {{111122223333}} --region {{us-east-1}}
   ```

1. 使用以下命令在所有作业状态间进行搜索。可能的作业状态包括 `Active`、`Cancelled`、`Cancelling`、`Complete`、`Completing`、`Failed`、`Failing`、`New`、`Paused`、`Pausing`、`Preparing`、`Ready`、和 `Suspended`。

   ```
   aws s3control list-jobs --account-id {{111122223333}} --job-statuses {{your-job-status}}
   ```

1. 使用以下命令检查作业是否存在于您通常创建作业的其它区域中。

   ```
   aws s3control list-jobs --account-id {{111122223333}} --region {{job-region-1}} aws s3control list-jobs --account-id {{111122223333}} --region {{job-region-2}}                    
   ```

1. 验证作业 ID 格式。作业 ID 通常包含 36 个字符，例如 `12345678-1234-1234-1234-123456789012`。检查是否有多余的空格、缺少字符或是否存在区分大小写问题，并验证您使用的是 `CreateJob` 命令返回的完整作业 ID。

1. 使用以下命令检查 CloudTrail 日志中是否存在作业创建事件。

   ```
       aws logs filter-log-events --log-group-name CloudTrail/S3BatchOperations \ --filter-pattern "{ $.eventName = CreateJob }" \ --start-time {{timestamp}}                    
   ```

### AccessDeniedException
<a name="accessdeniedexception"></a>

**类型：**API 失败

由于权限不足、操作不受支持或策略限制而阻止 S3 批量操作请求时，就会发生 `AccessDeniedException`。这是批量操作中最常见的错误之一。它具有以下常见原因：

1. **缺少 IAM 权限**：IAM 身份缺少批量操作 API 所需的权限。

1. **S3 权限不足**：缺少访问源或目标存储桶和对象的权限。

1. **作业执行角色问题**：作业执行角色缺少执行指定操作的权限。

1. **操作不受支持**：尝试使用当前区域或存储桶类型不支持的操作。

1. **跨账户访问问题**：缺少跨账户访问存储桶或对象的权限。

1. **基于资源的策略限制**：存储桶策略或对象 ACL 阻止操作。

1. **服务控制策略（SCP）限制**：组织级策略阻止操作。

相关错误消息：

1. `Access Denied`

1. `User: arn:aws:iam::account:user/username is not authorized to perform: s3:operation`

1. `Cross-account pass role is not allowed`

1. `The bucket policy does not allow the specified operation`

#### 防止 AccessDeniedException API 失败的最佳实践
<a name="accessdeniedexception-prevention"></a>

1. **使用最低权限原则**：仅授予特定操作所需的最小权限。

1. **在大型作业之前测试权限**：在处理成千上万个对象之前，运行小型测试作业来验证权限。

1. **使用 IAM 策略模拟器**：在部署之前使用 IAM 策略模拟器测试策略。有关更多信息，请参阅《IAM 用户指南》中的[使用 IAM 策略模拟器测试 IAM 策略](https://docs.amazonaws.cn/IAM/latest/UserGuide/access_policies_testing-policies.html)。

1. **实施正确的跨账户设置**：检查您的跨账户访问配置以了解跨账户作业配置。有关更多信息，请参阅《IAM 用户指南》中的 [IAM 教程：使用 IAM 角色委托跨 Amazon 账户的访问权限](https://docs.amazonaws.cn/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html)。

1. **监控权限变更**：针对可能影响批量操作的 IAM 策略修改设置 CloudTrail 提醒。

1. **记录角色要求**：清晰地记录每种作业类型的所需权限。

1. **使用常用权限模板**：使用权限示例和策略模板：

   1. [授予批处理操作的权限](batch-ops-iam-role-policies.md)

   1. 《IAM 用户指南》中的 [IAM 中的跨账户资源](https://docs.amazonaws.cn/IAM/latest/UserGuide/access_policies-cross-account-resource-access.html)。

   1. 《Amazon PrivateLink Guide》中的 [Control access to VPC endpoints using endpoint policies](https://docs.amazonaws.cn/vpc/latest/privatelink/vpc-endpoints-access.html)。

#### AccessDeniedException 故障排除
<a name="accessdeniedexception-troubleshooting"></a>

按照以下步骤系统化地识别和解决权限问题。

1. 查看 [S3 分批操作支持的操作](batch-ops-operations.md)以了解按区域支持的操作。确认目录存储桶操作仅适用于区域端点和可用区端点。验证存储桶的存储类别支持该操作。

1. 使用以下命令确定您是否可以列出作业。

   ```
    aws s3control list-jobs --account-id {{111122223333}}
   ```

1. 使用以下命令检查请求身份的 IAM 权限。运行作业的账户需要以下权限：`s3:CreateJob`、`s3:DescribeJob`、`s3:ListJobs`、`s3:UpdateJobPriority`、`s3:UpdateJobStatus` 和 `iam:PassRole`。

   ```
   aws sts get-caller-identity {{111122223333}}
   ```

1. 使用以下命令检查角色是否存在以及是否可代入。

   ```
   aws iam get-role --role-name {{role-name}}
   ```

1. 使用以下命令查看角色的信任策略。运行作业的角色必须具有以下各项：

   1. 可让 `batchoperations.s3.amazonaws.com` 代入此角色的信任关系。

   1. 批量操作正在执行的操作（例如，对于标记操作为 `s3:PutObjectTagging`）。

   1. 对源存储桶和目标存储桶的访问权限。

   1. 读取清单文件的权限。

   1. 写入完成报告的权限。

   ```
   aws iam get-role --role-name {{role-name}} --query 'Role.AssumeRolePolicyDocument'
   ```

1. 使用以下命令可测试对清单和源存储桶的访问权限。

   ```
   aws s3 ls s3://{{amzn-s3-demo-bucket}}                        
   ```

1. 测试批量操作正在执行的操作。例如，如果批量操作执行标记操作，则在源存储桶中为示例对象添加标签。

1. 查看存储桶策略，以了解是否存在可能拒绝该操作的策略。

   1. 如果使用旧版访问控制，请检查对象 ACL。

   1. 验证没有服务控制策略（SCP）阻止该操作。

   1.  如果使用 VPC 端点，请确认 VPC 端点策略支持批量操作。

1. 通过以下命令使用 CloudTrail 来识别权限故障。

   ```
   aws logs filter-log-events --log-group-name CloudTrail/S3BatchOperations \
       --filter-pattern "{ $.errorCode = AccessDenied }" \
       --start-time {{timestamp}}
   ```

#### SlowDownError
<a name="slowdownerror"></a>

**类型：**API 失败

当您的账户超过 S3 批量操作 API 的请求速率限制时，就会出现 `SlowDownError` 异常。这是一种节流机制，旨在防止服务因请求过多而不堪重负。它具有以下常见原因：

1. **API 请求频率高**：在短时间内进行过多的 API 调用。

1. **并行作业操作**：多个应用程序或用户同时创建/管理作业。

1. **没有速率限制的自动化脚本**：未实施正确的回退策略的脚本。

1. **过于频繁地轮询作业状态**：检查作业状态的频率超出所需程度。

1. **突增流量模式**：在高峰处理时段，API 使用量突然激增。

1. **区域容量限制**：超过您的区域的已分配请求容量。

相关错误消息：

1. `SlowDown`

1. `Please reduce your request rate`

1. `Request rate exceeded`

#### 防止 SlowDownError API 失败的最佳实践
<a name="slowdownerror-prevention"></a>

1. **实施客户端速率限制**：在应用程序中的 API 调用之间添加延迟。

1. **使用指数回退以及抖动**：随机化重试延迟，以避免出现惊群效应问题。

1. **设置正确的重试逻辑**：实施自动重试，并增加瞬态错误的延迟。

1. **使用事件驱动的架构**：将轮询替换为有关作业状态更改的 EventBridge 通知。

1. **跨时间分配负载**：将作业创建和状态检查错开在不同的时间段内进行。

1. **监控速率限制并发出提醒**：设置 CloudWatch 警报以便在接近限制时进行检测。

大多数 Amazon SDK 都包含针对速率限制错误的内置重试逻辑。按如下所示对它们进行配置：

1. **Amazon CLI**：使用 `cli-read-timeout` 和 `cli-connect-timeout` 参数。

1. **适用于 Python 的 Amazon SDK（Boto3）**：在客户端配置中配置重试模式和最大尝试次数。

1. **适用于 Java 的 Amazon SDK**：使用 `RetryPolicy` 和 `ClientConfiguration` 设置。

1. **适用于 JavaScript 的 Amazon SDK**：配置 `maxRetries` 和 `retryDelayOptions`。

有关重试模式和最佳实践的更多信息，请参阅《Amazon Prescriptive Guidance》指南中的 [Retry with backoff pattern](https://docs.amazonaws.cn/prescriptive-guidance/latest/cloud-design-patterns/retry-backoff.html)。

#### SlowDownError 故障排除
<a name="slowdownerror-troubleshooting"></a>

1. 在代码中立即实现指数回退。  
**Example ：bash 中的指数回退**  

   ```
   for attempt in {1..5}; do
       if aws s3control describe-job --account-id {{111122223333}} --job-id {{job-id}}; then 
           break
       else 
           wait_time=$((2**attempt)) echo "Rate limited, waiting ${wait_time} seconds..." sleep $wait_time
           fi
   done
   ```

1. 使用 CloudTrail 来识别高请求量的源。

   ```
   aws logs filter-log-events \
       --log-group-name CloudTrail/S3BatchOperations \
       --filter-pattern "{ $.eventName = CreateJob || $.eventName = DescribeJob }" \
       --start-time {{timestamp}} \
       --query 'events[*].[eventTime,sourceIPAddress,userIdentity.type,eventName]'
   ```

1. 查看轮询频率。

   1. 对于处于活动状态的作业，请避免检查作业状态的频率超过每 30 秒一次。

   1. 尽可能使用作业完成通知而非轮询。

   1. 在轮询间隔中实施抖动，以避免同步的请求。

1. 优化 API 使用模式。

   1. 如果可能，请批量执行多个操作。

   1. 使用 `ListJobs` 在一次调用中获取多个作业的状态。

   1. 缓存作业信息以减少冗余的 API 调用。

   1. 将作业创建操作分散到不同的时间，而不是同时创建许多作业。

1. 针对 API 调用使用 CloudWatch 指标来监控请求模式。

   ```
      aws logs put-metric-filter \
          --log-group-name CloudTrail/S3BatchOperations \
          --filter-name S3BatchOpsAPICallCount \      
          --filter-pattern "{ $.eventSource = s3.amazonaws.com && $.eventName = CreateJob }" \
          --metric-transformations \        
          metricName=S3BatchOpsAPICalls,metricNamespace=Custom/S3BatchOps,metricValue=1
   ```

## InvalidManifestContent
<a name="invalidmanifestcontent"></a>

**类型：**作业失败

当清单文件格式、内容或结构出现问题而导致 S3 批量操作无法处理作业时，就会出现 `InvalidManifestContent` 异常。它具有以下常见原因：

1. **格式违规**：缺少必需列、分隔符不正确或 CSV 结构的格式错误。

1. **内容编码问题**：字符编码、BOM 标记或非 UTF-8 字符不正确。

1. **对象键问题**：字符无效、URL 编码不正确或键超过长度限制。

1. **大小限制**：清单包含的对象数量超过了操作支持的数量。

1. **版本 ID 格式错误**：受版本控制的对象的版本 ID 无效或格式错误。

1. **ETag 格式问题**：ETag 格式不正确，或需要 ETag 的操作缺少引号。

1. **数据不一致**：同一个清单中具有混合格式或列计数不一致。

相关错误消息：

1. `Required fields are missing in the schema: + missingFields`

1. `Invalid Manifest Content`

1. `The S3 Batch Operations job failed because it contains more keys than the maximum allowed in a single job`

1. `Invalid object key format`

1. `Manifest file is not properly formatted`

1. `Invalid version ID format`

1. `ETag format is invalid`

### 防止 InvalidManifestContent 作业失败的最佳实践
<a name="invalidmanifestcontent-prevention"></a>

1. **上传前验证**：在处理大型数据集之前，使用小型作业测试清单格式。

1. **使用一致的编码**：对于清单文件，始终使用无 BOM 的 UTF-8 编码。

1. **实施清单生成标准**：为创建清单操作创建模板和验证过程。

1. **正确地处理特殊字符**：对包含特殊字符的对象键进行 URL 编码。

1. **监控对象计数**：跟踪清单大小并主动拆分大型作业。

1. **验证对象存在**：在将对象包括在清单中之前，先验证对象是否存在。

1. **使用 Amazon 工具生成清单**：利用 Amazon CLI `s3api list-objects-v2` 生成格式正确的对象列表。

常见清单问题和解决方案：

1. **缺少必需列**：确保清单包含适用于操作类型的所有必需列。最常见的缺失列是 Bucket 和 Key。

1. **CSV 格式不正确**：使用逗号分隔符，确保所有行的列计数一致，并避免在字段中嵌入换行符。

1. **对象键中的特殊字符**：对包含空格、Unicode 字符或 XML 特殊字符（<、>、&、"、'）的对象键进行 URL 编码。

1. **大型清单文件**：将超过操作限制的清单拆分为多个较小的清单并创建单独的作业。

1. **版本 ID 无效**：确保版本 ID 是格式正确的字母数字字符串。如果不需要版本 ID 列，请将其移除。

1. **编码问题**：将清单文件另存为无 BOM 的 UTF-8。避免通过可能更改编码的系统来复制清单。

有关详细的清单格式规范和示例，请参阅以下内容：

1. [指定清单](batch-ops-create-job.md#specify-batchjob-manifest)

1. [S3 分批操作支持的操作](batch-ops-operations.md)

1. [为 Amazon S3 对象命名](object-keys.md)

### InvalidManifestContent 故障排除
<a name="invalidmanifestcontent-troubleshooting"></a>

1. 下载并检查清单文件。手动验证清单是否符合格式要求：

   1. 使用逗号分隔符的 CSV 格式。

   1. 无 BOM 的 UTF-8 编码。

   1. 所有行的列数一致。

   1. 没有空行或尾随空格。

   1. 如果对象键包含特殊字符，已对对象键进行正确的 URL 编码。

   使用以下命令下载作业清单文件。

   ```
   aws s3 cp s3://{{amzn-s3-demo-bucket1}}/{{manifest-key}} {{./manifest.csv}} 
   ```

1. 检查您的操作所需的列：

   1. 所有操作：`Bucket`、`Key`

   1. 复制操作：`VersionId`（可选）

   1. 还原操作：`VersionId`（可选）

   1. 替换标签操作：无需其它列。

   1. 替换 ACL 操作：无需其它列。

   1. 启动还原：`VersionId`（可选）

1. 检查对象计数限制：

   1. 复制：最多 10 亿个对象。

   1. 删除：最多 10 亿个对象。

   1. 还原：最多 10 亿个对象。

   1. 添加标签：最多 10 亿个对象。

   1. ACL：最多 10 亿个对象。

1. 使用原始清单中的几个对象创建测试清单。

1. 使用以下命令检查清单中的对象示例是否存在。

   ```
   aws s3 ls s3://{{amzn-s3-demo-bucket1}}/{{object-key}}
   ```

1. 检查作业失败详细信息，并在作业描述中查看失败原因和任何特定错误详情。

   ```
   aws s3control describe-job --account-id {{111122223333}} --job-id {{job-id}}                        
   ```