Chromium nặng khoảng 280MB. Trong khi đó, gói giải nén tối đa của AWS Lambda chỉ là 250MB. Nếu bạn từng thử npm install puppeteer rồi triển khai thẳng lên Lambda, hẳn bạn đã biết phép toán này “không ổn” ở chỗ nào rồi đấy.
Tôi đã đủ thời gian ngồi gỡ lỗi lỗi "Failed to launch the browser process" lúc 2 giờ sáng để hiểu rằng chủ đề này xứng đáng có một bài so sánh tử tế, chứ không phải thêm một tutorial chỉ hướng dẫn một cách rồi bỏ mặc bạn tự đoán hai cách còn lại. Vì vậy, bài viết này sẽ đi thẳng vào: Layers vs. Container Images vs. direct ZIP upload, một ma trận tương thích phiên bản cập nhật đến 2026, và phần xử lý sự cố cho năm lỗi bạn có xác suất cao nhất sẽ gặp.
Puppeteer trên AWS Lambda là gì, và vì sao nên dùng?
Puppeteer là một thư viện Node.js điều khiển Chromium không giao diện thông qua Chrome DevTools Protocol. Lambda là dịch vụ compute serverless của AWS — bạn trả tiền theo từng lần chạy, hệ thống tự mở rộng, và bạn không phải đụng vào server nào cả. Ghép hai thứ này lại, bạn sẽ có một bộ tự động hóa trình duyệt có thể chạy song song hàng trăm phiên mà không cần provision một EC2 instance nào.
Các trường hợp sử dụng thường khá giống nhau giữa các team: crawl dữ liệu web, tạo ảnh chụp màn hình và PDF, giám sát synthetic, pre-render ứng dụng single-page để phục vụ SEO, và kiểm thử UI tự động. Vấn đề luôn quay về điểm tôi đã nói ở trên — kích thước của Chromium so với giới hạn package của Lambda. Đó là lý do không ai deploy nguyên bộ puppeteer (vốn tự tải kèm Chromium) lên Lambda. Thay vào đó, người ta dùng puppeteer-core (không kèm browser) kết hợp với một binary Chromium đã tối ưu cho Lambda, phổ biến nhất là @sparticuz/chromium.
Chỉ cần thay thế đó thôi — dùng puppeteer-core thay vì puppeteer — đã giải quyết được khoảng 80% bài toán dung lượng trước khi bạn viết bất kỳ cấu hình triển khai nào.
Layers vs. Container Image vs. ZIP: Chọn hướng đi trước đã
Có một điều khiến tôi hơi bực trong lúc nghiên cứu: gần như mọi hướng dẫn hiện có chỉ nói đúng một phương pháp triển khai. Tutorial AWS SAM thì dùng Layers. Ví dụ CDK thì dùng Docker. Một bài Substack ngẫu nhiên lại dùng ZIP thô với Chromium binary đặt trên S3. Không ai đặt chúng cạnh nhau, nên quyết định quan trọng đầu tiên — phương pháp nào phù hợp với tình huống của tôi — lại bị bỏ qua hoàn toàn.
Vậy thì hãy sửa điều đó.
| Tiêu chí | Lambda Layers | Container Image (Docker) | Tải ZIP trực tiếp |
|---|---|---|---|
| Kích thước gói tối đa | 250 MB sau khi giải nén (tính trên toàn bộ layers) | Image 10 GB | 250 MB sau khi giải nén |
| Độ phức tạp triển khai | Trung bình (quản lý layer ARN) | Cao hơn (Dockerfile + push ECR) | Thấp nhất (zip rồi upload) |
| Ảnh hưởng đến cold start | Trung bình | Cao hơn một chút (phải pull image lớn hơn) | Trung bình |
| Quy trình cập nhật Chromium | Publish lại phiên bản layer | Rebuild image | Upload lại zip |
| Phù hợp nhất với | Prototype nhanh, người dùng Serverless Framework | Workload production, team đã có Docker CI | Hàm đơn giản, dùng một lần |
| Hỗ trợ IaC | SAM, Serverless Framework | CDK, SAM, Terraform | Console, mọi IaC |
Cả giới hạn 250MB và 10GB đều lấy trực tiếp từ tài liệu quota Lambda của AWS — đây không phải con số mới thay đổi gần đây, nhưng nó là ràng buộc quyết định toàn bộ chiến lược triển khai ngay từ đầu.
Theo kinh nghiệm của tôi: nếu bạn đang làm prototype hoặc đã dùng Serverless Framework, hãy bắt đầu với Layers. Nếu bạn đang đưa vào production và team đã có Docker CI/CD, hãy chọn Container Image — ngưỡng 10GB cho bạn khá nhiều dư địa. Nếu bạn chỉ cần một hàm thỉnh thoảng chụp vài tấm màn hình, direct ZIP là lựa chọn ít rườm rà nhất.
Cả ba hướng đều dựa trên cùng một cặp phụ thuộc cốt lõi: puppeteer-core + @sparticuz/chromium. Phương pháp triển khai chỉ thay đổi cách bạn đóng gói cặp đó, chứ không thay đổi thứ bạn đang đóng gói.

