Day33-08|14.3.3 无服务器技术:按事件运行的弹性计算与平台化架构

一、教材定位与学习目标

14.3.3“无服务器技术”是云原生架构中重要的运行模式。无服务器并不是没有服务器,而是把服务器、操作系统、容量配置和部分运行时管理交给云平台,开发团队以函数、任务或托管服务为单位交付业务逻辑。它特别适合事件触发、调用频率波动、执行时间较短和希望减少基础设施运维的场景。

高级系统架构设计师考试常考的不是函数语法,而是架构判断:什么场景适合无服务器?函数为什么会冷启动?状态应该放在哪里?失败如何重试和幂等?函数数量增加后如何治理?成本和供应商锁定如何控制?本篇从这些问题出发建立完整认识。

二、无服务器架构的基本概念

无服务器架构通常包含两类能力:函数即服务和后端即服务。函数即服务由平台负责函数实例创建、调度、扩缩、运行和回收;后端即服务提供数据库、对象存储、消息、认证、搜索和 API 等托管能力。开发者主要关注业务逻辑、事件契约、数据和权限。

一个典型结构如下:

HTTP 请求 / 消息 / 定时器 / 文件事件 / 数据库事件
                     ↓
                触发器与路由
                     ↓
             函数运行时与工作流
              ↓       ↓       ↓
         数据库   对象存储   消息服务

无服务器的核心变化是资源供给和运行生命周期由平台动态决定。函数实例可能按请求创建,处理完成后回收;同一个函数可能同时有多个实例;实例也可能被复用一段时间。因此,应用不能依赖某个实例永久存在,必须面向无状态、并发和重复执行进行设计。

三、无服务器适合解决什么问题

3.1 负载不规律的任务

图片缩略图、文件转换、报表生成、通知发送和数据清洗可能长时间没有请求,偶尔出现集中峰值。长期运行固定服务器会产生闲置成本,函数按调用或执行资源计费更有弹性。

3.2 事件驱动的流程

文件上传、订单创建、支付回调、设备上报和定时任务天然可以表达为事件。函数作为事件消费者,便于按需扩展和独立交付。

3.3 轻量 API 与边缘逻辑

简单查询、数据转换、鉴权和协议适配可以使用函数快速实现。若请求量稳定、逻辑复杂、需要长连接或需要精细控制运行时,长期运行的容器或服务可能更合适。

四、无服务器的主要特征

特征 说明 设计影响
平台托管 平台负责实例和底层资源 减少运维,但依赖平台能力
事件触发 HTTP、消息、定时器等触发执行 必须设计事件契约和重试
弹性扩缩 根据请求并发动态调整 需要控制并发和下游承载力
按量计费 按调用次数、执行时间或资源计费 需监控成本和异常调用
短生命周期 实例可创建、复用、回收 不依赖本地永久状态
托管后端 使用数据库、存储、消息等 BaaS 注意数据、权限和供应商锁定

这些特征带来效率,也带来约束。开发者不再完全控制操作系统、网络和运行时,调试、性能调优、版本迁移和本地复现需要借助平台工具和契约测试。

五、函数生命周期与冷启动

函数可能经历初始化、加载依赖、接收事件、执行、返回结果和回收等阶段。首次创建实例或长时间没有请求时,平台需要加载运行时和代码,这段额外时间称为冷启动。冷启动对低延迟 API 和高峰突发流量影响较明显。

降低冷启动影响的方法包括:减少依赖和镜像体积、缩短初始化逻辑、延迟加载非必要模块、选择合适的运行时、使用预留或预热实例、通过队列平滑突发流量。预留实例可能增加成本,因此要根据延迟目标和调用规律选择。

需要区分冷启动和业务慢。数据库慢查询、外部接口超时和函数代码低效也会造成延迟,不能把所有问题都归因于冷启动。应通过指标和追踪分别测量初始化时间、业务执行时间、依赖耗时和排队时间。

六、无状态与状态管理

函数实例可以被并发调用、复用或回收,本地内存和文件不具有可靠持久性。函数应把业务状态保存到数据库、缓存、对象存储或消息系统中,并通过业务键关联上下文。

6.1 幂等状态

事件可能重复触发,函数必须能够安全重复执行。例如图片处理以文件摘要和版本作为幂等键,支付回调以第三方流水号去重,报表任务以任务编号防止重复生成。数据库唯一约束和处理记录是常见保障。

6.2 状态机与工作流

