热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Firebase云功能非常慢

如何解决《Firebase云功能非常慢》经验,为你挑选了3个好方法。

我们正在开发一个使用新的firebase云功能的应用程序.目前正在发生的事情是将事务放入队列节点.然后该函数删除该节点并将其放入正确的节点.由于能够脱机工作,因此已实施.

我们目前的问题是功能的速度.该功能本身需要大约400毫秒,所以没关系.但有时功能需要很长时间(大约8秒),而条目已经添加到队列中.

我们怀疑服务器需要时间来启动,因为当我们在第一次执行后再次执行操作时.它花费的时间更少.

有什么方法可以解决这个问题吗?在这里,我添加了我们的功能代码.我们怀疑它没有任何问题,但我们添加它以防万一.

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

exports.insertTransaction = functions.database
    .ref('/userPlacePromotionTransactionsQueue/{userKey}/{placeKey}/{promotionKey}/{transactionKey}')
    .onWrite(event => {
        if (event.data.val() == null) return null;

        // get keys
        const userKey = event.params.userKey;
        const placeKey = event.params.placeKey;
        const promotiOnKey= event.params.promotionKey;
        const transactiOnKey= event.params.transactionKey;

        // init update object
        const data = {};

        // get the transaction
        const transaction = event.data.val();

        // transfer transaction
        saveTransaction(data, transaction, userKey, placeKey, promotionKey, transactionKey);
        // remove from queue
        data[`/userPlacePromotionTransactionsQueue/${userKey}/${placeKey}/${promotionKey}/${transactionKey}`] = null;

        // fetch promotion
        database.ref(`promotions/${promotionKey}`).once('value', (snapshot) => {
            // Check if the promotion exists.
            if (!snapshot.exists()) {
                return null;
            }

            const promotion = snapshot.val();

            // fetch the current stamp count
            database.ref(`userPromotionStampCount/${userKey}/${promotionKey}`).once('value', (snapshot) => {
                let currentStampCount = 0;
                if (snapshot.exists()) currentStampCount = parseInt(snapshot.val());

                data[`userPromotionStampCount/${userKey}/${promotionKey}`] = currentStampCount + transaction.amount;

                // determines if there are new full cards
                const currentFullcards = Math.floor(currentStampCount > 0 ? currentStampCount / promotion.stamps : 0);
                const newStamps = currentStampCount + transaction.amount;
                const newFullcards = Math.floor(newStamps / promotion.stamps);

                if (newFullcards > currentFullcards) {
                    for (let i = 0; i <(newFullcards - currentFullcards); i++) {
                        const cardTransaction = {
                            action: "pending",
                            promotion_id: promotionKey,
                            user_id: userKey,
                            amount: 0,
                            type: "stamp",
                            date: transaction.date,
                            is_reversed: false
                        };

                        saveTransaction(data, cardTransaction, userKey, placeKey, promotionKey);

                        const completedPromotion = {
                            promotion_id: promotionKey,
                            user_id: userKey,
                            has_used: false,
                            date: admin.database.ServerValue.TIMESTAMP
                        };

                        const promotiOnPushKey= database
                            .ref()
                            .child(`userPlaceCompletedPromotions/${userKey}/${placeKey}`)
                            .push()
                            .key;

                        data[`userPlaceCompletedPromotions/${userKey}/${placeKey}/${promotionPushKey}`] = completedPromotion;
                        data[`userCompletedPromotions/${userKey}/${promotionPushKey}`] = completedPromotion;
                    }
                }

                return database.ref().update(data);
            }, (error) => {
                // Log to the console if an error happened.
                console.log('The read failed: ' + error.code);
                return null;
            });

        }, (error) => {
            // Log to the console if an error happened.
            console.log('The read failed: ' + error.code);
            return null;
        });
    });

function saveTransaction(data, transaction, userKey, placeKey, promotionKey, transactionKey) {
    if (!transactionKey) {
        transactiOnKey= database.ref('transactions').push().key;
    }

    data[`transactions/${transactionKey}`] = transaction;
    data[`placeTransactions/${placeKey}/${transactionKey}`] = transaction;
    data[`userPlacePromotionTransactions/${userKey}/${placeKey}/${promotionKey}/${transactionKey}`] = transaction;
}

