在多个云功能中最大限度地减少冷启动时间的最佳方法



如下所示;这里有两种不同的方法来运行不同的云函数,如foo.js和bar.js。

在方法#1中,管理、数据库和消息传递模块在index.js中初始化,并作为参数传递给每个相关函数。此外,在方法#2中,这些参数是在每个函数中定义的。

哪种方法适用于在运行每个功能期间最大限度地减少冷启动时间?

方法#1

index.js

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const database = admin.database();
const messaging = admin.messaging();

const fooFunction = require('./foo');
exports.fooFunction = functions.database.ref('/users/messages_inbox').onCreate( (snapshot, context) => { fooFunction.handler(database, messaging, snapshot, context) });
const barFunction = require('./bar');
exports.barFunction = functions.database.ref('/users').onCreate( (snapshot, context) => { barFunction.handler(database, snapshot, context) });

foo.js

exports.handler = (database, messaging, snapshot, context) => {
// some function
}

bar.js

exports.handler = (database, snapshot, context) => {
// some function
}

方法#2

index.js

const functions = require('firebase-functions');
const fooFunction = require('./foo');
exports.fooFunction = functions.database.ref('/users/messages_inbox').onCreate( fooFunction.handler );
const barFunction = require('./bar');
exports.barFunction = functions.database.ref('/users').onCreate( barFunction.handler );

foo.js

exports.handler = (snapshot, context) => {
const admin = require('firebase-admin');
const database = admin.database();
const messaging = admin.messaging();
// some function
}

bar.js

exports.handler = (snapshot, context) => {
const admin = require('firebase-admin');
const database = admin.database();
// some function
}

TL;DR:从冷启动的角度来看;方法2";看起来更有利,因为您(A(避免加载不必要的模块,(B(避免实例化不必要的服务,直到代码中实际需要它们

长答案:

主要有两个方面起作用;方法#2";导致更快的冷启动:

第一个方面是,通过在处理程序中本地使用require语法,而不是使用全局imports,可以有效地避免加载任何不需要的模块。在一个项目中,许多处理程序依赖于完全不同的模块和服务集,这可能会显著提高速度。

除此之外,它还将优化云功能服务器实例的资源使用情况。这是因为当部署您的项目并使用云功能时,firebase将为每个云功能服务器实例运行完整的项目代码。然后,它只使用这个专用服务器实例来运行项目的一个专用云功能。因此,如果您使用import语法(如"方法#1"(,这将导致不必要地包含项目中所有函数的所有导入依赖项,即使它们从来都不需要您通过require仅本地延迟加载模块的方法有效地防止了这种情况,因此理论上加快了冷启动。

";方法#2";除了避免加载不必要的模块(通过require()的帮助(之外,您正在延迟"的实例化;服务";(如admin.database()(,直到您真正需要它们。

从绝对性能的角度来看,最好不要实例化任何服务,直到需要它们,如";方法#2";。因此,如果您的firebase事件处理程序不一定依赖于";数据库";或";消息传送";服务,您可以通过不在全局项目范围内实例化它们来加快速度。当考虑到firebase服务的初始化性能在未来可能会发生变化时,情况尤其如此——它们现在很快,但谁知道呢,在不久的将来,对admin.database()的调用可能会变得计算量更大。这就是为什么最好的做法是假设最坏的情况,并将第三方库视为不受您控制的黑盒,并且在性能方面您不能依赖它。

缺点:

在函数中实例化服务(如"方法#2"中所做的(违背了依赖注入的思想,并使单元测试更加困难,您应该考虑这一点。

此外,通过require()在函数体内有条件地加载JS模块是以可读性和代码可维护性为代价的。此外,它使自动静态代码分析成为一项具有挑战性的任务,并防止像webpack这样的工具进行适当的树分解。这可能看起来很讽刺,但尽管您可能成功地优化了JS代码的初始化时间,但在较低的级别上,增加的捆绑包大小可能会对gcloud容器的剥离产生次优影响,从而影响冷启动时间(请参阅包大小重要吗?(,因为整个项目映像更大,容器实例本身需要更长的时间才能创建。

最后,你应该小心不要对你的项目进行微优化,除非你遇到了性能瓶颈,而是要保持一个可读性好的项目结构。

相关内容

  • 没有找到相关文章

最新更新