想象你是一家高档餐厅的厨师长。后厨里有十来位“临时工”厨师,每位只会做一道菜,做完就收工走人,不记得自己刚才做了什么。顾客点一桌宴席,如果没人统筹,这些厨师就会各做各的:有人已经炒完第二道菜,有人还在等第一道菜的食材,整个厨房乱成一锅粥。 你的核心工作,就是让这些“过目即忘”的厨师按正确顺序协作。主厨手里那张菜谱,就是状态机;每位厨师的任务单,就是一个个 Serverless 函数。函数本身无状态且短暂,但主厨通过状态机把它们的执行顺序、失败重试、条件分支全部管起来,最终让整桌宴席准时上齐。这就是 Serverless 函数编排 的核心思想——用状态机这一“流程总指挥”,优雅地编排分布式函数调用。

岗位关联

对 AI 从业者而言,函数编排和状态机是云原生架构的必修技能。掌握了它,你就能把复杂的分布式系统拆成清晰的步骤流,让系统像宴席流水线一样既高效又可容错,大幅提升架构设计能力与面试竞争力。

目录
  1. 可视化演示
  2. 编排器角色
  3. 状态机基础
  4. StepFunctions
  5. 错误重试
  6. 分支逻辑
  7. 应用场景
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

\u901a\u8fc7\u4e09\u9636\u6bb5\u4ea4\u4e92\u5c55\u793a\u72b6\u6001\u673a\u6267\u884c\u6d41\u7a0b\u3001\u9519\u8bef\u91cd\u8bd5\u4e0e\u8865\u507f\u673a\u5236\u53ca\u591a\u6a21\u5f0f\u7f16\u6392\u7b56\u7565\u3002

本节配有交互动效(进入视口后自动加载,约 3KB)。

\u72b6\u6001\u673a\u6267\u884c\u6d41\u7a0b \u987a\u5e8f\u6267\u884c \u72b6\u6001\u8f6c\u79fb S\u2090\u2192S\u2098 \u6709\u9650\u72b6\u6001\u673a\u9a71\u52a8\u6d41\u7a0b

编排器角色

在餐厅后厨,主厨最清楚一件事:光靠“能人”,做不成一桌席。每位厨师都是顶尖的“单项选手”,但他们记忆极差——做完一道菜就忘记之前的一切。Serverless 中的函数恰如这些临时工:每次调用都是全新进程,不保存上一次的内存状态。如果让它们凭“记忆”彼此协作,流程必然断裂。因此,函数设计上要单一职责——一个函数只做“切菜”“炒菜”或“摆盘”中的一件小事。

无状态函数带来了一个矛盾:系统需要状态,而函数不持有状态。这就像每个厨师都不记得菜做到哪一步,但整桌宴席必须按顺序上菜。解法就是引入一位“主厨”——编排器。编排器是一个持久存在的工作流大脑,它持有“当前做到哪一步”的信息,按既定顺序逐个唤起函数,并把上一个函数的输出传给下一个。这就是函数编排的本质:把无状态的函数串成有条理的工作流。

在技术实现上,每一步函数执行后,编排器都会把它返回的数据存下来,并依据结果决定接下来调用哪个函数。对调用方来说,整个流程就像一次超级函数调用——你只管发起请求,流程内部如何流转、状态如何保存,都由编排器替你操心。

主厨不需要亲自做菜,他只负责“看单、派单、盯进度”。同理,编排器不执行业务计算,它只负责状态流转和函数调度——这类架构里,编排器是大脑,函数是手脚,各司其职,整条流水线才稳。

st+1=δ(st,et)s_{t+1} = \delta(s_t, e_t)
状态机的工作规律:当前状态 \(s_t\) 遇到一个事件 \(e_t\)(如“支付成功”),就通过转换函数 \(\delta\) 跳到下一个状态 \(s_{t+1}\)。
  1. 当前状态 \(s_t\)工作流此刻所在的位置,比如主厨手记上写着“备货中”。
    st=当前步骤名称s_t = \text{当前步骤名称}
  2. 触发事件 \(e_t\)驱动流转的输入,比如“顾客扫码支付了”或“食材已送达”。
    et=外部输入或上游函数返回的事件e_t = \text{外部输入或上游函数返回的事件}
  3. 转换函数 \(\delta\)定义了“在哪个状态+哪个事件 → 去哪”,相当于菜谱上的步骤连线。
    δ:S×Σ→S\delta: S \times \Sigma \rightarrow S