Frank van Pu.. 92

这里有一个firebaser

听起来你正在经历一个所谓的冷启动功能.

当您的功能在一段时间内未执行时,Cloud Functions会将其置于使用较少资源的模式中.然后,当您再次点击该功能时,它将从此模式恢复环境.恢复所需的时间包括固定成本(例如恢复容器)和部分可变成本(例如,如果使用大量节点模块,则可能需要更长时间).

我们不断监控这些操作的性能,以确保开发人员体验和资源使用之间的最佳组合.所以期望这些时间随着时间的推移而改善

好消息是你应该只在开发过程中体验这一点.一旦你的功能在生产中经常被触发,很可能它们再也不会出现冷启动.



1> Frank van Pu..:

这里有一个firebaser

听起来你正在经历一个所谓的冷启动功能.

当您的功能在一段时间内未执行时,Cloud Functions会将其置于使用较少资源的模式中.然后,当您再次点击该功能时,它将从此模式恢复环境.恢复所需的时间包括固定成本(例如恢复容器)和部分可变成本(例如,如果使用大量节点模块,则可能需要更长时间).

我们不断监控这些操作的性能,以确保开发人员体验和资源使用之间的最佳组合.所以期望这些时间随着时间的推移而改善

好消息是你应该只在开发过程中体验这一点.一旦你的功能在生产中经常被触发,很可能它们再也不会出现冷启动.



2> Tyris..:

更新 - 看起来很多这些问题可以使用隐藏变量解决,process.env.FUNCTION_NAME如下所示:https://github.com/firebase/functions-samples/issues/170#issuecomment-323375462

使用代码更新 - 例如,如果您有以下索引文件:

...
exports.doSomeThing = require('./doSomeThing');
exports.doSomeThingElse = require('./doSomeThingElse');
exports.doOtherStuff = require('./doOtherStuff');
// and more.......

然后将加载所有文件,并且还将加载所有这些文件的要求,从而导致大量开销并污染所有功能的全局范围.

而是将您的包括分开:

if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === 'doSomeThing') {
  exports.doSomeThing = require('./doSomeThing');
}
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === 'doSomeThingElse') {
  exports. doSomeThingElse = require('./doSomeThingElse');
}
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === 'doOtherStuff') {
  exports. doOtherStuff = require('./doOtherStuff');
}

这只会在专门调用该函数时加载所需的文件; 让您的全球范围更加清洁,从而加快冷靴的速度.


这应该允许比我在下面做的更简洁的解决方案(尽管下面的解释仍然有效).


原始答案

看起来需要文件和在全局范围内发生的一般初始化是冷启动期间减速的一个重要原因.

随着项目获得更多功能,全局范围受到越来越多的污染,使问题变得更糟 - 特别是如果您将功能范围限定在单独的文件中(例如Object.assign(exports, require('./more-functions.js'));在您的文件中使用)index.js.

通过将所有需求转移到如下所示的init方法,然后将其作为该文件的任何函数定义中的第一行,我已经设法看到冷启动性能的巨大收益.例如:

const functiOns= require('firebase-functions');
const admin = require('firebase-admin');
// Late initialisers for performance
let initialised = false;
let handlebars;
let fs;
let path;
let encrypt;

function init() {
  if (initialised) { return; }

  handlebars = require('handlebars');
  fs = require('fs');
  path = require('path');
  ({ encrypt } = require('../common'));
  // Maybe do some handlebars compilation here too

  initialised = true;
}

当我将这种技术应用到一个包含8个文件的~30个函数的项目时,我已经看到从大约7-8s到2-3s的改进.这似乎也导致函数需要不经常冷启动(可能是由于较低的内存使用量?)

不幸的是,这仍然使HTTP功能几乎不能用于面向用户的生产用途.

希望Firebase团队将来有一些计划允许适当的功能范围,以便只需要为每个功能加载相关模块.



3> Mr.hands-on..:

我面临着与firestore云功能类似的问题.最大的是性能.特别是在早期创业公司的情况下,当你无法让早期客户看到"呆滞"的应用程序时.一个简单的文档生成功能,例如给出:

- 函数执行花了9522毫秒,完成状态代码:200

