AWS Lambda 完整教程:函数创建、触发器配置、计费方式与冷启动优化

AWS Lambda 教程

AWS Lambda 是 AWS 提供的无服务器计算服务,核心思路是只需要上传代码,Lambda 负责运行环境的创建、扩展和销毁,不需要预置或管理任何服务器。
代码由事件驱动,有请求时运行,没有请求时不占用任何资源,按实际执行时间和调用次数计费。

对于大多数 Web 应用来说,Lambda 并不是 EC2 的替代品,而是对特定场景的补充,当业务逻辑可以拆解为独立的、短时间执行的函数,且流量模式呈现明显的波峰波谷时,Lambda 在成本和运维复杂度上都优于常驻运行的服务器。

Lambda 是什么,和 EC2 的本质区别

EC2 是按小时计费的虚拟机,无论是否有流量,只要实例处于运行状态就持续计费。Lambda 是按实际调用次数和执行时间计费的函数运行环境,没有调用就没有费用。

这个差距在不同流量模式下的影响截然不同。
一个每天只在固定时间段有流量的后台任务,部署在 EC2 上需要 24 小时保持运行,而放在 Lambda 上只在有触发事件时运行,闲置时间完全不计费。
另一方面,一个每秒有大量持续请求的高并发 API,Lambda 的调用次数和执行时长叠加计算,成本可能超过同等能力的 EC2 实例。

Lambda 的另一个关键特点是自动扩展。
并发请求增加时,Lambda 自动创建新的执行环境处理请求,不需要人工配置 Auto Scaling 策略,也不需要预先规划容量。默认并发上限为 1000 个同时执行的函数实例,可以通过申请提升。

Lambda 支持的运行时覆盖主流编程语言:Node.js、Python、Java、Go、C#(.NET)和 Ruby。Python 和 Node.js 是最常用的两个,启动速度快,代码简洁,适合大多数事件处理场景。Java 功能完整但冷启动时间明显长于其他语言,在对延迟敏感的场景中需要额外处理。

Lambda 的核心概念

理解 Lambda 需要先搞清楚四个基础概念:函数、事件、执行角色和触发器。

函数是 Lambda 的基本单位,包含运行代码、运行时配置、内存分配和超时时间。内存可以在 128MB 到 10,240MB(10GB)之间配置,CPU 能力与内存成正比,提高内存分配同时提升了 CPU 性能。最长执行时间(超时限制)最大为 15 分钟(900 秒),超过这个时间函数会被强制终止并返回超时错误。

事件是触发函数执行的输入数据。
每次函数调用都会收到一个事件对象,包含触发源传递的信息,比如 S3 上传事件会包含存储桶名称和对象键名,API Gateway 请求会包含 HTTP 方法、路径和请求体。
函数通过处理事件对象获取输入,完成业务逻辑后返回响应。

执行角色是赋予 Lambda 函数访问其他 AWS 资源权限的 IAM 角色。
函数需要读取 S3 文件,就需要在执行角色中包含 S3 读取权限;需要写入 DynamoDB,就需要对应的 DynamoDB 写入权限。执行角色遵循最小权限原则,只授予函数实际需要的权限,不应使用具有完整管理员权限的角色。
关于 IAM 角色和权限策略的配置方法,可以参考 AWS IAM 权限管理 的完整说明。

触发器是配置在函数上的事件源,定义了哪些 AWS 服务或外部事件可以调用该函数。一个函数可以有多个触发器,每个触发器对应一类事件源。

创建第一个 Lambda 函数

在 AWS 控制台搜索 Lambda,进入 Lambda 控制台后点击「创建函数」。
创建方式选择「从头开始创作」,填写函数名称,选择运行时(以 Python 3.12 为例),执行角色选择「创建具有基本 Lambda 权限的新角色」,这会自动创建一个允许函数写入 CloudWatch Logs 的基础角色,创建完成后可以根据需要补充其他权限。

函数创建完成后,控制台会显示代码编辑器,默认的 Python 函数结构如下:

import json

def lambda_handler(event, context):

    print(“Event:”, json.dumps(event))

    return {

        ‘statusCode’: 200,

        ‘body’: json.dumps(‘Hello from Lambda!’)

    }

lambda_handler 是函数的入口点,event 参数接收触发事件的数据,context 参数包含函数运行时的元数据(如剩余执行时间、函数名称等)。
函数返回值的格式取决于触发器类型,API Gateway 触发时需要返回包含 statusCode 和 body 的字典。

