You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Puppeteer大规模PDF生成致VM资源耗尽崩溃问题求助

Puppeteer大规模PDF生成导致GCP虚拟机资源耗尽崩溃的优化方案

我在测试Puppeteer的大规模PDF生成能力时,执行每秒5次请求、持续1分钟的压力测试,发现Google Cloud e2-highcpu-4(4核4GB内存、Ubuntu系统)虚拟机因资源耗尽崩溃。相关代码如下:

generatePdf函数

async generatePdf({
url,

displayHeaderFooter,
headerContent,
footerContent,

width,
height,
marginTop,
marginRight,
marginBottom,
marginLeft}: IPDFRepositoryDTO): Promise<Buffer> {
if (!global.browser) {
  await launchPuppeteer();
}

const page = await global.browser.newPage();

await page.goto(url, {
  waitUntil: 'networkidle0',
});

const isDisplayHeaderFooter =
  displayHeaderFooter != undefined ? displayHeaderFooter : true;

const pageOptions = {
  printBackground: true,
  format: 'Letter',
  displayHeaderFooter: isDisplayHeaderFooter,
  headerTemplate: headerContent,
  footerTemplate: footerContent,
  width,
  height,
  margin: {
    top: marginTop || '80px',
    bottom: marginBottom || '80px',
    left: marginLeft || '20px',
    right: marginRight || '20px',
  },
} as PDFOptions;

const pdf = await page.pdf(pageOptions);

await page.close();

return pdf;}

launchPuppeteer函数

export const launchPuppeteer = async () => {
    global.browser = await launch({
     args: [
      // '--no-sandbox',
      // '--disable-setuid-sandbox',
      // '--disable-dev-shm-usage',
      // '--disable-accelerated-2d-canvas',
      // '--no-first-run',
      // '--no-zygote',
      // '--single-process',
      // '--disable-gpu',

      '--no-sandbox',
      '--disable-accelerated-2d-canvas',
      '--no-zygote',
       '--single-process',
       '--disable-gpu',

      '--disable-canvas-aa', // Disable antialiasing on 2d canvas
      '--disable-2d-canvas-clip-aa', // Disable antialiasing on 2d canvas clips
      '--disable-gl-drawing-for-tests', // BEST OPTION EVER! Disables GL drawing operations which produce pixel output. With this the GL output will not be correct but tests will run faster.
      '--disable-dev-shm-usage',
      '--use-gl=swiftshader', // better cpu usage with --use-gl=desktop rather than --use-gl=swiftshader, still needs more testing.
      '--enable-webgl',
      '--hide-scrollbars',
      '--mute-audio',
      '--no-first-run',
      '--disable-infobars',
      '--disable-breakpad',
      //'--ignore-gpu-blacklist',
      // '--window-size=1280,1024', // see defaultViewport
      // '--user-data-dir=./chromeData', // created in index.js, guess cache folder ends up inside too.
      '--disable-setuid-sandbox'
    ],
  });

  console.log('browser ready');
};

核心问题分析

当前代码无并发控制,高请求量下瞬间创建大量页面,导致CPU和内存被完全占用;同时Puppeteer启动参数存在冗余,部分参数反而限制了资源利用效率,最终引发虚拟机崩溃。

优化方案

1. 限制并发页面数量

用队列机制控制同时处理的PDF生成任务数,避免瞬间耗尽资源。建议并发数与CPU核心数匹配(4核机器设为4):

// 引入p-queue实现队列管理(也可自行实现简单队列)
const PQueue = require('p-queue');
const pdfQueue = new PQueue({ concurrency: 4 });

async generatePdf(params) {
  return pdfQueue.add(async () => {
    if (!global.browser) await launchPuppeteer();
    const page = await global.browser.newPage();
    try {
      await page.goto(params.url, { waitUntil: 'networkidle2' });
      
      const isDisplayHeaderFooter = params.displayHeaderFooter != undefined ? params.displayHeaderFooter : true;
      const pageOptions = {
        printBackground: true,
        format: 'Letter',
        displayHeaderFooter: isDisplayHeaderFooter,
        headerTemplate: params.headerContent,
        footerTemplate: params.footerContent,
        width: params.width,
        height: params.height,
        margin: {
          top: params.marginTop || '80px',
          bottom: params.marginBottom || '80px',
          left: params.marginLeft || '20px',
          right: params.marginRight || '20px',
        },
      } as PDFOptions;

      const pdf = await page.pdf(pageOptions);
      return pdf;
    } catch (err) {
      console.error('PDF生成失败:', err);
      throw err;
    } finally {
      // 确保页面无论成功失败都关闭,避免内存泄漏
      await page.close().catch(closeErr => console.error('页面关闭失败:', closeErr));
    }
  });
}

2. 优化Puppeteer启动参数

移除冗余参数,启用新版无头模式,降低资源占用:

export const launchPuppeteer = async () => {
  global.browser = await launch({
    args: [
      '--no-sandbox',
      '--disable-setuid-sandbox',
      '--disable-dev-shm-usage', // 解决虚拟机共享内存不足问题
      '--disable-accelerated-2d-canvas',
      '--disable-gpu', // 虚拟机无GPU,直接禁用
      '--disable-canvas-aa', // 禁用画布抗锯齿,减少CPU消耗
      '--disable-2d-canvas-clip-aa',
      '--disable-gl-drawing-for-tests', // 禁用GL绘图,提升速度
      '--hide-scrollbars',
      '--mute-audio',
      '--no-first-run',
      '--disable-infobars',
      '--disable-breakpad'
    ],
    headless: 'new', // 使用新版无头模式,资源占用更低
    defaultViewport: { width: 1280, height: 720 }, // 设置默认视口,避免自适应消耗资源
  });
  console.log('browser ready');
};

3. 调整页面加载策略

networkidle0等待所有网络连接断开,高并发下会延长等待时间。改为networkidle2(允许最多2个活跃连接)或load(页面加载完成即停止),根据页面实际情况选择:

await page.goto(params.url, { waitUntil: 'networkidle2' });

4. 可选:虚拟机资源升级

如果业务需求的并发量确实较高,可考虑升级到e2-highcpu-8(8核8GB内存)虚拟机,或采用容器化部署配合自动扩容,应对峰值请求。


内容的提问来源于stack exchange,提问作者Eder Aparecido

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 18:33:36