Step Functions 的最佳实操 - Amazon Step Functions
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

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

Step Functions 的最佳实操

管理状态和转换数据

Step Functions 最近添加了变量JSONata,用于管理状态和转换数据。

了解如何使用变量传递数据使用转换数据JSONata

以下主题是有助于您管理和优化 Step Functions 工作流程的最佳实践。

使用快速工作流程优化成本

Step Functions 根据您用来构建状态机的工作流类型来确定标准和快速工作流的定价。要优化无服务器工作流的成本,您可以遵循以下一项或两项建议:

有关选择标准或快速工作流类型如何影响账单的信息,请参阅Amazon Step Functions 定价

在标准工作流程中嵌套快速工作流程

Step Functions 运行的工作流具有有限的持续时间和步骤数量。有些工作流可能会在短时间内完成执行。其他可能需要将长期运行和 high-event-rate工作流程结合起来。借助 Step Functions,您可以利用多个更小、更简单的工作流来构建大型复杂的工作流。

例如,要构建订单处理工作流,您可以将所有非幂等操作包含到标准工作流中。这可能包括通过人际互动批准订单和处理付款等操作。然后,您可以在快速工作流中组合一系列幂等操作,例如发送付款通知和更新产品库存。您可以将此快速工作流嵌套在标准工作流中。在此示例中,标准工作流被称为父状态机。嵌套的快速工作流被称为子状态机

将标准工作流程转换为快速工作流程

如果现有标准工作流满足以下要求,则可以将其转换为快速工作流:

  • 工作流必须在五分钟内完成执行。

  • 该工作流程符合at-least-once执行模型。这意味着工作流中的每个步骤都可能运行不止一次。

  • 工作流不使用 .waitForTaskToken.sync 服务集成模式。

重要

Express 工作流程使用 Amazon CloudWatch 日志记录执行历史记录。使用 Lo CloudWatch gs 时,您将产生额外费用。

使用控制台将标准工作流转换为快速工作流
  1. 打开 Step Functions 控制台

  2. 状态机页面上,选择一个标准类型的状态机将其打开。

    提示

    任意类型下拉列表中,选择标准以筛选状态机列表,并仅查看标准工作流。

  3. 选择复制到新项目

    Workflow Studio 在设计模式下打开,显示所选状态机的工作流。

  4. (可选)更新工作流设计。

  5. 为状态机指定一个名称。为此,请选择默认状态机名称旁边的编辑图标MyStateMachine。然后,找到状态机配置,在状态机名称框中指定一个名称。

  6. (可选)在状态机配置中,指定其他工作流设置,例如状态机类型及其执行角色。

    确保在类型中选择快速。保留状态机设置中的所有其他默认选项。

    注意

    如果您要转换之前在Amazon CDK或中定义的标准工作流程 Amazon SAM,则必须更改TypeResource名称的值。

  7. 确认角色创建对话框中,选择确认继续。

    您也可以选择查看角色设置,返回至状态机配置

    注意

    如果你删除 Step Functions 创建的IAM角色,Step Functions 以后将无法重新创建它。同样,如果您修改角色(例如,通过从IAM策略的主体中删除 Step Functions),Step Functions 以后将无法恢复其原始设置。

有关管理工作流程成本优化时的最佳实践和指南的更多信息,请参阅构建具有成本效益 Amazon Step Functions 的工作流程

在 Step Functions 中标记状态机和活动

Amazon Step Functions 支持标记状态机(标准和快速)和活动。标签可以帮助您跟踪和管理资源,并提高您的 Amazon Identity and Access Management (IAM) 策略的安全性。标记 Step Functions 资源后,你可以使用对其进行 Amazon Resource Groups管理。要了解如何操作,请参阅 Amazon Resource Groups User Guide

对于基于标签的授权,状态机执行资源(如下例所示)会继承与状态机关联的标签。

arn:<partition>:states:<Region>:<account-id>:execution:<StateMachineName>:<ExecutionId>

当您调用DescribeExecution或APIs以其他方式指定执行资源时ARN,Step Functions 会在执行基于标签的授权时使用与状态机关联的标签来接受或拒绝请求。这有助于在状态机级别允许或拒绝对状态机执行的访问。

要查看与资源标记相关的限制,请参阅与标记相关的限制

成本分配的标记

您可以使用成本分配标签来识别状态机的用途,并在 Amazon 账单中反映该组织。注册以获取包含标签密钥和值的 Amazon 账户账单。有关设置报告的详细信息,请参阅《Amazon Billing 用户指南》中的 Setting Up a Monthly Cost Allocation Report

例如,可以添加表示 Step Functions 资源的成本中心和用途的标签,如下所示。

资源
StateMachine1 Cost Center 34567
Application Image processing
StateMachine2 Cost Center 34567
Application Rekognition processing

标记以提高安全性

IAM 支持基于标签控制对资源的访问。要基于标签控制访问,请在 IAM 策略的条件元素中提供有关您的资源标签的信息。