Ma trận tương thích phiên bản cho 2026 (đừng đoán mò nữa)
Đây mới là phần khiến mọi người mất hàng tháng, không phải vài giờ. Phàn nàn lớn nhất trên Stack Overflow và GitHub issues không phải là “triển khai thế nào”, mà là “vì sao deployment đang chạy ổn tự nhiên hỏng sau một lần npm update”. Thủ phạm gần như luôn là sự lệch pha giữa @sparticuz/chromium, puppeteer-core, và runtime Node.js.
Trước hết, cần nhấn mạnh: chrome-aws-lambda (gói gốc của alixaxel) đã ngừng duy trì. Nó lỗi trên Node 18+ và không còn theo kịp các bản Chromium mới. Nếu bạn gặp tutorial nào còn nhắc tới nó, hãy đóng tab đó lại — đó là tài liệu đã lỗi thời. Mọi hướng dẫn hiện nay nên trỏ bạn sang @sparticuz/chromium.
Hãy dùng quy tắc tương thích sau thay vì nhìn số major của package rồi ghép bừa:
| Thành phần | Quy tắc phiên bản | Cần kiểm tra gì trước khi deploy |
|---|---|---|
puppeteer-core | Chọn phiên bản Puppeteer mà ứng dụng của bạn cần | Tra phiên bản Chromium build được hỗ trợ bởi bản Puppeteer đó |
@sparticuz/chromium | Major version của nó bám theo major Chromium, không phải major Puppeteer | Khớp với Chromium build trong bảng hỗ trợ của Puppeteer và đọc release notes của Sparticuz |
| AWS Lambda Node.js runtime | Dùng runtime Lambda còn được hỗ trợ hiện tại | Chạy thử invocation sau mỗi lần cập nhật runtime hoặc package |
| Kiến trúc | Package npm có sẵn binary x64; hỗ trợ arm64 bắt đầu từ Chromium v135 qua arm64 layer hoặc remote pack | Khớp chính xác kiến trúc Lambda, artifact layer/pack và phiên bản Chromium |
Tôi cố tình không gán cứng một cặp package ở đây vì @sparticuz/chromium đi theo vòng đời phát hành của Chromium và không dùng semantic versioning theo kiểu thông thường. Hãy bắt đầu từ trang chính thức Puppeteer Chromium Support, ghi lại major Chromium được phiên bản Puppeteer bạn chọn hỗ trợ, rồi chọn đúng major đó của @sparticuz/chromium. Sau đó, đọc release notes của Sparticuz để biết các thay đổi gây break ở mức patch và chi tiết kiến trúc. Đừng cài cùng một số major cho cả hai package trừ khi mapping đó đã được xác nhận rõ từ hai nguồn này.

