Lambda ngoài VPC chạy ngon, nhưng gắn vào VPC để gọi RDS thì cold start từ 200ms lên 5s. Bài này là những gì cần biết để Lambda chạy production: VPC, concurrency, và Powertools.
flowchart TB
subgraph VPC["VPC"]
Lambda["Lambda VPC-attached<br/>ENI trong private subnet"]
RDS["RDS PostgreSQL"]
Lambda -->|"port 5432"| RDS
end
subgraph Concurrency
Prov["Provisioned: 10 instances always warm<br/>$0.015/GB-hr phụ phí (thêm vào execution cost,<br/>không thay thế on-demand — tổng cost cao hơn)"]
Res["Reserved: 50 slots guaranteed<br/>Free · bảo vệ khỏi function khác"]
OnDemand["On-Demand: 1,000 limit<br/>Can be throttled"]
end
Lambda trong VPC
aws lambda update-function-configuration \
--function-name api-handler \
--vpc-config SubnetIds=subnet-private-a,subnet-private-b,SecurityGroupIds=sg-lambda
Hậu quả: cold start chậm thêm 2-5s (tạo ENI trong subnet), mất internet access. Giải pháp cho S3/DynamoDB: VPC Gateway Endpoint (miễn phí giờ, nhưng có phí xử lý data ~$0.01/GB). Cho Secrets Manager/SQS: Interface Endpoint (~$7.20/tháng/AZ).
Concurrency: Reserved vs Provisioned
# Reserved: đảm bảo 50 slot cho function này (miễn phí)
aws lambda put-function-concurrency --function-name api-handler --reserved-concurrent-executions 50
# Provisioned: pre-warm 10 instances (loại bỏ cold start)
# Lưu ý: cần publish version trước, không dùng $LATEST
aws lambda publish-version --function-name api-handler
aws lambda put-provisioned-concurrency-config \
--function-name api-handler --qualifier '1' \
--provisioned-concurrent-executions 10
| Loại | Cost | Dùng khi |
|---|---|---|
| Reserved | Miễn phí | Bảo vệ function A không đói khi B spike |
| Provisioned | $0.015/GB-hr | Production API cần sub-100ms p99 |
Powertools: structured logging + metrics + tracing
import { Logger, injectLambdaContext } from "@aws-lambda-powertools/logger";
import { Metrics, logMetrics } from "@aws-lambda-powertools/metrics";
import { Tracer, captureLambdaHandler } from "@aws-lambda-powertools/tracer";
import middy from "@middy/core";
const logger = new Logger({ serviceName: "api-handler" });
const metrics = new Metrics({ namespace: "MyApp" });
const tracer = new Tracer({ serviceName: "api-handler" });
const handler = async (event: any) => {
logger.info("Processing", { path: event.path });
metrics.addMetric("SuccessfulRequest", "Count", 1);
const segment = tracer.getSegment()!;
const sub = segment.addNewSubsegment("## dbQuery");
const result = await db.query("...");
sub.close();
return { statusCode: 200, body: JSON.stringify(result) };
};
export const main = middy(handler)
.use(injectLambdaContext(logger))
.use(logMetrics(metrics))
.use(captureLambdaHandler(tracer));
- Logger: structured JSON + correlation ID (context.awsRequestId), cold start marker
- Metrics: EMF → CloudWatch metrics, không cần PutMetricData API call (không throttle, không cost thêm)
- Tracer: X-Ray subsegment tự động cho DynamoDB, S3, HTTP calls
Những nguyên tắc nhớ nhanh
- VPC-attached Lambda: chỉ khi cần truy cập tài nguyên private (RDS, ElastiCache, Secrets Manager, on-premise qua Direct Connect/VPN). Dùng VPC Endpoint thay NAT Gateway
- Provisioned concurrency: loại bỏ cold start. Application Auto Scaling cho scheduled scaling
- Powertools: Logger + Metrics + Tracer — dùng ngay từ function đầu tiên
Bài sau: Phần 12: RDS & Aurora PostgreSQL — managed SQL toàn tập