当流程包含多个步骤和等待时,不应依赖函数内存保存进度。可以使用工作流服务或状态表记录当前步骤、输入、输出、重试次数和错误原因。工作流需要处理补偿、超时、人工干预和版本升级。

6.3 缓存的边界

函数实例内存缓存可以减少重复加载,但它可能随实例回收消失,不能作为权威数据。共享缓存也要考虑过期、一致性、容量和击穿。缓存失效时,函数应避免同时大量请求数据库。

七、事件触发与消息可靠性

7.1 事件契约

事件应包含事件编号、类型、版本、产生时间、主体、业务关联键和必要数据。生产者与消费者要约定字段兼容、重复投递、乱序和延迟。事件名称应表达已发生的事实,例如“订单已支付”,而不是含义模糊的“处理订单”。

7.2 重试和死信

函数执行失败时,平台可能自动重试。架构师要确认重试次数、间隔、最大事件保留时间和失败后的去向。临时网络错误适合延迟重试,参数错误等永久失败应进入死信队列。死信需要告警、查看、修复和重新投递机制。

7.3 顺序与并发

事件驱动平台可能并发处理同一业务实体的多个事件。如果库存或订单状态要求顺序,需要按业务键分区、版本检查或使用状态机拒绝过期事件。对不要求顺序的独立任务,可以充分并发提高吞吐。全局顺序通常会牺牲扩展性。

八、函数编排与复杂业务流程

单个函数适合完成短小、边界清晰的动作;多个函数组成的业务流程需要编排。编排器可以管理步骤、条件、并行、等待、超时、重试和补偿,降低业务流程散落在函数之间的问题。

例如订单履约流程可以分为校验订单、预占库存、创建支付单、等待支付事件、生成出库任务和发送通知。支付等待不适合让函数一直占用执行资源,应该由状态机或工作流记录等待状态,收到事件后继续推进。

工作流本身也要版本化。流程升级时,正在执行的旧实例可能需要继续按旧定义完成,新实例使用新定义;数据结构和外部接口要保持兼容,不能简单替换导致历史任务无法恢复。

九、无服务器的数据与一致性

函数通常通过托管数据库和消息服务读写数据。函数调用和数据库事务之间可以保持本地原子性,但跨函数、跨服务和跨供应商的流程仍要采用最终一致性。可靠事件、发件箱、幂等、状态机、补偿和对账是常用措施。

以“上传文件后生成缩略图”为例,文件保存成功和缩略图生成失败不能简单回滚文件。系统应记录文件状态,发布生成任务;函数失败后重试,超过上限进入死信;人工修复或定时补偿后更新状态。用户界面显示处理中或失败,而不是误报成功。

十、并发、限流与下游保护

无服务器平台能够快速创建大量实例,但下游数据库和第三方接口可能无法承受突增并发。平台并发上限、队列长度、连接池和调用配额需要统一规划。可以通过队列、批处理、令牌桶、分级优先级和最大并发限制形成背压。

数据库连接管理尤其重要。每个函数实例都建立连接,实例数增加会迅速耗尽连接池。应使用连接复用、代理、连接上限或数据访问层治理,并根据函数并发和数据库容量进行压测。弹性计算不是无限吞吐,必须以依赖承载能力为边界。

十一、成本模型与运营治理

无服务器按调用次数、执行时间、内存、网络和配套服务费用计费。调用异常循环、消息重复、过度日志和函数等待都会造成成本失控。应为函数设置并发、执行时间和内存上限,监控调用量、错误重试、平均耗时和单位业务成本。

成本优化包括减少冷启动和依赖加载、缩短执行时间、批量处理、合理选择内存规格、避免长时间等待、设置日志留存和对象存储生命周期。优化不能只看单次调用价格,还要考虑开发、运维、故障和迁移成本。

十二、安全设计

函数执行身份应遵循最小权限,只能访问完成任务所需的资源;触发器要进行来源认证和授权,不能因为是内部消息就默认可信;敏感配置使用密钥服务,避免写入环境变量日志或代码仓库;输入事件需要校验大小、格式和签名,防止注入和资源滥用。

函数代码、依赖和运行时要进行漏洞扫描和版本管理。日志应脱敏并限制访问,审计记录保留调用主体、事件、资源和结果。多租户平台还要隔离函数权限、网络和数据,防止一个租户访问另一租户资源。

十三、无服务器与容器/微服务的选型