修改代码后点击「部署」使更改生效,再点击「测试」配置一个测试事件验证函数是否正常运行。测试事件是一个 JSON 对象,模拟实际触发时传入的事件数据,执行结果和日志输出会在控制台直接显示。

常用触发器配置

S3 触发器:文件上传自动处理

S3 触发器是 Lambda 最经典的使用场景之一,每当 S3 存储桶有新文件上传时自动触发函数执行。典型用途是图片缩略图生成、文件格式转换和日志文件处理。

在函数页面点击「添加触发器」,选择 S3,配置目标存储桶和事件类型(通常选择「PUT」即对象创建)。需要注意,输入和输出不应使用同一个存储桶——函数处理完文件后如果写回同一个存储桶,会再次触发函数形成无限递归,产生大量非预期费用。关于 S3 存储桶的权限配置和事件通知设置,可以参考 AWS S3 对象存储 的完整使用说明。

触发时函数接收到的事件对象包含存储桶名称和对象键名,通过这两个信息可以读取对应文件并进行处理:

import boto3

def lambda_handler(event, context):

    s3 = boto3.client(‘s3’)

    bucket = event[‘Records’][0][‘s3’][‘bucket’][‘name’]

    key = event[‘Records’][0][‘s3’][‘object’][‘key’]

    response = s3.get_object(Bucket=bucket, Key=key)

    content = response[‘Body’].read()

    # 处理文件内容

    print(f”处理文件:{bucket}/{key},大小:{len(content)} 字节”)

API Gateway 触发器:构建 HTTP API 后端

API Gateway 触发器让 Lambda 函数成为 HTTP API 的处理逻辑,每次 HTTP 请求到达 API Gateway 时调用对应的 Lambda 函数。这个组合是最常见的无服务器 API 架构,适合请求量不均衡、不需要持续运行后端服务的场景。

添加 API Gateway 触发器时,可以选择创建新的 HTTP API(简单,低成本)或 REST API(功能更完整,支持请求验证、缓存、使用计划等)。对于简单的 API 场景,HTTP API 价格更低,配置更简单。

函数接收到 API Gateway 事件后,通过 event 对象获取 HTTP 方法、路径参数、查询字符串和请求体,处理完成后返回包含状态码和响应体的字典。

EventBridge 触发器:定时任务

EventBridge(原 CloudWatch Events)可以按照 cron 表达式或固定频率定时触发 Lambda 函数,相当于在 AWS 上运行的定时任务,不需要专门保持一台服务器在线。

常见用途包括每小时执行一次数据汇总、每天凌晨清理过期数据、每周生成报表并发送邮件通知。添加 EventBridge 触发器时,配置 Schedule expression 字段:rate(1 hour) 表示每小时触发一次,cron(0 2 * * ? *) 表示每天 UTC 时间 2:00 触发一次。

SQS 触发器:消息队列处理

SQS 触发器让 Lambda 成为消息队列的消费者,队列中有消息时自动批量触发函数处理。适合异步任务处理、削峰填谷和分布式工作流场景。Lambda 从队列中拉取消息批次,处理成功后自动删除消息,处理失败时消息重新进入队列等待重试。

计费方式与免费额度

Lambda 的计费由两部分构成:请求次数费用和执行时间费用(GB-秒)。

请求次数: 每月前 100 万次调用永久免费,超出后 $0.20/百万次请求。100 万次调用对于大多数中小型应用来说是一个相当充裕的免费额度,日均 3 万次调用才会触发收费。

执行时间: 按函数运行的内存量和持续时间计算,单位是 GB-秒(内存 GB 数 × 执行秒数),价格为 $0.0000166667/GB-秒。每月前 400,000 GB-秒永久免费。以 128MB 内存为例,每月可以免费执行约 320 万秒;以 1GB 内存为例,每月免费执行时间为 400,000 秒。

以一个实际场景估算:256MB 内存、平均每次执行 200ms、每月 1000 万次调用:

  • 请求费:(10,000,000 – 1,000,000) × $0.20 / 1,000,000 = $1.80
  • 执行费:10,000,000 × 0.2s × 0.25GB × $0.0000166667 = $8.33
  • 月度合计:约 $10.13

相同工作负载如果部署在 EC2 上,需要至少一台常驻实例处理请求,t3.small(2 vCPU、2GB 内存)在 us-east-1 按需价格约 $15/月,并发量高时还需要多台实例。低于约 800–1000 万次请求/月时,Lambda 的成本优势显著;高于这个阈值,且每次执行时间较长时,常驻 EC2 可能更经济。关于 AWS 各产品的成本构成和估算方法,可以参考 亚马逊云服务器价格 的完整分析。

