提示与技巧

本文档介绍 Cloud Functions 设计、实现、测试和部署方面的最佳做法。

正确做法

本部分介绍 Cloud Functions 设计和实现方面的一般性最佳做法。

编写幂等函数

即使您的函数被多次调用,也应产生相同的结果。这样,如果前面的代码调用中途失败,您可以重新调用。如需了解详情,请参阅重试后台函数

务必删除临时文件

临时目录中的本地磁盘存储是内存中的文件系统。您写入的文件会占用函数可以使用的内存,并且有时会在多次调用之间持续存在。如果不明确删除这些文件,最终可能会导致内存不足错误,并且随后需要进行冷启动。

要查看具体函数所使用的内存,您可以访问 API 控制台,在函数列表中选择相应的函数,然后选择“内存使用量”图。

请勿试图在临时目录之外执行写入操作,并务必使用独立于平台/操作系统的方法构建文件路径。

要绕过临时文件的大小限制,您可以使用管道。例如,要在 Cloud Storage 上处理文件,您可以创建读取流,通过基于流的进程传递读取流,然后将输出流直接写入 Cloud Storage。

工具

本部分指导您如何使用工具来实现和测试 Cloud Functions 并与之互动。

本地开发

函数部署需要一些时间,因此使用 shim 在本地测试函数的代码通常会更快。

建议您使用 Cloud Functions Node.js Emulator 作为 shim。

使用 Sendgrid 发送电子邮件

Cloud Functions 不允许在端口 25 上建立出站连接,因此您无法建立到 SMTP 服务器的非安全连接。推荐使用 SendGrid 发送电子邮件。您可以在 SendGrid 教程中找到完整的示例,并在 Google Compute Engine 文档从实例发送电子邮件中查看可用于发送电子邮件的其他选项。

性能

本部分介绍性能优化方面的最佳做法。

谨慎使用依赖项

由于函数是无状态的,且执行环境通常是从头开始初始化(称为“冷启动”),因此当发生冷启动时,系统会对函数的全局环境进行评估。

如果您的函数导入了模块,那么在冷启动期间,这些模块的加载时间会造成调用延迟加重。正确加载依赖项而不加载函数不使用的依赖项,即可缩短此延迟时间以及函数部署时间。

使用全局变量,以便在日后的调用中重复使用对象

Cloud Functions 的状态无法保证能保留以备将来调用。不过,Cloud Functions 经常会回收利用先前调用的执行环境。如果您在全局范围内声明一个变量,就可以在后续的调用中再次使用该变量的值,而不必重新计算。

通过这种方式,您可以缓存在每次调用函数时重建的成本较高的对象。将此类对象从函数体移到全局范围可能会显著提升性能。下面的示例会为每个函数实例创建一个重量级对象(每个实例仅限一次),并提供给连接指定实例的所有函数调用共用:

console.log('Global scope');
const perInstance = heavyComputation();
const functions = require('firebase-functions');

exports.function = functions.https.onRequest((req, res) => {
    console.log('Function invocation');
    const perFunction = lightweightComputation();

    res.send(`Per instance: ${perInstance}, per function: ${perFunction}`);
});

尤为重要的是,您应在全局范围内缓存网络连接、库引用和 API 客户端。如需相关示例,请参阅优化网络连接方式

对全局变量进行延迟初始化

如果您在全局范围内初始化变量,就始终会通过冷启动调用执行初始化代码,因而增加函数的延迟时间。如果某些对象并非在所有代码路径中都会用到,可以考虑按需对它们进行延迟初始化:

const functions = require('firebase-functions');
let myCostlyVariable;

exports.function = functions.https.onRequest((req, res) => {
    doUsualWork();
    if(unlikelyCondition()){
        myCostlyVariable = myCostlyVariable || buildCostlyVariable();
    }
    res.status(200).send('OK');
});

如果您在单个文件中定义多个函数,并且不同的函数使用不同的变量,这种做法尤其有用。如果不使用延迟初始化,您可能会因为初始化后永远不会再用到的变量而浪费资源。

发送以下问题的反馈:

此网页
需要帮助?请访问我们的支持页面