例如,您可能会限制对下面这样的所有 Step Functions 资源的访问:在这些资源包含的标签中,具有键 environment 和值 production

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Deny", "Action": [ "states:TagResource", "states:DeleteActivity", "states:DeleteStateMachine", "states:StopExecution" ], "Resource": "*", "Condition": { "StringEquals": {"aws:ResourceTag/environment": "production"} } } ] }

有关更多信息,请参阅《IAM用户指南》中的使用标签控制访问权限

在 Step Functions 控制台中管理标签

可以在 Step Functions 控制台中查看和管理状态机的标签。在状态机的 Details (详细信息) 页面中,选择 Tags (标签)

使用 Step Functions API 操作管理标签

要使用 Step Functions 管理标签API,请使用以下API操作:

使用超时来避免 Step Functions 工作流程执行卡顿

默认情况下,Amazon States Language 不会为状态机定义指定超时。如果没有显式超时,Step Functions 通常仅依靠来自活动工作线程的响应来了解任务是否已完成。如果发生错误并且 ActivityTask 状态未指定 TimeoutSeconds 字段,则执行会卡住,等待永远不会出现的响应。

为避免这种情况,请在状态机中创建 Task 时指定合理的超时。例如:

"ActivityState": { "Type": "Task", "Resource": "arn:aws:states:us-east-1:123456789012:activity:HelloWorld", "TimeoutSeconds": 300, "Next": "NextState" }

如果您使用带有任务令牌的回调 (. waitForTaskToken),我们建议您使用心跳并在Task状态定义中添加该HeartbeatSeconds字段。您可以将 HeartbeatSeconds 设置为小于任务超时时间,因此,如果您的工作流因检测信号错误而失败,那么您就知道这是因为任务失败,而不是任务需要很长时间才能完成。

{ "StartAt": "Push to SQS", "States": { "Push to SQS": { "Type": "Task", "Resource": "arn:aws:states:::sqs:sendMessage.waitForTaskToken", "HeartbeatSeconds": 600, "Parameters": { "MessageBody": { "myTaskToken.$": "$$.Task.Token" }, "QueueUrl": "https://sqs.us-east-1.amazonaws.com/123456789012/push-based-queue" }, "ResultPath": "$.SQS", "End": true } } }

有关更多信息,请参阅 Amazon States Language 文档中的 Task 工作流程状态

注意

您可以使用 Amazon States Language 定义中的 TimeoutSeconds 字段为状态机设置超时。有关更多信息,请参阅 Amazon States Language 中用于 Step Functions 工作流程的状态机结构

使用 Amazon S3 ARNs 而不是在 Step Functions 中传递大型有效负载

可以终止在状态间传递大量数据负载的执行。如果您在各州之间传递的数据可能增长到 256 KiB 以上,请使用亚马逊简单存储服务 (Amazon S3) Service 来存储数据,并在Payload参数中解析存储桶的亚马逊资源名称 (ARN) 以获取存储桶名称和密钥值。或者,您也可以调整实现,以便在执行中传递较少的负载。

在以下示例中,状态机将输入传递给一个 Amazon Lambda 函数,该函数处理 Amazon S3 存储桶中的JSON文件。运行此状态机后,Lambda 函数读取文件内容,并将JSON文件内容作为输出返回。

创建 Lambda 函数

以下名为的 Lambda 函数pass-large-payload读取存储在特定 Amazon S3 存储桶中的JSON文件内容。

注意

创建此 Lambda 函数后,请确保为其IAM角色提供相应的权限,使其能够从 Amazon S3 存储桶中读取。例如,将 AmazonS3 ReadOnlyAccess 权限附加到 Lambda 函数的角色。

import json import boto3 import io import os s3 = boto3.client('s3') def lambda_handler(event, context): event = event['Input'] final_json = str() s3 = boto3.resource('s3') bucket = event['bucket'].split(':')[-1] filename = event['key'] directory = "/tmp/{}".format(filename) s3.Bucket(bucket).download_file(filename, directory) with open(directory, "r") as jsonfile: final_json = json.load(jsonfile) os.popen("rm -rf /tmp") return final_json
创建状态机

以下状态机调用您之前创建的 Lambda 函数。

{ "StartAt":"Invoke Lambda function", "States":{ "Invoke Lambda function":{ "Type":"Task", "Resource":"arn:aws:states:::lambda:invoke", "Parameters":{ "FunctionName":"arn:aws:lambda:us-east-2:123456789012:function:pass-large-payload", "Payload":{ "Input.$":"$" } }, "OutputPath": "$.Payload", "End":true } } }

与其在输入中传递大量数据,不如将这些数据保存在 Amazon S3 存储桶中,然后在Payload参数中传递存储桶的 Amazon 资源名称 (ARN) 以获取存储桶名称和密钥值。然后,您的 Lambda 函数可以使用它直接ARN访问数据。以下是状态机执行的输入示例,其中数据以 amzn-s3-demo-large-payload-json 形式存储在名为 data.json 的 Amazon S3 存储桶中。