Cách triển khai Puppeteer trên AWS Lambda bằng Lambda Layers
Lambda Layer cho phép bạn đóng gói Chromium tách biệt khỏi mã hàm, nhờ đó handler của bạn nhẹ hơn và có thể tái sử dụng cùng một Chromium layer cho nhiều function. Đây là thứ gần với “quick start” nhất trong toàn bộ không gian này.
Bước 1: Cài puppeteer-core và package -min
Khi file Chromium nằm trong Lambda Layer, hãy giữ package của function thật nhỏ bằng cách dùng @sparticuz/chromium-min. Hãy thay các placeholder bằng phiên bản tương thích mà bạn đã xác nhận ở trên:
npm install puppeteer-core@$PUPPETEER_VERSION \
@sparticuz/chromium-min@$CHROMIUM_VERSION
Bạn đang cài puppeteer-core — không phải puppeteer — vì nó bỏ qua bước tự động tải browser. Package -min cung cấp các helper để launch, còn layer sẽ cung cấp file Chromium nén Brotli dưới /opt/chromium.
Bước 2: Tạo hoặc tham chiếu một Chromium Lambda Layer
Dùng archive layer theo kiến trúc được đính kèm trong một release chính thức của Sparticuz, hoặc tự build archive từ repository chính thức. Với Lambda x86_64, lệnh build được tài liệu hóa là:
git clone --depth=1 https://github.com/sparticuz/chromium.git
cd chromium
make chromium.x64.zip
Lệnh này tạo ra chromium.x64.zip. Hãy upload nó lên S3 rồi publish thành Lambda Layer với runtime và kiến trúc bạn thực sự dùng. Với arm64, hãy dùng artifact release arm64 tương ứng hoặc target build phù hợp; đừng gắn archive x64 vào function arm64.
Nếu bạn dùng SAM, gắn trực tiếp layer ARN trong template.yaml:
Resources:
PuppeteerFunction:
Type: AWS::Serverless::Function
Properties:
Layers:
- arn:aws:lambda:us-east-1:XXXXXXXXXXXX:layer:chromium-layer:1
Bước 3: Viết Lambda Handler
Đây là một pattern handler hoạt động tốt, mở một URL rồi trả về tiêu đề trang:
import puppeteer from "puppeteer-core";
import chromium from "@sparticuz/chromium-min";
export const handler = async () => {
const browser = await puppeteer.launch({
args: puppeteer.defaultArgs({ args: chromium.args, headless: "shell" }),
executablePath: await chromium.executablePath("/opt/chromium"),
headless: "shell",
});
try {
const page = await browser.newPage();
await page.goto("https://example.com", { waitUntil: "domcontentloaded" });
return { title: await page.title() };
} finally {
await browser.close();
}
};
Hãy chú ý đến khối finally. Luôn đóng browser ở đó — nếu không, các môi trường Lambda warm sẽ tích tụ tiến trình browser “zombie” qua nhiều lần gọi, và sớm muộn gì bạn cũng gặp lỗi bộ nhớ kỳ lạ không liên quan gì đến code của chính mình.
Bước 4: Cấu hình Memory, Timeout và Architecture
Hãy đặt memory tối thiểu 1024 MB — tôi khuyên 1536–2048 MB cho bất kỳ thứ gì vượt quá một tác vụ chụp màn hình đơn giản. Đặt timeout ít nhất 60 giây. Chỉ định architecture là x86_64 trừ khi bạn đã xác nhận rõ hỗ trợ arm64 cho đúng phiên bản Chromium của mình (mỗi release có thể khác nhau).
Bước 5: Triển khai và kiểm thử
sam build && sam deploy --guided
Hãy invoke bằng test event, rồi kiểm tra ngay CloudWatch Logs nếu có gì trục trặc — 90% lỗi trong phần troubleshooting bên dưới sẽ hiện rất rõ trong đó.
Cách triển khai Puppeteer trên AWS Lambda bằng Container Images (Docker)
Container image giải quyết hoàn toàn nỗi đau 250MB bằng cách cho bạn giới hạn 10GB. Đây thường là lựa chọn tốt hơn cho workload production, nhất là khi team của bạn đã có Docker trong pipeline CI.
Bước 1: Tạo Dockerfile
Bắt đầu từ AWS Lambda base image chính thức cho Node.js, cài dependencies của bạn, rồi khai báo handler:
FROM public.ecr.aws/lambda/nodejs:20
COPY package*.json ./
RUN npm install --production
COPY . .
CMD ["index.handler"]
Tùy theo package Chromium bạn dùng, bạn có thể cần yum install thêm một vài shared library (xem kỹ hơn trong phần troubleshooting) — @sparticuz/chromium đã đóng gói sẵn phần lớn thứ nó cần, nên giảm đáng kể ma sát so với việc cài Chrome đầy đủ thủ công.
Bước 2: Build và push lên Amazon ECR
aws ecr create-repository --repository-name puppeteer-lambda
docker build -t puppeteer-lambda .
docker tag puppeteer-lambda:latest <account-id>.dkr.ecr.<region>.amazonaws.com/puppeteer-lambda:latest
aws ecr get-login-password | docker login --username AWS --password-stdin <account-id>.dkr.ecr.<region>.amazonaws.com
docker push <account-id>.dkr.ecr.<region>.amazonaws.com/puppeteer-lambda:latest
Hãy giữ image ở cùng region với Lambda function — kéo image xuyên region sẽ thêm độ trễ không cần thiết.
Bước 3: Tạo Lambda Function từ container image
Trỏ function của bạn tới ECR image URI bằng CLI hoặc CDK, rồi đặt memory (1536–2048 MB) và timeout (60–120 giây) giống như khi deploy bằng layer.
Bước 4: Triển khai và kiểm thử
Invoke bằng test event và kiểm tra output. Tradeoff chính so với Layers: cold start cao hơn một chút vì phải pull image lớn hơn, nhưng bạn có nhiều không gian hơn cho dependencies.
Cách triển khai Puppeteer trên AWS Lambda bằng direct ZIP upload
Đây là lựa chọn không cầu kỳ — không cần quản lý layer, cũng không phải build Docker. Phù hợp cho prototype hoặc một function đơn lẻ không cần mở rộng thành cả một nền tảng tự động hóa trình duyệt.
Bước 1: Cài dependencies cục bộ
Với một gói ZIP độc lập, hãy dùng puppeteer-core + @sparticuz/chromium và khóa cố định cả hai phiên bản. Package đầy đủ chứa các file Chromium đã nén và sẽ giải nén ra /tmp khi chạy. Chỉ dùng @sparticuz/chromium-min khi các file đó được cung cấp riêng qua Lambda Layer hoặc một remote pack URL tốc độ cao; bản -min tự nó không chứa file Brotli.
Bước 2: Bundle và nén ZIP function
npm install --production
zip -r function.zip . -x "*.git*"
Cờ --production rất quan trọng ở đây — các dev dependencies sẽ ăn vào ngân sách 250MB của bạn một cách vô ích.
Bước 3: Upload và cấu hình Lambda Function
aws lambda update-function-code --function-name my-puppeteer-fn --zip-file fileb://function.zip
Nếu ZIP của bạn vượt quá 50MB, bạn không thể upload trực tiếp qua console hoặc một lệnh CLI đơn giản — bạn sẽ cần upload lên S3 trước rồi tham chiếu đến S3 URI. Hãy đặt memory, timeout và architecture giống như hai cách trước.
Bước 4: Triển khai và kiểm thử
Dùng lại flow invoke rồi xem logs. Với full package, chromium.executablePath() không cần đối số. Với chromium-min, hãy truyền đúng đường dẫn layer hoặc remote pack URL, chẳng hạn chromium.executablePath("/opt/chromium") cho layout layer ở trên. Remote pack sẽ cộng thêm thời gian tải ở cold start đầu tiên, nên hãy host nó gần function và kiểm tra kỹ version artifact cùng architecture.
Những đối số puppeteer.launch() thực sự hoạt động trên Lambda
Đây là đoạn code ai cũng copy-paste, nên hãy làm cho đúng. Môi trường thực thi của Lambda không có /dev/shm, không có GPU, và chạy với quyền hạn bị giới hạn — nghĩa là lời gọi puppeteer.launch() mặc định vốn chạy ngon trên laptop sẽ chỉ đơn giản là... không chạy ở đây.
const viewport = {
width: 1920,
height: 1080,
deviceScaleFactor: 1,
isMobile: false,
hasTouch: false,
isLandscape: true,
};
const browser = await puppeteer.launch({
args: await puppeteer.defaultArgs({ args: chromium.args, headless: "shell" }),
executablePath: await chromium.executablePath(),
headless: "shell",
defaultViewport: viewport,
});
Mảng chromium.args từ @sparticuz/chromium đã bao gồm sẵn các flag quan trọng cho môi trường serverless — --no-sandbox, --disable-gpu, --disable-dev-shm-usage, và các flag tương tự. Đó chính là lý do nên dùng package này thay vì tự viết danh sách flag: nó bám theo yêu cầu của Chromium để bạn không phải tự xử lý.