状态机基础

主厨手里那张菜谱,其实就是一台“状态机”的化身。菜谱上每一行都写得很清楚:先切菜(状态A),如果锅热了(事件),就下锅翻炒(进入状态B),炒熟后装盘(进入状态C)。状态机的定义也完全如此:状态 + 事件 + 转换规则。理解状态机,是理解一切编排工具的地基。

一台严格的状态机,由五个要素组成:状态集合、事件集合、转换函数、初始状态和终止状态集合。这就像一张宴席流程表必须写明:一共几道菜(状态集合)、什么条件触发换菜(事件)、每道菜之后上什么(转换函数)、从哪道菜开始(初始状态)、上到哪道算结束(终止状态)。离开了这五要素,任何“流程图”都只是画着好看的纸,无法落地执行。

在实际执行模型中,状态机一次只能处于一个状态,必须等待下一个事件到来才发生转换。这种“一次一步、事件驱动”的执行模型,天然适合拆解分布式业务——每一步的执行结果都是下一步的触发事件。想想看,后厨是不是也这样?主厨发出“上菜”指令后,必须等传菜员回报“已上桌”,才会继续安排下一道。

主厨的菜谱之所以可靠,是因为每一步都白纸黑字写得清清楚楚。状态机的价值也在于此:把流程从“口口相传的默契”变成“可验证、可执行的数学模型”——不依赖任何人的临场发挥,流程因此稳定、可复现、可审计。

M=(S, Σ, δ, s0, F)M = (S, \, \Sigma, \, \delta, \, s_0, \, F)
一台状态机 M 由状态集合 S、事件集合 Σ、转换函数 δ、初始状态 s₀ 和终止状态集合 F 五要素构成。
  1. 状态集合 \(S\)所有合法状态的集合,比如“待支付→已支付→已发货→已完成”。
    S={s0,s1,s2,…}S = \{ s_0, s_1, s_2, \ldots \}
  2. 事件集合 \(\Sigma\)所有能引起状态变化的输入事件集合。
    Σ={e0,e1,e2,…}\Sigma = \{ e_0, e_1, e_2, \ldots \}
  3. 转换函数 \(\delta\)给定当前状态和事件,返回唯一的下一状态。
    δ:S×Σ→S\delta: S \times \Sigma \rightarrow S
  4. 初始状态 \(s_0\)工作流启动时所在的状态,对应“宴席从开胃菜开始”。
    s0∈Ss_0 \in S
  5. 终止状态集合 \(F\)表示流程成功结束的合法终点。
    F⊆SF \subseteq S

StepFunctions

既然用手写菜谱太累,主厨值得拥有一块智能平板——上面画好流程模板,按一下就能自动派单、盯进度、记日志。AWS Step Functions 就是云上的这块“智能平板”。它是 AWS 提供的托管编排服务,你只需把状态机定义上传,平台就负责调度函数、保存状态、处理重试,并提供执行历史查询。

Step Functions 的核心是 ASL(Amazon States Language)——一种基于 JSON 的领域特定语言,用来描述状态机的每一个状态。每个状态对象里有几个关键字段:Type 声明状态类型(任务、选择、并行等),Resource 指向要调用的函数 ARN,Next 指明完成后去往哪个状态,Retry 定义重试策略,Catch 定义兜底处理。这样一个状态接一个状态,整条工作流就被完整描述出来了。

服务还提供了可视化的设计器画布,你在界面上拖拽状态节点、连线,系统自动生成 ASL 定义;运行时,每一步执行都会留下血统追踪记录——何时启动、哪个状态执行多久、结果如何,全部可查。这几个特性让 Step Functions 成为企业落地的首选:既能让你在画布上“看菜谱”,也能让运维人员在日志里“查老账”。