{ "key": "data.json", "bucket": "arn:aws:s3:::amzn-s3-demo-large-payload-json" }

在 Step Functions 中启动新的执行以避免达到历史记录配额

Amazon Step Functions 在执行事件历史记录中有 25,000 个条目的硬配额。当执行达到 24,999 个事件时,它会等待下一个事件发生。

  • 如果事件编号为 25,000 是 ExecutionSucceeded,则执行成功完成。

  • 如果事件编号 25,000 不是 ExecutionSucceeded,则会记录 ExecutionFailed 事件,状态机执行因达到历史记录上限而失败

为了避免长时间运行的执行达到此配额,您可以尝试以下一种变通方法:

处理短暂的 Lambda 服务异常

Amazon Lambda 偶尔会遇到暂时的服务错误。在这种情况下,调用 Lambda 会导致 500 错误,例如 ClientExecutionTimeoutExceptionServiceExceptionAWSLambdaExceptionSdkClientException。作为最佳实操,在状态机中主动处理这些异常,以 Retry 调用 Lambda 函数或 Catch 错误。

Lambda 错误报告为 Lambda.ErrorName。要重试 Lambda 服务异常错误,可以使用以下 Retry 代码。

"Retry": [ { "ErrorEquals": [ "Lambda.ClientExecutionTimeoutException", "Lambda.ServiceException", "Lambda.AWSLambdaException", "Lambda.SdkClientException"], "IntervalSeconds": 2, "MaxAttempts": 6, "BackoffRate": 2 } ]
注意

Lambda 中未处理的错误在错误输出中报告为 Lambda.Unknown。其中包括 out-of-memory错误和函数超时。您可以匹配 Lambda.UnknownStates.ALLStates.TaskFailed 来处理这些错误。当 Lambda 达到最大调用次数时,会出现 Lambda.TooManyRequestsException 错误。有关 Lambda HandledUnhandled 错误的更多信息,请参阅 Amazon Lambda 开发人员指南中的 FunctionError

有关更多信息,请参阅下列内容:

避免轮询活动任务时发生延迟

GetActivityTaskAPI旨在只提供一taskToken。如果在通过活动工作线程通信时 taskToken 被丢弃,大量 GetActivityTask 请求可能会被阻止 60 秒以等待响应,直至 GetActivityTask 超时。

如果只有少量轮询等待响应,则可能所有请求都会排在被阻止的请求之后,无法处理。但是,如果您对每项活动 Amazon Resource Name (ARN) 都有大量未完成的民意调查,并且您的请求中有一定比例处于等待状态,那么还有更多请求仍然可以获得taskToken并开始处理工作。

对于生产系统,我们建议每个活动ARN在每个时间点至少进行100次公开投票。如果一个轮询被阻止,其后有一部分轮询排队,在 GetActivityTask 请求被阻止时,仍然有更多请求将获得 taskToken 可以处理工作。

避免在轮询任务时出现这类延迟问题:

  • 在活动工作线程实现的工作之外通过单独的线程实现轮询器。

  • 每个时间点每项活动ARN至少有 100 次公开投票。

    注意

    将每个民意调查扩展到100次ARN可能很昂贵。例如,每个 100 个 Lambda 函数进行轮询的成本ARN是拥有一个 100 个轮询线程的 Lambda 函数的 100 倍。要降低延迟 最大限度减少成本,请使用具有异步 I/O 的语言,并且每个工作线程实施多个轮询线程。有关轮询器线程独立于工作线程的示例活动工作线程,请参阅示例:Ruby 中的活动工作线程

有关活动和活动工作线程的更多信息,请参阅了解 Step Functions 中的活动

CloudWatch 日志资源策略大小限制

当您创建带有日志记录的状态机或更新现有状态机以启用日志记录时,Step Function CloudWatch s 必须使用您指定的日志组更新您的日志资源策略。 CloudWatch 日志资源策略限制在 5,120 个字符以内。

当 CloudWatch Logs 检测到策略接近大小限制时,Lo CloudWatch gs 会自动为以开头的日志组启用日志记录/aws/vendedlogs/

您可以在 CloudWatch 日志日志组名称前加上前缀/aws/vendedlogs/,以避免 CloudWatch 日志资源策略的大小限制。如果您在 Step Functions 控制台中创建日志组,则建议的日志组名称将已经以 /aws/vendedlogs/states 为前缀。

CloudWatch 日志还有每个账户每个区域 10 个资源策略的配额。如果您尝试在某个账户的某个区域中已有 10 个 CloudWatch 日志资源策略的状态机上启用登录功能,则不会创建或更新状态机。有关记录报价的更多信息,请参阅CloudWatch 日志配额

如果您在向 Logs 发送 CloudWatch 日志时遇到问题,请参阅Troubleshooting state machine logging to CloudWatch Logs。要了解有关一般日志记录的更多信息,请参阅启用来自 Amazon 服务的日志记录