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

在AWS Lambda热启动时复用Chromium/Puppeteer实例的方案问询

问题

我在AWS Lambda中使用Puppeteer/Chromium,目前每次调用Lambda处理程序时都会启动并关闭一个Chromium实例。以下是基于@sparticuz/chromium文档简化的ES模块示例:

import puppeteer from "puppeteer-core";
import chromium from "@sparticuz/chromium";

export const handler = async (event, context) => {
  let browser = null;

  try {
    browser = await puppeteer.launch({
      args: [
        ...chromium.args,
        '--disable-gpu',
        '--single-process',
      ],
      defaultViewport: chromium.defaultViewport,
      executablePath: await chromium.executablePath(),
      headless: chromium.headless,
      ignoreHTTPSErrors: true,
    });

    let page = await browser.newPage();

    await page.goto(event.url || 'https://example.com');

    return await page.title();
  } catch (error) {
    console.log('Error: ', error);
  } finally {
    if (browser !== null) {
      await browser.close();
    }
  }
};

由于启动Chromium耗时较长,我希望在热启动场景下降低延迟。AWS Lambda官方文档《Optimizing static initialization》提到,同一执行环境中的全局变量会在调用间保留值。请问:

  1. 能否将浏览器实例移至全局变量?
  2. 若可以,当浏览器崩溃时如何避免Lambda实例卡住?
  3. 同时如何防止处理程序未正常关闭时出现内存耗尽(如加载无限量页面)的问题?

解答

1. 可以将浏览器实例移至全局变量

Lambda的执行环境在热启动时会保留全局变量的状态,把浏览器实例放在全局作用域,就能实现跨调用复用,避免每次启动Chromium的开销。修改后的代码示例如下:

import puppeteer from "puppeteer-core";
import chromium from "@sparticuz/chromium";

// 全局变量存储浏览器实例
let globalBrowser = null;

export const handler = async (event, context) => {
  let page = null;

  try {
    // 若全局浏览器未初始化或已断开连接,才启动新实例
    if (!globalBrowser || !globalBrowser.isConnected()) {
      globalBrowser = await puppeteer.launch({
        args: [
          ...chromium.args,
          '--disable-gpu',
          '--single-process',
        ],
        defaultViewport: chromium.defaultViewport,
        executablePath: await chromium.executablePath(),
        headless: chromium.headless,
        ignoreHTTPSErrors: true,
      });
    }

    page = await globalBrowser.newPage();
    await page.goto(event.url || 'https://example.com', { timeout: 30000 }); // 添加载超时
    return await page.title();
  } catch (error) {
    console.log('Error: ', error);
    // 捕获浏览器崩溃相关错误,重置全局实例
    if (error.message.includes('Browser closed') || error.message.includes('Target closed')) {
      globalBrowser = null;
    }
    throw error;
  } finally {
    // 每次调用结束后关闭当前页面,而非浏览器
    if (page !== null) {
      await page.close().catch(err => console.log('Failed to close page:', err));
    }
  }
};

2. 浏览器崩溃时的处理方案

  • 错误捕获与实例重置:在catch块中识别浏览器崩溃类错误(如Browser closed、Target closed),一旦触发就将全局浏览器实例置为null,确保下次调用会重新初始化新实例。
  • 前置健康检查:每次调用前通过globalBrowser.isConnected()判断浏览器是否存活,若未连接则直接重启实例,避免使用已崩溃的浏览器。
  • 利用Lambda超时机制:配置合理的Lambda超时时间(比如30秒),即使浏览器崩溃导致处理程序卡住,超时后Lambda会自动终止当前执行环境,不会持续占用资源。

3. 防止内存耗尽的措施

  • 强制关闭页面:在finally块中确保每次调用后关闭当前使用的页面,避免页面实例累积占用内存;即使关闭失败也要捕获错误,不影响后续流程。
  • 限制页面加载时长:在page.goto()中添加超时参数,防止页面无限加载导致资源耗尽。
  • 监控全局页面数量:可以在全局维护一个页面计数变量,每次创建页面时递增,关闭时递减;当计数达到阈值时,拒绝新请求或清理闲置页面。
  • 调整Lambda资源配置:Chromium对内存需求较高,建议给Lambda配置至少1GB内存,同时启用CloudWatch监控内存使用情况,及时调整配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 10:22:46