智能平板不是万能的,但它把主厨从“喊破喉咙”的指挥中解放出来,把精力放在真正需要智慧的地方。Step Functions 也一样——把调度、重试、追踪这些脏活累活交给托管服务,你只管专注业务设计。

State={Type:string,  Resource:ARN,  Next:name,  Retry:policy,  Catch:policy}\text{State} = \{ \text{Type}: \text{string}, \; \text{Resource}: \text{ARN}, \; \text{Next}: \text{name}, \; \text{Retry}: \text{policy}, \; \text{Catch}: \text{policy} \}
一个 ASL 状态对象由五个核心字段组成,它们共同定义了“这步做什么、失败怎么重试、下一步去哪”。
  1. 状态类型 Type声明这个状态是任务、选择、并行还是等待等。
    Type∈{Task,Choice,Parallel,Wait,…}\text{Type} \in \{ \text{Task}, \text{Choice}, \text{Parallel}, \text{Wait}, \ldots \}
  2. 任务资源 ResourceTask 状态要调用的函数 ARN,相当于“这道菜交给哪位厨师”。
    Resource=Lambda函数的ARN\text{Resource} = \text{Lambda函数的ARN}
  3. 下一状态 Next本状态成功完成后跳转的目标状态名。
    Next=下一个状态的名称\text{Next} = \text{下一个状态的名称}
  4. 重试策略 Retry定义失败后的重试规则(次数、间隔、退避倍数)。
    Retry={MaxAttempts,IntervalSeconds,BackoffRate}\text{Retry} = \{ \text{MaxAttempts}, \text{IntervalSeconds}, \text{BackoffRate} \}
  5. 兜底策略 Catch捕获指定错误后跳到降级处理状态。
    Catch={ErrorEquals,Next}\text{Catch} = \{ \text{ErrorEquals}, \text{Next} \}

错误重试

后厨有个铁律:菜炒糊了,绝不能直接端给顾客。最稳妥的做法是让厨师重新做一份——但也不能无限重做,否则顾客等到花儿都谢了。函数执行同样会失败:下游服务抖动、网络闪断、数据暂时不可用。此时编排器的第一反应就是“重试”,但重试要有策略,不能像无头苍蝇一样乱撞。

一个工程上常见的策略是指数退避:第一次失败后等 1 秒再试,第二次失败等 2 秒,第三次等 4 秒……间隔时间随尝试次数指数增长。为什么这么做?如果下游服务已经过载,立刻高频重试只会火上浇油,把它彻底压垮;而逐步拉长间隔,既给了下游恢复时间,又控制了自身对下游的冲击。这就像主厨吩咐“菜糊了先别急着骂人,等厨师深吸一口气再重做,越慌越容易再糊”。

仅仅重试还不够,流程还需要捕获降级的兜底。(Step Functions 的)Catch 可以让指定错误不再重试,而是流转到备用分支,比如“支付服务三次失败后,转人工处理”。这样整个工作流不会因一次失败而全线崩溃,能优雅降级、保住底线。

重试不是盲目的执着,而是有节制的智慧。主厨知道什么时候该重做、什么时候该换菜、什么时候该申请上级支援——状态机的重试与捕获,正是把这种“有节制的智慧”写进了可自动执行的规则中。

delay(n)=base×backoff (n−1)\text{delay}(n) = \text{base} \times \text{backoff}^{\,(n-1)}
第 n 次重试前需要等待的秒数:基础等待时间乘以退避倍数的 (n-1) 次方。
  1. 基础间隔 base第一次重试前等待的时间,工程上通常设为 1 秒。
    base=1 秒\text{base} = 1 \text{ 秒}
  2. 退避倍数 backoff每次重试后间隔增长的倍数,通常设为 2。
    backoff=2\text{backoff} = 2
  3. 尝试次数 n当前是第几次重试,从 1 开始计数。
    n=1,2,3,…n = 1, 2, 3, \ldots
  4. 综合计算 delay(n)第 n 次重试的等待秒数,指数级增长。
    delay(n)=1×2(n−1)=2(n−1) 秒\text{delay}(n) = 1 \times 2^{(n-1)} = 2^{(n-1)} \text{ 秒}