值得注意的隐藏成本: 如果使用 API Gateway 配合 Lambda 构建 API,API Gateway 本身按 $3.50/百万次 API 调用收费,流量大时 API Gateway 的费用可能超过 Lambda 本身。

冷启动问题与解决方案

冷启动是 Lambda 性能问题中最常被讨论的话题。当函数长时间未被调用,或者并发请求量突增需要创建新的执行环境时,Lambda 需要初始化运行时环境、加载函数代码和依赖,这个过程会在正常执行时间之外增加额外延迟,称为冷启动。

在 AWS 对实际用户调用模式的统计中,生产环境冷启动占比不足 1%,因为持续有流量的函数执行环境会被复用。冷启动主要发生在以下几种情况:函数第一次被调用、长时间无请求后的首次调用(执行环境闲置约 5–15 分钟后被回收)、并发量突增时新实例的初始化。

冷启动时间因运行时不同差异明显。Python 和 Node.js 的冷启动通常在 100ms 以内,对绝大多数场景没有感知影响。Java 的冷启动时间可能达到 1–6 秒,主要原因是 JVM 初始化和类加载耗时,对于面向用户的实时 API 来说影响较为明显。

缓解冷启动的几种方式:

第一是优化函数代码结构。将初始化操作(数据库连接、SDK 客户端创建)放在 lambda_handler 函数之外的模块级别,这样这些对象在执行环境被复用时不需要重新创建,减少后续调用的实际执行时间。

import boto3

# 在函数外初始化,执行环境复用时不重新创建

s3_client = boto3.client(‘s3’)

dynamodb = boto3.resource(‘dynamodb’)

def lambda_handler(event, context):

    # 直接使用已初始化的客户端

    response = s3_client.list_buckets()

    return response

第二是减小部署包体积。依赖库越多,冷启动时加载时间越长。只打包函数实际需要的库,移除未使用的依赖,可以有效缩短冷启动时间。

第三是使用预置并发(Provisioned Concurrency)。这个功能让 Lambda 预先初始化并保持指定数量的执行环境处于热启动状态,完全消除冷启动延迟。代价是持续计费——以 us-east-1 为例,256MB 内存的预置实例约 $0.0042/小时,保持 10 个预置实例全月费用约 $30。适合对延迟有严格要求的面向用户实时 API,普通异步处理任务不需要开启。

Lambda 访问 VPC 内部资源

默认情况下,Lambda 函数运行在 AWS 管理的网络环境中,可以访问公网资源,但无法直接访问 VPC 内部的私有资源,例如放在私有子网的 RDS 数据库或 ElastiCache。

如果函数需要访问 VPC 内部资源,需要在函数配置中启用 VPC 访问,选择目标 VPC、私有子网和安全组。启用 VPC 访问后,函数会在对应子网内创建网络接口(ENI),通过内网访问 VPC 内的资源。需要注意的是,VPC 内的 Lambda 函数无法直接访问公网,如果同时需要访问外网 API,必须为子网配置 NAT Gateway。

VPC 访问会增加冷启动时间,因为 ENI 创建本身需要额外耗时。在函数需要同时访问 VPC 内部资源和外网资源时,网络配置的设计需要提前规划。关于 VPC 子网、路由表和 NAT Gateway 的配置方法,可以参考 AWS VPC 网络配置教程。

Lambda vs EC2:场景判断

两种计算方式适合不同的场景,判断依据是工作负载的持续性、执行时间和触发模式。

适合用 Lambda 的场景:单次处理时间在 15 分钟以内、由事件触发而非持续运行、流量模式不均衡(有明显的闲置时间)、无需维护应用状态在多次调用之间共享、处理逻辑可以拆解为独立的函数单元。典型场景包括图片和文件处理、定时任务、Webhook 处理、API 后端(配合 API Gateway)、消息队列消费。

适合用 EC2 的场景:需要持续运行的服务(如 Web 服务器、游戏服务端)、执行时间超过 15 分钟的任务、需要在内存中维护状态、对冷启动延迟极度敏感的实时服务、或者每月请求量大到 Lambda 费用超过 EC2 的成本临界点。

两者也可以组合使用:EC2 处理需要持续运行的核心服务,Lambda 处理周边的事件驱动任务,互相补充,按各自的优势覆盖不同的工作负载。

滚动至顶部