Troubleshooting: 5 lỗi mà developer nào cũng gặp
Tôi không thấy guide nào trước đây có phần troubleshooting tử tế, điều này khá khó hiểu vì lỗi gần như chắc chắn là lý do bạn đang đọc bài này ngay từ đầu.
"Failed to launch the browser process"
Nguyên nhân gốc: thiếu shared libraries (libnss3.so, libatk, v.v.) hoặc executablePath sai.
Cách sửa: @sparticuz/chromium đã đóng gói phần lớn dependency cần thiết, đó là lý do nó được khuyên dùng thay vì tự mang một Chromium binary riêng. Với triển khai Docker, nếu vẫn gặp lỗi này, hãy yum install trực tiếp các thư viện còn thiếu trong Dockerfile.
"Unzipped size must be smaller than 262144000 bytes"
Nguyên nhân gốc: bạn đã cài package puppeteer đầy đủ, vốn đi kèm Chromium download riêng của nó (~400MB).
Cách sửa: chuyển sang puppeteer-core + @sparticuz/chromium. Nếu thực sự cần nhiều dung lượng hơn, hãy chuyển sang Container Image với giới hạn 10GB.
"Browser disconnected" hoặc timeout ở browser.newPage()
Nguyên nhân gốc: memory Lambda không đủ, hoặc bạn thiếu các flag như --disable-gpu trong launch args.
Cách sửa: đặt memory tối thiểu 1024MB (tôi sẽ chọn cao hơn — xem benchmark bên dưới) và đảm bảo rằng bạn đang truyền chromium.args thay vì một danh sách custom bị cắt bớt.
Code chạy được nhưng hỏng sau khi Lambda runtime cập nhật
Nguyên nhân gốc: AWS định kỳ vá runtime nền, điều này có thể làm thay đổi phiên bản shared library hoặc patch Node.js khiến bạn bị ảnh hưởng.
Cách sửa: khóa cứng phiên bản @sparticuz/chromium, khóa phiên bản Node runtime trong cấu hình function, và — phần này nhiều người hay bỏ qua — test lại sau mỗi thông báo cập nhật runtime của AWS, không chỉ khi có gì đó hỏng.
"Protocol error: Connection closed" sau khoảng 30 giây
Nguyên nhân gốc: timeout của Lambda ngắn hơn thời gian page thực sự cần để tải và render.
Cách sửa: tăng timeout lên 60–120 giây, đặt rõ page.setDefaultNavigationTimeout(), và đổi waitUntil: 'networkidle0' sang waitUntil: 'domcontentloaded' nếu bạn không cần chờ mọi request mạng phải ổn định hoàn toàn mới đi tiếp.
Tối ưu cho production: Memory, cold start và chi phí
Phần lớn guide chỉ bảo bạn “tăng memory” rồi dừng lại. Như vậy không đủ thực dụng — dưới đây là điều thực sự thay đổi khi bạn tăng memory.
Memory vs. Performance
Lambda cấp phát CPU tỷ lệ thuận với memory, đây là chi tiết khiến nhiều người nhầm. Nhiều memory hơn không chỉ là “nhiều RAM hơn” — mà còn là CPU nhanh hơn, trực tiếp giúp Chromium render nhanh hơn. Trong thực tế, các team chạy benchmark Puppeteer thường thấy thời gian thực thi cải thiện đáng kể khi tăng từ 512MB lên dải 1536–2048MB, dù con số chính xác còn phụ thuộc rất nhiều vào trang bạn đang render. Thay vì đưa ra một bảng benchmark cụ thể rồi vài tuần sau đã lỗi thời, hãy tự test ở 512MB, 1024MB, 1536MB và 2048MB trên chính trang mục tiêu của bạn — một bài test 10 phút sẽ cho bạn biết chính xác điểm cân bằng giữa chi phí và hiệu năng.
Provisioned Concurrency cho cold start
Nếu bạn đang làm thứ nhạy cảm với độ trễ — giám sát synthetic, API chụp màn hình thời gian thực — cold start là kẻ thù của bạn. Provisioned Concurrency giữ sẵn một số environment ở trạng thái warm và sẵn sàng, loại bỏ chi phí cold start nhưng đổi lại bạn phải trả tiền cho năng lực nhàn rỗi đó. Nó rất đáng giá khi độ trễ quan trọng hơn tối ưu chi phí thuần túy.
arm64 (Graviton) để tiết kiệm chi phí
Lambda chạy trên Graviton thường rẻ hơn khoảng 20% so với x86_64. Điểm cần lưu ý: hỗ trợ arm64 của @sparticuz/chromium trong lịch sử ít hoàn thiện hơn x86_64, nên hãy xác nhận rõ ràng với đúng phiên bản bạn đã khóa trước khi chuyển sang Graviton trong production.
VPC vs. không VPC
Đưa function vào VPC trước đây làm cold start tăng đáng kể; AWS đã thu hẹp phần lớn khoảng cách này trong những năm gần đây, nhưng nó vẫn chưa bằng không. Chỉ nên đặt function trong VPC nếu nó thực sự cần truy cập tài nguyên private như RDS hoặc ElastiCache — nếu không, hãy bỏ qua.
Khi nào nên rời Lambda hoàn toàn
Nếu tác vụ trình duyệt của bạn thường vượt quá 15 phút, cần hơn 10GB memory, hoặc cần session browser tồn tại liên tục giữa các request, thì ở giai đoạn đó Lambda đang cản trở bạn. ECS Fargate được sinh ra cho đúng kiểu này — compute chạy dài, tài nguyên cấu hình được, trả tiền theo giây. Lambda rất tuyệt cho tác vụ trình duyệt ngắn, theo đợt, có thể song song hóa; nhưng nó là công cụ sai khi workload của bạn bắt đầu giống một service lâu dài.
Khi nào triển khai Puppeteer trên Lambda là cách tiếp cận sai
Có một điều đáng để nhìn nhận thật lòng: một phần lớn developer tìm đến các bài “Puppeteer + Lambda” thực ra đang cố giải bài toán trích xuất dữ liệu, chứ không phải bài toán tự động hóa trình duyệt. Nếu thứ bạn thực sự cần là dữ liệu có cấu trúc từ trang web — danh sách sản phẩm, thông tin liên hệ, nội dung trang — thì toàn bộ công đoạn đóng gói Chromium, khóa phiên bản và quản lý layer ở trên chỉ là overhead không cần thiết.
Nên dùng Lambda + Puppeteer nếu bạn thật sự cần điều khiển trình duyệt: tương tác form tùy chỉnh, pipeline chụp màn hình/PDF, giám sát synthetic, hoặc kiểm thử dựa trên browser nơi bạn thực sự thao tác DOM bằng code.
Hãy cân nhắc một scraping API nếu mục tiêu cuối cùng của bạn là JSON có cấu trúc từ một trang web, chứ không phải một phiên browser bạn tự điều khiển. Thunderbit Open API xử lý rendering JS, cơ chế chống bot và CAPTCHA chỉ bằng một HTTP call — POST /extract với JSON Schema sẽ trả về dữ liệu có cấu trúc, còn POST /distill cho ra Markdown sạch. Ngoài ra còn có MCP server (thunderbit_extract, thunderbit_distill) nếu bạn đang xây AI agent cần lấy dữ liệu giữa workflow mà không muốn tự spin up browser.
| Yếu tố | Lambda + Puppeteer (tự làm) | Extraction API (ví dụ: Thunderbit) |
|---|---|---|
| Thời gian thiết lập | Vài giờ (đóng gói, layer, debug) | Vài phút (API key + HTTP call) |
| Bảo trì | Liên tục (khóa phiên bản, cập nhật runtime) | Nhà cung cấp xử lý |
| Xử lý anti-bot | Thủ công (stealth plugin, proxy) | Tích hợp sẵn |
| Định dạng đầu ra | HTML/ảnh chụp thô, bạn tự parse | JSON có cấu trúc qua schema |
| Phù hợp nhất với | Tự động hóa browser đầy đủ, testing, luồng tùy chỉnh | Trích xuất dữ liệu, scraping, ingest nội dung |
Tôi nói thẳng nhé: nếu bạn đang tốn hàng giờ debug Chromium binary chỉ để kéo JSON từ trang sản phẩm, đó là dấu hiệu bạn đang giải sai bài toán. Hãy dành route Lambda tự dựng cho khi bạn thật sự cần điều khiển browser — còn với trích xuất dữ liệu, có một con đường trực tiếp hơn. Nếu bạn đang cân nhắc lựa chọn này cho một dự án cụ thể, hướng dẫn về AI web scraper của chúng tôi sẽ đi sâu hơn vào bức tranh tổng thể, và Thunderbit Chrome Extension rất đáng xem nếu bạn muốn thử hướng tiếp cận “extraction-first” trước khi chốt một trong hai con đường.
Kết luận
Ba phương pháp triển khai, một điểm chung: khóa phiên bản cho chuẩn, cấp đủ memory để Chromium có không gian hoạt động, và chọn cách deploy theo đúng ràng buộc thực tế của bạn thay vì theo tutorial đầu tiên bạn tìm thấy. Layers phù hợp cho iteration nhanh, Container Images phù hợp cho production scale, còn ZIP phù hợp cho trường hợp đơn lẻ, đơn giản. Và nếu thứ bạn thực sự làm là trích xuất dữ liệu chứ không phải tự động hóa trình duyệt — có lẽ nên kiểm tra xem một API trích xuất chuyên dụng có thể giúp bạn tránh hoàn toàn nỗi đau đóng gói hay không.
Câu hỏi thường gặp
Năm 2026 còn chạy được Puppeteer trên AWS Lambda không?
Có — dùng puppeteer-core kết hợp với @sparticuz/chromium, rồi triển khai qua Layers, Container Image hoặc direct ZIP. Package puppeteer đầy đủ và package chrome-aws-lambda đã ngừng duy trì không còn hoạt động ổn định trên các runtime Lambda hiện tại.
Kích thước package tối đa của AWS Lambda là bao nhiêu? 250MB sau khi giải nén cho Layers và ZIP deployments; 10GB cho Container Image deployments, theo quota Lambda của AWS.
chrome-aws-lambda còn được duy trì không?
Không. Package chrome-aws-lambda gốc (của alixaxel) đã ngừng duy trì và lỗi trên Node 18+. Hãy dùng @sparticuz/chromium thay thế — hiện đây là tiêu chuẩn còn được bảo trì.
Puppeteer cần bao nhiêu memory trên AWS Lambda? 1024MB là mức tối thiểu thực tế; 1536–2048MB là vùng bạn mới thấy hiệu năng thật sự thoải mái. Dưới 1024MB, hãy chuẩn bị tinh thần cho tốc độ chạy chậm hơn đáng kể vì Lambda gắn CPU allocation với memory.
Làm sao để giảm cold start cho Puppeteer trên Lambda? Cấp nhiều memory hơn (đồng thời có thêm CPU), cân nhắc Provisioned Concurrency nếu độ trễ là yếu tố sống còn, và giữ deployment package thật gọn — mỗi dependency thêm vào đều làm cold start lâu hơn.