分支逻辑

宴席上十桌客人,有人不吃辣、有人海鲜过敏、有人点了儿童套餐。主厨不会让所有厨师做同一道菜,而是看一眼点菜单,把订单分流到不同的出餐线。状态机的 Choice 状态 就承担着这样的“分流”职责:它根据当前输入或上下文变量的值,选择不同的下一步。

Choice 状态的判断条件多种多样:字符串相等、数值大小比较、布尔值判断等。更强大的是 Parallel 并行状态——它可以同时启动多个分支执行多个函数,全部完成后才汇合继续。这就像一桌菜里有汤、有肉、有甜品,主厨让三位厨师同时开火,而不是傻等一道做完才做下一道,效率天差地别。

分支设计里有一项铁律:必须要有默认兜底分支。Choice 的多个条件都匹配不上时,如果没有默认路径,流程就会卡死。这好比客人点了一道菜单上没有的菜,如果主厨没有“推荐替代菜”的预案,就只能尴尬地站在那儿。一个健壮的流程,任何分支判断都要有“其他情况去哪”的答案。

分流是后厨高效运转的关键,也是流程设计的核心艺术。好的分支设计让系统能应对千变万化的业务输入,而不会在异常输入面前“僵住”——这正是状态机架构优于“写死逻辑”的地方。