然后:我有一个直截了当的条款和条件页面.使用云功能,由于冷启动执行甚至有时需要10-15秒.然后我将它移动到一个node.js应用程序,托管在appengine容器上.时间已经缩短到2-3秒.

我一直在比较mongodb的许多功能和firestore,有时我也想知道在我的产品的早期阶段我是否也应该转移到另一个数据库.我在firestore中最大的优点是onCreate的触发器功能,onUpdate文件对象.

https://db-engines.com/en/system/Google+Cloud+Firestore%3BMongoDB

基本上,如果您的网站的静态部分可以卸载到appengine环境,也许不是一个坏主意.


推荐阅读
  • MongoDB用户验证auth的权限设置及角色说明
    本文介绍了MongoDB用户验证auth的权限设置,包括readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase、cluster相关的权限以及root权限等角色的说明和使用方法。 ... [详细]
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • 使用nodejs爬取b站番剧数据,计算最佳追番推荐
    本文介绍了如何使用nodejs爬取b站番剧数据,并通过计算得出最佳追番推荐。通过调用相关接口获取番剧数据和评分数据,以及使用相应的算法进行计算。该方法可以帮助用户找到适合自己的番剧进行观看。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Oracle Database 10g许可授予信息及高级功能详解
    本文介绍了Oracle Database 10g许可授予信息及其中的高级功能,包括数据库优化数据包、SQL访问指导、SQL优化指导、SQL优化集和重组对象。同时提供了详细说明,指导用户在Oracle Database 10g中如何使用这些功能。 ... [详细]
  • Oracle10g备份导入的方法及注意事项
    本文介绍了使用Oracle10g进行备份导入的方法及相关注意事项,同时还介绍了2019年独角兽企业重金招聘Python工程师的标准。内容包括导出exp命令、删用户、创建数据库、授权等操作,以及导入imp命令的使用。详细介绍了导入时的参数设置,如full、ignore、buffer、commit、feedback等。转载来源于https://my.oschina.net/u/1767754/blog/377593。 ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • 本文记录了在vue cli 3.x中移除console的一些采坑经验,通过使用uglifyjs-webpack-plugin插件,在vue.config.js中进行相关配置,包括设置minimizer、UglifyJsPlugin和compress等参数,最终成功移除了console。同时,还包括了一些可能出现的报错情况和解决方法。 ... [详细]
  • MySQL中的MVVC多版本并发控制机制的应用及实现
    本文介绍了MySQL中MVCC的应用及实现机制。MVCC是一种提高并发性能的技术,通过对事务内读取的内存进行处理,避免写操作堵塞读操作的并发问题。与其他数据库系统的MVCC实现机制不尽相同,MySQL的MVCC是在undolog中实现的。通过undolog可以找回数据的历史版本,提供给用户读取或在回滚时覆盖数据页上的数据。MySQL的大多数事务型存储引擎都实现了MVCC,但各自的实现机制有所不同。 ... [详细]
  • 本文介绍了在使用Laravel和sqlsrv连接到SQL Server 2016时,如何在插入查询中使用输出子句,并返回所需的值。同时讨论了使用CreatedOn字段返回最近创建的行的解决方法以及使用Eloquent模型创建后,值正确插入数据库但没有返回uniqueidentifier字段的问题。最后给出了一个示例代码。 ... [详细]
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
  • Android日历提醒软件开源项目分享及使用教程
    本文介绍了一款名为Android日历提醒软件的开源项目,作者分享了该项目的代码和使用教程,并提供了GitHub项目地址。文章详细介绍了该软件的主界面风格、日程信息的分类查看功能,以及添加日程提醒和查看详情的界面。同时,作者还提醒了读者在使用过程中可能遇到的Android6.0权限问题,并提供了解决方法。 ... [详细]
  • Python操作MySQL(pymysql模块)详解及示例代码
    本文介绍了使用Python操作MySQL数据库的方法,详细讲解了pymysql模块的安装和连接MySQL数据库的步骤,并提供了示例代码。内容涵盖了创建表、插入数据、查询数据等操作,帮助读者快速掌握Python操作MySQL的技巧。 ... [详细]
  • node.jsrequire和ES6导入导出的区别原 ... [详细]
author-avatar
张兵在江湖
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有