TL;DR
API AWS Lambda cho phép nhà phát triển triển khai, quản lý và gọi các hàm serverless một cách lập trình. Sử dụng xác thực IAM, các endpoint RESTful để quản lý hàm, gọi hàm đồng bộ/không đồng bộ, đồng thời được kiểm soát ở cấp tài khoản. Bài viết này hướng dẫn từng bước thiết lập xác thực, triển khai hàm, gọi hàm, ánh xạ nguồn sự kiện và chiến lược kiến trúc serverless cho môi trường production.
Giới thiệu
AWS Lambda xử lý hàng nghìn tỷ request mỗi tháng cho hơn 1 triệu người dùng. Đối với dev xây dựng ứng dụng serverless, tự động hóa hoặc kiến trúc event-driven, API Lambda là thành phần thiết yếu cho hạ tầng IaC và quy trình CI/CD.
Thực tế, quản lý thủ công trên 50 hàm Lambda có thể tiêu tốn 10-15 giờ/tuần cho deploy, update config và monitoring. Tích hợp API Lambda tự động hóa toàn bộ: deploy, phát hành blue-green, scale động theo nhu cầu.
Bài viết này hướng dẫn toàn diện tích hợp API AWS Lambda: xác thực IAM, tạo/triển khai hàm, mẫu gọi (sync/async), ánh xạ event source, quản lý layer và chiến lược deploy production-ready.
API AWS Lambda là gì?
AWS Lambda cung cấp API RESTful để quản lý các hàm serverless:
- Tạo, cập nhật, xóa hàm
- Deploy & quản lý version code
- Gọi hàm (sync/async)
- Ánh xạ nguồn sự kiện (SQS, Kinesis, DynamoDB, S3)
- Quản lý layer cho code dùng chung
- Cấu hình alias, routing
- Quản lý concurrency, provisioned concurrency
- Tích hợp logging & monitoring
Các tính năng chính
| Tính năng | Mô tả |
|---|---|
| API RESTful | Các endpoint HTTPS tiêu chuẩn |
| Xác thực IAM | AWS Signature Version 4 |
| Gọi không đồng bộ | Xử lý sự kiện "bắn và quên" |
| Gọi đồng bộ | Yêu cầu-phản hồi |
| Nguồn sự kiện | 200+ dịch vụ AWS |
| Các lớp (Layers) | Code/phụ thuộc dùng chung |
| Phiên bản/Biệt danh | Chuyển lưu lượng, rollback |
| Provisioned Concurrency | Loại bỏ cold start |
Hỗ trợ Runtime Lambda
| Runtime | Phiên bản | Ứng dụng chính |
|---|---|---|
| Node.js | 18.x, 20.x | Backend API, event processing |
| Python | 3.9, 3.10, 3.11 | Data processing, ML inference |
| Java | 11, 17, 21 | Enterprise apps |
| Go | 1.x | Hiệu suất cao |
| Rust | 1.x | Độ trễ thấp |
| .NET | 6, 8 | Workload Windows |
| Ruby | 3.x | Web app |
| Tùy chỉnh | Bất kỳ | Container-based runtime |
Tổng quan kiến trúc API
Lambda sử dụng endpoint:
https://lambda.{region}.amazonaws.com/2015-03-31/
Các phiên bản API
| Phiên bản | Trạng thái | Trường hợp sử dụng |
|---|---|---|
| 2015-03-31 | Hiện tại | Tất cả Lambda actions |
| 2018-01-31 | API Runtime | Giao diện runtime tùy chỉnh |
Bắt đầu: Thiết lập xác thực
Bước 1: Tạo tài khoản AWS và IAM user
- Vào AWS Console
- Tạo tài khoản AWS mới hoặc đăng nhập
- Vào IAM Console → Users → Create User
- Gán policy thực thi Lambda
Bước 2: Tạo thông tin xác thực IAM
Tạo access key để truy cập lập trình:
# AWS CLI
aws iam create-access-key --user-name lambda-deployer
# Lưu lại AccessKeyId và SecretAccessKey
Lưu trữ an toàn:
# ~/.aws/credentials
[lambda-deployer]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
# Hoặc biến môi trường
export AWS_ACCESS_KEY_ID="AKIAIOSFODNN7EXAMPLE"
export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
export AWS_DEFAULT_REGION="us-east-1"
Bước 3: Ký yêu cầu với AWS Signature V4
Tất cả request đến API Lambda phải ký SigV4. Ví dụ Node.js:
const crypto = require('crypto');
class AWSSigner {
constructor(accessKeyId, secretAccessKey, region, service = 'lambda') {
this.accessKeyId = accessKeyId;
this.secretAccessKey = secretAccessKey;
this.region = region;
this.service = service;
}
sign(request, body = null) {
const now = new Date();
const amzDate = now.toISOString().replace(/[:-]|\.\d{3}/g, '');
const dateStamp = amzDate.slice(0, 8);
const hashedPayload = body ? crypto.createHash('sha256').update(body).digest('hex') : 'UNSIGNED-PAYLOAD';
const canonicalUri = request.path;
const canonicalQuerystring = request.query || '';
const canonicalHeaders = `host:${request.host}\nx-amz-date:${amzDate}\n`;
const signedHeaders = 'host;x-amz-date';
const canonicalRequest = `${request.method}\n${canonicalUri}\n${canonicalQuerystring}\n${canonicalHeaders}\n${signedHeaders}\n${hashedPayload}`;
const algorithm = 'AWS4-HMAC-SHA256';
const credentialScope = `${dateStamp}/${this.region}/${this.service}/aws4_request`;
const hash = crypto.createHash('sha256').update(canonicalRequest).digest('hex');
const stringToSign = `${algorithm}\n${amzDate}\n${credentialScope}\n${hash}`;
const kDate = this.hmac(`AWS4${this.secretAccessKey}`, dateStamp);
const kRegion = this.hmac(kDate, this.region);
const kService = this.hmac(kRegion, this.service);
const kSigning = this.hmac(kService, 'aws4_request');
const signature = this.hmac(kSigning, stringToSign, 'hex');
const authorizationHeader = `${algorithm} Credential=${this.accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
return {
'Authorization': authorizationHeader,
'X-Amz-Date': amzDate,
'X-Amz-Content-Sha256': hashedPayload
};
}
hmac(key, string, encoding = 'buffer') {
return crypto.createHmac('sha256', key).update(string).digest(encoding);
}
}
// Sử dụng
const signer = new AWSSigner(
process.env.AWS_ACCESS_KEY_ID,
process.env.AWS_SECRET_ACCESS_KEY,
'us-east-1'
);
Bước 4: Tạo client API Lambda
const LAMBDA_BASE_URL = 'https://lambda.us-east-1.amazonaws.com/2015-03-31';
const lambdaRequest = async (path, options = {}) => {
const url = new URL(`${LAMBDA_BASE_URL}${path}`);
const method = options.method || 'GET';
const body = options.body ? JSON.stringify(options.body) : null;
const signer = new AWSSigner(
process.env.AWS_ACCESS_KEY_ID,
process.env.AWS_SECRET_ACCESS_KEY,
'us-east-1'
);
const headers = signer.sign({ method, host: 'lambda.us-east-1.amazonaws.com', path }, body);
const response = await fetch(url.toString(), {
method,
headers: {
'Content-Type': 'application/json',
...headers,
...options.headers
},
body
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Lỗi API Lambda: ${error.Message}`);
}
return response.json();
};
// Liệt kê hàm Lambda
const functions = await lambdaRequest('/functions');
console.log(`Tìm thấy ${functions.Functions.length} hàm`);
Thay thế: Sử dụng AWS SDK
AWS SDK hỗ trợ tự động ký SigV4, phù hợp production:
const { LambdaClient, ListFunctionsCommand, CreateFunctionCommand, InvokeCommand } = require('@aws-sdk/client-lambda');
const lambda = new LambdaClient({ region: 'us-east-1' });
// Liệt kê hàm
const listCommand = new ListFunctionsCommand({});
const result = await lambda.send(listCommand);
// Tạo hàm
const createCommand = new CreateFunctionCommand({
FunctionName: 'my-function',
Runtime: 'nodejs20.x',
Role: 'arn:aws:iam::123456789012:role/lambda-execution-role',
Handler: 'index.handler',
Code: {
S3Bucket: 'my-bucket',
S3Key: 'function.zip'
}
});
const fn = await lambda.send(createCommand);
Quản lý hàm
Tạo một hàm Lambda
const createFunction = async (functionConfig) => {
const response = await lambdaRequest('/functions', {
method: 'POST',
body: {
FunctionName: functionConfig.name,
Runtime: functionConfig.runtime || 'nodejs20.x',
Role: functionConfig.roleArn,
Handler: functionConfig.handler || 'index.handler',
Code: {
S3Bucket: functionConfig.s3Bucket,
S3Key: functionConfig.s3Key
},
Description: functionConfig.description || '',
Timeout: functionConfig.timeout || 3,
MemorySize: functionConfig.memorySize || 128,
Environment: {
Variables: functionConfig.environment || {}
},
Tags: functionConfig.tags || {}
}
});
return response;
};
// Ví dụ sử dụng
const fn = await createFunction({
name: 'order-processor',
roleArn: 'arn:aws:iam::123456789012:role/lambda-execution-role',
handler: 'index.handler',
runtime: 'nodejs20.x',
s3Bucket: 'my-deployments-bucket',
s3Key: 'order-processor/v1.0.0.zip',
description: 'Xử lý các đơn hàng từ hàng đợi SQS',
timeout: 30,
memorySize: 512,
environment: {
DB_HOST: 'db.example.com',
LOG_LEVEL: 'info'
}
});
console.log(`Hàm đã được tạo: ${fn.FunctionArn}`);
Tải mã trực tiếp (upload file zip nhỏ)
const fs = require('fs');
const path = require('path');
const createFunctionWithZip = async (functionName, zipPath) => {
const zipBuffer = fs.readFileSync(zipPath);
const base64Code = zipBuffer.toString('base64');
const response = await lambdaRequest('/functions', {
method: 'POST',
body: {
FunctionName: functionName,
Runtime: 'nodejs20.x',
Role: 'arn:aws:iam::123456789012:role/lambda-execution-role',
Handler: 'index.handler',
Code: {
ZipFile: base64Code
}
}
});
return response;
};
// Đóng gói hàm: zip -r function.zip index.js node_modules/
await createFunctionWithZip('my-function', './function.zip');
Cập nhật mã hàm
const updateFunctionCode = async (functionName, updateConfig) => {
const response = await lambdaRequest(`/functions/${functionName}/code`, {
method: 'PUT',
body: {
S3Bucket: updateConfig.s3Bucket,
S3Key: updateConfig.s3Key,
Publish: updateConfig.publish || false
}
});
return response;
};
// Triển khai phiên bản mới
const updated = await updateFunctionCode('order-processor', {
s3Bucket: 'my-deployments-bucket',
s3Key: 'order-processor/v1.1.0.zip',
publish: true
});
console.log(`Đã cập nhật lên phiên bản: ${updated.Version}`);
Cập nhật cấu hình hàm
const updateFunctionConfig = async (functionName, config) => {
const response = await lambdaRequest(`/functions/${functionName}/configuration`, {
method: 'PUT',
body: {
Runtime: config.runtime,
Handler: config.handler,
Description: config.description,
Timeout: config.timeout,
MemorySize: config.memorySize,
Environment: {
Variables: config.environment
}
}
});
return response;
};
// Sửa đổi cấu hình
const updated = await updateFunctionConfig('order-processor', {
timeout: 60,
memorySize: 1024,
environment: {
DB_HOST: 'new-db.example.com',
LOG_LEVEL: 'debug'
}
});
Xóa một hàm
const deleteFunction = async (functionName, qualifier = null) => {
const path = qualifier
? `/functions/${functionName}?Qualifier=${qualifier}`
: `/functions/${functionName}`;
await lambdaRequest(path, { method: 'DELETE' });
console.log(`Hàm ${functionName} đã bị xóa`);
};
Gọi hàm Lambda
Gọi đồng bộ (yêu cầu-phản hồi)
const invokeFunction = async (functionName, payload, qualifier = null) => {
const path = qualifier
? `/functions/${functionName}/invocations?Qualifier=${qualifier}`
: `/functions/${functionName}/invocations`;
const response = await lambdaRequest(path, {
method: 'POST',
headers: {
'X-Amz-Invocation-Type': 'RequestResponse',
'X-Amz-Log-Type': 'Tail'
},
body: payload
});
const result = JSON.parse(Buffer.from(response.Payload).toString());
const logs = Buffer.from(response.LogResult, 'base64').toString();
return { result, logs };
};
// Gọi đồng bộ
const { result, logs } = await invokeFunction('order-processor', {
orderId: 'ORD-12345',
customerId: 'CUST-67890',
items: [
{ sku: 'PROD-001', quantity: 2 },
{ sku: 'PROD-002', quantity: 1 }
]
});
console.log(`Kết quả: ${JSON.stringify(result)}`);
console.log(`Nhật ký:\n${logs}`);
Gọi không đồng bộ (fire-and-forget)
const invokeAsync = async (functionName, payload) => {
const response = await lambdaRequest(`/functions/${functionName}/invocations`, {
method: 'POST',
headers: {
'X-Amz-Invocation-Type': 'Event',
'X-Amz-Log-Type': 'None'
},
body: payload
});
return {
statusCode: response.StatusCode,
executionId: response['X-Amz-Execution-Id']
};
};
// Gọi async
const result = await invokeAsync('email-sender', {
to: 'customer@example.com',
template: 'order-confirmation',
data: { orderId: 'ORD-12345' }
});
console.log(`ID gọi không đồng bộ: ${result.executionId}`);
Gọi thử nghiệm (Dry Run Invocation)
const dryRunInvocation = async (functionName) => {
const response = await lambdaRequest(`/functions/${functionName}/invocations`, {
method: 'POST',
headers: {
'X-Amz-Invocation-Type': 'DryRun'
}
});
return response;
};
// Kiểm tra quyền IAM
try {
await dryRunInvocation('order-processor');
console.log('Quyền gọi hàm OK');
} catch (error) {
console.error('Quyền bị từ chối:', error.message);
}
Các loại phản hồi gọi hàm
| Loại gọi hàm | Hành vi | Trường hợp sử dụng |
|---|---|---|
RequestResponse |
Đồng bộ, chờ kết quả | API, CLI |
Event |
Không đồng bộ, fire-and-forget | Xử lý sự kiện, notify |
DryRun |
Kiểm tra quyền | Xác thực, debug |
Quản lý phiên bản và biệt danh
Xuất bản phiên bản mới
const publishVersion = async (functionName, description = null) => {
const response = await lambdaRequest(`/functions/${functionName}/versions`, {
method: 'POST',
body: description ? { Description: description } : {}
});
return response;
};
// Xuất bản version
const version = await publishVersion('order-processor', 'v1.2.0 - Thêm tính toán thuế');
console.log(`Phiên bản đã xuất bản: ${version.Version}`);
Tạo biệt danh (alias)
const createAlias = async (functionName, aliasName, version, description = null) => {
const response = await lambdaRequest(`/functions/${functionName}/aliases`, {
method: 'POST',
body: {
Name: aliasName,
FunctionVersion: version,
Description: description
}
});
return response;
};
// Tạo alias production
const prodAlias = await createAlias('order-processor', 'prod', '5', 'Phiên bản sản xuất');
console.log(`ARN biệt danh: ${prodAlias.AliasArn}`);
Chuyển đổi lưu lượng với routing config
const updateAliasWithRouting = async (functionName, aliasName, routingConfig) => {
const response = await lambdaRequest(`/functions/${functionName}/aliases/${aliasName}`, {
method: 'PUT',
body: {
RoutingConfig: {
AdditionalVersionWeights: routingConfig
}
}
});
return response;
};
// 10% lưu lượng sang version 6, còn lại version 5
await updateAliasWithRouting('order-processor', 'prod', {
'6': 0.1
});
// Khi ổn định, chuyển toàn bộ sang version mới
await updateAliasWithRouting('order-processor', 'prod', {});
Use case alias phổ biến
| Biệt danh | Phiên bản | Mục đích |
|---|---|---|
dev |
$LATEST | Phát triển, testing |
staging |
Phiên bản kiểm thử | QA |
prod |
Phiên bản ổn định | Production traffic |
blue |
Hiện tại | Blue/green deploy |
green |
Phiên bản mới | Blue/green deploy |
Ánh xạ nguồn sự kiện
Tạo trigger SQS
const createSQSEventSource = async (functionName, queueArn, batchSize = 10) => {
const response = await lambdaRequest('/event-source-mappings', {
method: 'POST',
body: {
EventSourceArn: queueArn,
FunctionName: functionName,
BatchSize: batchSize,
Enabled: true
}
});
return response;
};
// Kết nối SQS
const mapping = await createSQSEventSource(
'order-processor',
'arn:aws:sqs:us-east-1:123456789012:orders-queue',
10
);
console.log(`Nguồn sự kiện đã được tạo: ${mapping.UUID}`);
Tạo trigger DynamoDB Stream
const createDynamoDBEventSource = async (functionName, streamArn, startingPosition = 'LATEST') => {
const response = await lambdaRequest('/event-source-mappings', {
method: 'POST',
body: {
EventSourceArn: streamArn,
FunctionName: functionName,
StartingPosition: startingPosition,
BatchSize: 100,
BisectBatchOnFunctionError: true,
MaximumRetryAttempts: 3
}
});
return response;
};
// Kết nối DynamoDB Stream
await createDynamoDBEventSource(
'user-analytics',
'arn:aws:dynamodb:us-east-1:123456789012:table/Users/stream/2026-03-25T00:00:00.000'
);
Các loại nguồn sự kiện
| Nguồn | Trường hợp sử dụng | Hỗ trợ Batch |
|---|---|---|
| SQS | Hàng đợi tin nhắn | Có (1-10) |
| Kinesis | Luồng real-time | Có (1-10.000) |
| DynamoDB | Thay đổi DB | Có (1-1.000) |
| S3 | Sự kiện object | Không |
| EventBridge | Định tuyến sự kiện | Có |
| API Gateway | HTTP API | Không |
| Schedule | Cron jobs | Không |
Quản lý lớp (Layer)
Tạo một layer
const createLayer = async (layerName, layerConfig) => {
const response = await lambdaRequest('/layers', {
method: 'POST',
body: {
LayerName: layerName,
Description: layerConfig.description,
CompatibleRuntimes: layerConfig.runtimes,
Content: {
S3Bucket: layerConfig.s3Bucket,
S3Key: layerConfig.s3Key
}
}
});
return response;
};
// Đóng gói layer
const layer = await createLayer('shared-utils', {
description: 'Các tiện ích và phụ thuộc dùng chung',
runtimes: ['nodejs20.x', 'nodejs18.x'],
s3Bucket: 'my-layers-bucket',
s3Key: 'shared-utils/v1.zip'
});
console.log(`ARN của lớp: ${layer.LayerArn}`);
Sử dụng layer trong hàm Lambda
const createFunctionWithLayers = async (functionConfig) => {
const response = await lambdaRequest('/functions', {
method: 'POST',
body: {
FunctionName: functionConfig.name,
Runtime: functionConfig.runtime,
Role: functionConfig.roleArn,
Handler: functionConfig.handler,
Code: {
S3Bucket: functionConfig.s3Bucket,
S3Key: functionConfig.s3Key
},
Layers: functionConfig.layers // Mảng ARN layer
}
});
return response;
};
// Gắn layer vào function
await createFunctionWithLayers({
name: 'api-handler',
roleArn: 'arn:aws:iam::123456789012:role/lambda-execution-role',
handler: 'index.handler',
runtime: 'nodejs20.x',
s3Bucket: 'my-deployments-bucket',
s3Key: 'api-handler/v1.0.0.zip',
layers: [
'arn:aws:lambda:us-east-1:123456789012:layer:shared-utils:1',
'arn:aws:lambda:us-east-1:123456789012:layer:aws-sdk:3'
]
});
Đồng thời và mở rộng quy mô
Thiết lập Reserved Concurrency
const putFunctionConcurrency = async (functionName, reservedConcurrentExecutions) => {
const response = await lambdaRequest(`/functions/${functionName}/concurrency`, {
method: 'PUT',
body: {
ReservedConcurrentExecutions: reservedConcurrentExecutions
}
});
return response;
};
// Dự trữ 100 lần thực thi đồng thời
await putFunctionConcurrency('order-processor', 100);
Giới hạn đồng thời mặc định
| Loại tài khoản | Giới hạn mặc định | Có thể tăng |
|---|---|---|
| Free Tier | 1.000 | Có |
| Pay-as-you-go | 1.000 | Có |
| Enterprise | 1.000+ | Tuỳ chỉnh |
Danh sách kiểm tra triển khai production
Trước khi lên production, cần:
- [ ] Sử dụng AWS SDK cho SigV4 tự động
- [ ] Quản lý version qua alias
- [ ] Thiết lập reserved concurrency cho hàm quan trọng
- [ ] Cài đặt Dead Letter Queue (DLQ) cho async
- [ ] Kích hoạt X-Ray tracing
- [ ] Cấu hình VPC cho DB access
- [ ] Ghi log định dạng JSON
- [ ] Thiết lập CloudWatch alarm
- [ ] Dùng layer cho các dependency chung
- [ ] Triển khai blue-green
Các ví dụ thực tế
Backend API serverless
Case: SaaS xây dựng API REST
- Thách thức: Lưu lượng biến động, khó scale
- Giải pháp: Lambda + API Gateway, auto scale
- Kết quả: Uptime 99.99%, tiết kiệm 60% chi phí
Triển khai:
- Mỗi resource 1 Lambda function
- API Gateway routing/xác thực
- DynamoDB backend
- Provisioned concurrency để đảm bảo latency
Quy trình xử lý sự kiện
Case: E-commerce xử lý đơn hàng
- Thách thức: Đột biến traffic
- Giải pháp: SQS + Lambda batch processing
- Kết quả: Không mất đơn, xử lý tăng 10 lần
Triển khai:
- SQS buffer đơn hàng
- Lambda batch 10 messages/lô
- DLQ cho message lỗi
- CloudWatch alarm theo dõi queue depth
Kết luận
API AWS Lambda cung cấp nền tảng serverless mạnh mẽ cho tự động hóa và scale. Các điểm cần nhớ:
- Xác thực IAM với SigV4 (dùng AWS SDK)
- Mẫu gọi hàm sync/async
- Quản lý version & alias cho deploy
- Ánh xạ nguồn sự kiện cho event-driven
- Layer chia sẻ code/phụ thuộc
- Apidog tối ưu kiểm thử API & cộng tác nhóm
Phần Câu hỏi thường gặp
Làm cách nào để xác thực với API Lambda?
Sử dụng thông tin xác thực AWS IAM với ký Signature Version 4. AWS SDK tự động ký.
Sự khác biệt giữa gọi đồng bộ và không đồng bộ là gì?
Gọi đồng bộ (RequestResponse) chờ hàm hoàn thành và trả về kết quả. Gọi không đồng bộ (Event) chỉ đẩy request vào hàng đợi và trả về ngay.
Các phiên bản Lambda hoạt động như thế nào?
Mỗi version đã xuất bản là immutable snapshot. Dùng alias để trỏ tới version cụ thể và chuyển đổi lưu lượng.
Lambda Layers là gì?
Layer đóng gói code/phụ thuộc riêng biệt, dùng chung cho nhiều hàm.
Làm sao giảm cold start?
Dùng provisioned concurrency, gói nhỏ, hoặc các runtime biên dịch (Go, Rust) cho hàm cần latency thấp.
Reserved concurrency là gì?
Đảm bảo số khe thực thi cố định cho hàm, tránh "noisy neighbor".
Kích hoạt Lambda từ S3 được không?
Được, cấu hình event notification S3 để gọi Lambda khi có object mới hoặc bị xóa.
Top comments (0)