next_state={A若金额≥100B若金额<100\text{next\_state} =\begin{cases}A & \text{若金额} \ge 100 \\B & \text{若金额} < 100\end{cases}
分支规则示例:金额 ≥ 100 走贵宾通道 A,否则走普通通道 B;没有匹配项时走默认兜底。
  1. 判断条件Choice 里每个分支都绑定一个判断表达式,比如金额比较。
    Variable:$.amount  ≥  100\text{Variable}: \$.\text{amount} \; \ge \; 100
  2. 条件分流表达式为真时,跳到对应分支状态。
    next=A当条件成立\text{next} = A \quad \text{当条件成立}
  3. 默认兜底所有条件都不成立时,进入预设的默认状态。
    next=Default若所有条件均不满足\text{next} = \text{Default} \quad \text{若所有条件均不满足}

应用场景

一场大型婚宴,几十桌客人,菜品必须同时准备:冷菜先上、热菜紧跟、甜品最后。主厨把后厨分成几条流水线,每条线负责一路菜系,再统一下令起菜。Serverless 状态机的典型应用,正是把这种“多条流水线、统一调度”的智慧搬到真实业务中。

最经典的应用是订单履约:下单后,状态机依次触发“支付核验”、“库存锁定”、“打包发货”三个函数,支付失败自动重试,库存不足则分支到“缺货通知”。数据处理流水线同样常见:每天凌晨从多个数据源抽取日志,状态机用并行分支同时拉取,全部到齐后开始清洗转换,最后加载进数仓。微服务编排则把多个服务的调用聚合到一个工作流里,比如用户注册后并行创建账户、发欢迎邮件、初始化配置。

这些场景有一个共同点:流程长、步骤多、有失败可能。传统做法是用一个上帝函数串起所有调用,代码里塞满 if-else、循环重试、状态标记,最后谁也维护不动。而状态机把这些横切关注点全部抽离出来,业务代码只关心“这一步做自己该做的事”,流程的骨架由状态机显式呈现,一眼就能看懂。

婚宴落幕,宾客满意而归,靠的不是哪个厨师技艺超群,而是主厨把每条流水线都安排得明明白白。状态机在真实业务中的作用同理——它不是炫技的工具,而是让复杂系统变得清晰、可靠、可演进的工程基石。

OrderFlow=下单→支付核验→库存锁定→打包发货→签收完成\text{OrderFlow} = \text{下单} \rightarrow \text{支付核验} \rightarrow \text{库存锁定} \rightarrow \text{打包发货} \rightarrow \text{签收完成}
一个典型的订单履约工作流,按顺序流转五个状态,每个状态对应一次函数调用或人工处理。
  1. 起始状态工作流从“下单”事件开始,进入第一个状态。
    s0=下单s_0 = \text{下单}
  2. 顺序流转每个状态完成后,通过事件驱动进入下一个状态。
    st+1=δ(st,success)s_{t+1} = \delta(s_t, \text{success})
  3. 终止状态最后一个状态“签收完成”是成功终点。
    s终∈Fs_\text{终} \in F

AI 应用场景

电商订单全链路履约

阶段:业务流程编排与自动化

解决的问题:传统订单系统用一个大函数串联支付、库存、物流调用,一旦某个环节失败,要么重头再来,要么留下一堆“半死不活”的脏数据。状态机将整条链路拆成多个无状态函数,由编排器统一调度,状态一目了然,失败自动重试,库存不足自动分支到缺货通知。

具体案例:用户在电商 App 下单后,状态机立刻开始流转:拉起支付核验函数 → 支付网关返回超时 → 触发指数退避重试,2 秒后重试成功 → 进入库存锁定函数 → 库存只剩 1 件,锁定成功 → 调用物流下单函数 → 返回运单号 → 状态机将整个执行历史写入日志。全程用户无感,系统自动完成了三次服务调用和一次故障恢复。

多源数据清洗流水线

阶段:数据处理与管道调度

解决的问题:数据分析平台每天要从多个数据源拉取日志,传统脚本用循环逐源拉取,单个源超时会导致整个管道阻塞。利用状态机的并行分支,多个拉取任务同时执行,任一分支超时只重试该分支,不影响全局。

具体案例:某广告平台每天凌晨从 S3、Kinesis、RDS 三个数据源拉取曝光日志。状态机用 Parallel 状态同时启动三个 Lambda 拉取函数,全部成功后在汇合点触发清洗函数,再用分支逻辑判断数据量是否超过阈值,决定走快速通道还是批量加载通道,最后写入数仓。执行时间和失败率都大幅下降。

微服务注册聚合

阶段:服务集成与系统解耦

解决的问题:用户注册涉及账户创建、欢迎邮件、推荐配置等多项服务,直接互相调用会形成网状依赖。状态机以“中央协调者”身份聚合服务调用,拆散了服务间的强耦合。

具体案例:某 SaaS 平台的新用户注册流程:状态机先调用账户服务创建账号;创建成功后,并行调用邮件服务发送激活链接、调用配置服务初始化工作空间;邮件服务偶尔超时,重试两次后仍失败则走 Catch 分支——不阻塞注册主流程,仅给用户发送站内信提醒。注册体验流畅,系统韧性显著提升。

Python 演示

python48 行
"""迷你状态机:模拟 Serverless 订单编排(含重试与分支)""" import time  class OrderStateMachine:    def __init__(self):        self.state = 'CREATED'        self.retry_count = 0        self.history = []        # 转换表: (当前状态, 事件) -> (下一状态, 是否成功)        self.rules = {            ('CREATED', 'start'): ('PAY_VALIDATING', True),            ('PAY_VALIDATING', 'pay_success'): ('STOCK_LOCKING', True),            ('PAY_VALIDATING', 'pay_fail'): ('PAY_VALIDATING', False),            ('STOCK_LOCKING', 'stock_ok'): ('PACKING', True),            ('STOCK_LOCKING', 'stock_empty'): ('OUT_OF_STOCK', False),            ('PACKING', 'pack_ok'): ('SHIPPING', True),            ('SHIPPING', 'delivered'): ('COMPLETED', True),        }     def trigger(self, event):        key = (self.state, event)        if key not in self.rules:            raise ValueError('非法事件: {} @ {}'.format(event, self.state))        next_state, success = self.rules[key]        self.history.append('{} --{}--> {}'.format(self.state, event, next_state))        if not success and next_state == self.state:            self.retry_count += 1            print('支付失败,第 {} 次重试...'.format(self.retry_count))            return next_state, False        self.state = next_state        return next_state, True     def run(self, events):        for e in events:            self.trigger(e)            time.sleep(0.2)        return self.state, self.history  if __name__ == '__main__':    sm = OrderStateMachine()    events = ['start', 'pay_fail', 'pay_success', 'stock_ok', 'pack_ok', 'delivered']    final, records = sm.run(events)    print('最终状态:', final)    for line in records:        print(line)
目的:用纯 Python 实现一个状态机驱动的订单编排,演示状态转换、失败重试与成功终止三个核心机制。
  1. self.rules = {...}定义状态转换表,每个(状态,事件)映射到“下一状态 + 是否成功”,相当于状态机的“菜谱”。
  2. key = (self.state, event)在当前状态下查找事件对应的转换规则,这是所有状态机引擎的核心查找逻辑。
  3. next_state, success = self.rules[key]取出规则,得到目标状态和成功标志。
  4. if not success and next_state == self.state:识别“重试事件”:转换失败且状态不迁移,则重试计数并留在当前状态。
  5. sm = OrderStateMachine()创建状态机实例,等价于主厨接管订单,开始盯流程。

常见误区

误区既然 Lambda 函数里可以直接用 SDK 调用另一个函数,为什么还要多学一个状态机?直接写代码把函数串起来不就完事了吗?

正解函数之间直接调用会形成网状依赖,且没有任何一层持有“全局进度”。状态机编排器像一个主厨,掌控每道菜的状态和顺序;函数直连则像厨师们隔着灶台喊话,锅一多就乱。状态机提供执行历史、自动重试、可视化监控,手工代码要实现这些得自己造无数轮子。

为何常见:Serverless 上手体验极佳,调用函数像调用本地函数一样简单,容易让人忽略“流程本身也需要被治理”这一层。

误区用画图工具画一张业务流程箭头图,然后照着图配几个函数,就认为状态机设计完成了。

正解状态机是严格的工程模型:每个状态要有明确的事件触发条件,每个转换必须合法,每个状态都要考虑失败时去哪。画图只是可视化表达,真正的设计在于状态定义、事件语义、重试和兜底策略如何落到 ASL 或等价定义中。

为何常见:人的大脑天然喜欢看流程图,容易把“看得懂流程”误当成“设计好了流程”。

误区代码里写个循环,函数失败就一直重试,觉得总有一次能成功,反正云函数便宜。

正解无限重试或过高频率的重试,会放大下游服务的故障——下游本来就过载,你还拿重试流量轰炸它,最终引发雪崩。业界标准做法是有限次重试+指数退避+超过上限后走 Catch 兜底分支,让流程优雅降级。

为何常见:“多试几次总能成功”符合日常直觉,但它忽略了分布式系统中故障传播的连锁效应。

误区花时间学的全是 AWS 特有的服务和 ASL 语法,如果公司不用 AWS,这些知识就全部浪费了。

正解状态机是通用的架构设计模式,AWS Step Functions 只是它的一个优质实现。Azure Durable Functions、阿里云 Serverless 工作流、开源 Temporal,底层思想完全一致。掌握了状态、事件、转换、重试、分支这些核心概念,任何平台对你来说都只是换一套 API 而已。

为何常见:以工具名代替了思想本身,把“一种服务的用法”误当成了“一种技术的全部”。

面试题

Q1. Serverless 中单个函数通常被设计成什么样?

单选题 · easy

  • A.带有大量内部状态的长期运行服务
  • B.无状态且执行时间短暂的计算单元← 正确答案
  • C.一次性执行完毕后常驻内存的进程
  • D.必须依赖专用服务器才能运行的任务

答案:B。Serverless 函数就像“做完就走”的临时厨师,执行完即销毁,不保留状态。A 和 C 都是有状态、常驻的描述,违背 Serverless 核心特征;D 说要依赖专用服务器,也与“托管、弹性”背道而驰。

Q2. 状态机五元组中,δ 表示什么?

单选题 · mid

  • A.全部状态的集合
  • B.输入事件的集合
  • C.状态转换的函数← 正确答案
  • D.终止状态的集合

答案:C。五元组 \((S, \Sigma, \delta, s_0, F)\) 中,δ 是转换函数,定义“当前状态 + 事件 → 下一状态”。A 对应 S,B 对应 Σ,D 对应 F,都是干扰项。

Q3. AWS Step Functions 使用什么语言定义状态机?

单选题 · mid

  • A.ASL,一种基于 JSON 的描述语言← 正确答案
  • B.Python 的状态转换装饰器框架
  • C.YAML 的流水线管道配置语言
  • D.特化于该服务的 Java 类库

答案:A。Step Functions 使用 Amazon States Language(ASL),基于 JSON 描述状态、转换、重试等。B、C、D 都不是 Step Functions 官方定义语言,虽然思想类似,但具体实现完全不同。

Q4. 指数退避重试中,每次重试的等待时间如何变化?

单选题 · mid

  • A.固定不变
  • B.线性增长
  • C.指数增长← 正确答案
  • D.随机波动

答案:C。指数退避的公式是 delay = base × backoff^(n-1),间隔随次数指数放大,如 1s、2s、4s、8s。A 是固定间隔,B 是线性增长,D 是抖动或随机策略,均不符合指数退避定义。

Q5. 状态机中 Choice 状态的主要作用是什么?

单选题 · easy

  • A.并行执行多个子函数
  • B.根据条件选择下一步分支← 正确答案
  • C.重试失败的任务函数
  • D.记录日志和执行历史

答案:B。Choice 状态负责条件路由,像主厨看订单分流到不同出餐线。A 是 Parallel 状态的功能,C 是 Retry 的能力,D 是执行追踪服务,都不属于 Choice 的核心职责。

Q6. 以下哪些是状态机编排相比手工代码的优势?

多选题 · hard

  • A.可视化流程一目了然← 正确答案
  • B.支持失败重试和恢复← 正确答案
  • C.完全取代编程语言
  • D.精确追踪执行历史← 正确答案

答案:ABD。状态机让流程可视化(A)、自带失败重试(B)、记录完整执行历史(D),这些都是显著优势。但它不会“取代编程语言”——每个函数内部的业务逻辑仍用代码实现,状态机只是编排层,C 过度夸大。

Q7. Serverless 函数“无状态”主要体现在哪里?

单选题 · easy

  • A.执行结束后不保留内部状态← 正确答案
  • B.函数无法访问外部存储服务
  • C.函数绝不能使用数据库缓存
  • D.函数只接收输入不允许输出

答案:A。无状态是指函数实例执行完即销毁,内部变量不保留到下一次调用。但这不妨碍函数访问外部存储(B/C 错),也不限制输入输出(D 错)。这也是为什么需要编排器来持有流程状态。

Q8. 设计错误重试策略时,以下哪些做法是合理的?

多选题 · mid

  • A.对任何错误都无限次快速重试
  • B.对瞬时故障设置有限次重试← 正确答案
  • C.采用指数退避避免雪崩效应← 正确答案
  • D.设置兜底分支实现降级处理← 正确答案

答案:BCD。瞬时故障有限重试(B)、指数退避(C)、兜底降级(D)都是工程最佳实践。A 的无限快速重试会放大下游故障,是典型的错误策略。

Q9. 在 Step Functions 中,Catch 字段的主要作用是什么?

单选题 · mid

  • A.捕获异常并进行后续降级处理← 正确答案
  • B.将函数执行时间延长至一小时
  • C.自动修改函数的返回结果集
  • D.让多个函数共享同一份状态存储

答案:A。Catch 用于捕获指定错误,并让流程跳转到降级分支,防止整体失败。B 是执行超时配置,C 是函数内部逻辑,D 是存储设计,均与 Catch 无关。

Q10. 在 Serverless 编排中,常见的设计模式有哪些?

多选题 · hard

  • A.顺序执行模式依次调用任务← 正确答案
  • B.分支选择模式按条件分流← 正确答案
  • C.并行扇出模式批量并发处理← 正确答案
  • D.无限循环模式防止流程结束

答案:ABC。顺序执行、分支选择、并行扇出是三种经典的状态机编排模式。D 是陷阱选项——状态机必须设有终止状态,无限循环是设计缺陷而非设计模式,没有“防止流程结束”的合法性。