场景 无服务器函数 长期运行微服务/容器
调用模式 事件触发、频率波动 持续请求、稳定负载
生命周期 短任务、可重试 长连接、长任务
运维控制 平台托管程度高 自主控制更多
弹性 平台自动扩缩 需要配置编排和扩缩
约束 运行时、时间和并发限制 运维和资源管理成本较高
适用案例 图片处理、通知、定时任务 核心交易、长连接、复杂服务

二者可以组合。核心订单服务使用容器长期运行,订单完成后通过事件触发函数生成发票或发送通知;文件上传进入对象存储,函数负责异步转码;低频管理 API 使用函数,高并发稳定 API 使用容器。模式组合时要设计统一身份、日志、追踪和事件契约。

十四、案例分析:在线票务平台的无服务器改造

某在线票务平台每天流量不均,图片审核和通知任务在演出发布时集中增长,核心购票流程要求低延迟和严格防重复。平台希望减少非核心任务的服务器运维。

合理方案是保留购票和库存服务作为长期运行的核心服务,采用本地事务、锁或条件更新和幂等键保证票务正确;图片上传后由对象存储事件触发审核函数,审核结果通过消息回传;订单支付成功发布事件,发票和通知由函数异步处理;工作流记录需要人工审核或重试的长流程;平台为函数设置并发和下游配额,防止演出发布时冲击数据库和第三方短信;所有函数使用专用身份、密钥服务和结构化日志。

改造验证包括:重复事件测试、函数超时与冷启动测试、消息积压和死信恢复、数据库连接峰值、权限越界、安全扫描和单位订单成本。这样既利用无服务器的弹性,又避免将核心强一致交易放入不适合的执行模型。

十五、课后练习

练习一:选择题

下列哪项最适合采用无服务器函数?

A. 需要长期保持 TCP 连接的交易网关

B. 低频触发的图片缩略图生成任务

C. 需要持续运行的大型内存数据库

D. 必须在一个进程中维护长事务的核心服务

答案:B。 图片任务事件触发、执行时间有限且负载波动明显,适合函数;其他场景需要长期运行、连接或状态控制。

练习二:简答题

为什么无服务器函数仍然需要设计幂等和限流?

参考答案: 事件可能重复投递,函数执行失败后平台会重试,若无幂等会导致重复写入或重复扣款;平台弹性扩容可能瞬间产生大量并发,超过数据库、消息和第三方服务的承载能力,因此需要设置并发上限、队列、批处理和背压。无服务器减少资源管理,但没有消除分布式系统的重复、失败和容量问题。

练习三:案例题

某团队用函数实现订单支付主流程,支付平台响应慢时函数长时间等待,峰值期间出现大量超时和重复支付。请分析并改进。

参考答案: 团队让短生命周期函数承担长时间同步等待,没有设置清晰状态和幂等,也没有限制并发和处理下游慢依赖。应将订单创建、支付单创建和支付结果确认建模为状态机;创建支付单后立即返回处理中,通过支付回调或主动查询事件推进状态;以订单号和支付流水号实现幂等,验签并核对金额;函数只处理短步骤,等待交给工作流或消息机制;对支付接口设置截止时间、有限重试、熔断和并发配额;失败事件进入延迟重试和死信队列。改造后进行重复回调、网络超时、消息积压和并发压测。

十六、论文写作素材

论文中写无服务器,建议围绕“适用场景、事件模型、状态与可靠性、成本治理”展开。首先说明为什么低频、事件驱动或弹性任务适合函数;再写触发器、事件契约、幂等、重试、死信和工作流;随后写状态外置、权限最小化、并发限制、数据库连接治理;最后说明冷启动、供应商锁定和成本监控等代价。

不要把“按量计费、自动扩容”作为全部收益。高级论文需要写清下游保护、数据一致性和失败补偿,否则函数越多,系统越可能出现重复执行和资源过载。

十七、今日复盘清单

  • 我能否解释无服务器为什么不是没有服务器?
  • 我能否区分 FaaS、BaaS、事件触发器和工作流?
  • 我能否说明冷启动、并发、状态外置和下游保护?
  • 我能否为函数设计幂等、重试、死信和补偿?
  • 我能否判断核心交易、长连接和低频异步任务各适合什么运行模式?
  • 我能否同时写出无服务器的收益、限制和成本治理?

本节的核心结论是:无服务器通过平台托管和事件驱动实现按需运行与弹性扩展,适合短小、波动和异步任务;但它仍然需要状态管理、幂等、可靠消息、并发控制、安全和成本治理。架构师应把无服务器作为场景化能力,与容器、微服务和托管服务合理组合。