AWS Lambda 函式
Vibe Prompt
「幫我用 Python 寫一個 AWS Lambda 函式:接收 API Gateway 的 POST 請求,解析 JSON body,存入 DynamoDB,回傳 201 Created。」
Lambda 函式
import json
import boto3
from datetime import datetime
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Visitors')
def lambda_handler(event, context):
body = json.loads(event['body'])
item = {
'id': str(int(datetime.now().timestamp())),
'name': body.get('name', 'anonymous'),
'message': body.get('message', ''),
'created_at': datetime.now().isoformat()
}
table.put_item(Item=item)
return {
'statusCode': 201,
'headers': {'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*'},
'body': json.dumps({'id': item['id'], 'message': 'Created successfully'})
}
CDK 部署
import * as lambda_ from 'aws-cdk-lib/aws-lambda';
import * as apigw from 'aws-cdk-lib/aws-apigateway';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
const table = new dynamodb.Table(this, 'Visitors', {
partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
});
const fn = new lambda_.Function(this, 'VisitorFunc', {
runtime: lambda_.Runtime.PYTHON_3_11,
handler: 'index.lambda_handler',
code: lambda_.Code.fromAsset('lambda'),
environment: { TABLE_NAME: table.tableName },
});
table.grantWriteData(fn);
new apigw.LambdaRestApi(this, 'VisitorApi', { handler: fn });
關鍵要點
| 概念 | 說明 | |------|------| | Lambda | 事件驅動的無伺服器函式,按使用量計費 | | 觸發器 | API Gateway、S3、DynamoDB Streams、SQS、EventBridge | | Timeout | 最大 15 分鐘(同步呼叫) | | 記憶體 | 128 MB - 10,240 MB(CPU 與記憶體成正比) | | 冷啟動 | 閒置後首次調用需載入執行環境(延遲 100-1000ms) | | 並發 | 每個帳戶 1000 並發執行(可提高配額) |
冷啟動優化
# 1. 減少部署包大小
# 2. 使用 Provisioned Concurrency(預先啟動容器)
# 3. 使用 SnapStart (Java/Python) 快照加速
# 4. 避免大型依賴套件(如整包 Pandas、TensorFlow)
# 5. 使用 Lambda Layer 分離程式碼與依賴
Lambda 最佳實踐
- ✅ 將設定寫入環境變數,不要寫死在程式碼
- ✅ 使用 Lambda Layer 管理依賴套件
- ✅ 資料庫連線寫在 Handler 外部(全域變數),重複使用
- ✅ 日誌使用結構化 JSON 格式,方便 Loki/CloudWatch 解析
- ✅ 設定 DLQ(Dead Letter Queue)處理失敗的事件
實戰經驗:Lambda 常見陷阱與解法
| 陷阱 | 症狀 | 解法 |
|:----|:----|:----|
| Handler 外層初始化過重 | 每次冷啟動都超時 | 只 import 需要的套件,懶載入(Lazy Import) |
| 環境變數硬編碼 | 測試/正式環境切換困難 | 一律使用 os.environ + Lambda Console 設定 |
| 日誌印太多 | CloudWatch 費用暴增 | 使用結構化 JSON 日誌 + Debug Level 動態控制 |
| VPC 內 Lambda 沒設 NAT | 無法連線外部 API | 使用 VPC Endpoint 或 NAT Gateway |
| Timeout 設太短 | 資料量大時總是失敗 | 根據實際測試設定(預設 3 秒,建議先設 30 秒) |
# 實戰級別 Lambda Handler 範本
import json
import os
import logging
logger = logging.getLogger()
logger.setLevel(os.environ.get('LOG_LEVEL', 'INFO'))
# Lazy Import:按需載入,加速冷啟動
def _get_dynamodb():
import boto3
return boto3.resource('dynamodb')
def lambda_handler(event, context):
logger.info(json.dumps({'event': event, 'remaining_ms': context.get_remaining_time_in_millis()}))
try:
table = _get_dynamodb().Table(os.environ['TABLE_NAME'])
body = json.loads(event.get('body', '{}'))
# 主要邏輯
result = table.put_item(Item=body)
return {
'statusCode': 201,
'body': json.dumps({'success': True, 'id': body.get('id')})
}
except Exception as e:
logger.exception('Handler failed')
return {'statusCode': 500, 'body': json.dumps({'error': str(e)})}
為什麼要學 Lambda?
AWS Lambda 是 Serverless 應用的核心積木。你不需要管理任何伺服器,只要寫程式、上傳、設定觸發器,剩下的擴展、可用性、安全修補都由 AWS 處理。對於小型團隊或獨立開發者來說,這代表你可以在一個週末內建立一個能撐住百萬使用者的 API。
如何學好 Lambda?
重點不是語法——Python/Node.js 寫 Lambda 跟寫一般函式幾乎一樣。關鍵在於:
- 理解執行模型:冷啟動、並發限制、Timeout 如何影響你的架構設計
- 學會除錯:CloudWatch Logs、X-Ray 分散式追蹤、結構化日誌
- 掌握 IAM 權限:Least Privilege 原則——給 Lambda 剛剛好的權限
- 部署自動化:用 CDK/Terraform 管理基礎設施,不要手動上傳 ZIP
接下來學什麼
你已經學會了 Lambda 的基礎——寫程式、設觸發器、部署上線。下一章 DynamoDB 與資料模型 將教你在 Serverless 世界裡如何設計資料庫。這和傳統的關聯式資料庫思維完全不同——你會學到為什麼「一個表格放所有資料」反而是最佳做法,以及如何設計 Partition Key 讓查詢永遠在毫秒級完成。