ফায়ারবেস ক্লাউড ফাংশন খুব ধীর


131

আমরা এমন একটি অ্যাপ্লিকেশন নিয়ে কাজ করছি যা নতুন ফায়ারবেস ক্লাউড ফাংশন ব্যবহার করে। বর্তমানে যা ঘটছে তা হ'ল একটি লেনদেন সারি নোডে রাখা হয়েছে। এবং তারপরে ফাংশনটি সেই নোডটি সরিয়ে সঠিক নোডে রাখে। অফলাইনে কাজ করার দক্ষতার কারণে এটি প্রয়োগ করা হয়েছে।

আমাদের বর্তমান সমস্যাটি হচ্ছে ফাংশনের গতি। ফাংশনটি নিজেই প্রায় 400 মিমি নেয়, তাই ঠিক আছে। তবে কখনও কখনও ফাংশনগুলি খুব দীর্ঘ সময় নেয় (প্রায় 8 সেকেন্ড), যখন ইতিমধ্যে কাতারে প্রবেশিকা যুক্ত করা হয়েছিল।

আমাদের সন্দেহ হয় যে সার্ভারটি বুট আপ করতে সময় নেয়, কারণ যখন আমরা প্রথমটির পরে আরও একবার ক্রিয়া করি। সময় কম লাগে takes

এই সমস্যা সমাধানের জন্য কোনো উপায় আছে কি? এখানে নীচে আমি আমাদের ফাংশন কোড যুক্ত। আমরা সন্দেহ করি এর সাথে কোনও ভুল নেই, তবে আমরা কেবল এটি ক্ষেত্রে যুক্ত করেছি।

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;
}

উপরের প্রতিশ্রুতি 'একবার ()' কল না ফিরিয়ে দেওয়া কি নিরাপদ?
জাজগিল

উত্তর:


111

ফায়ারব্যাসার এখানে

দেখে মনে হচ্ছে আপনি ফাংশনটির একটি তথাকথিত ঠান্ডা শুরু করছেন।

যখন আপনার ফাংশনটি কিছু সময়ের মধ্যে কার্যকর করা হয়নি তখন ক্লাউড ফাংশনগুলি এটিকে এমন একটি মোডে রাখে যা কম সংস্থান ব্যবহার করে। তারপরে আপনি যখন আবার ফাংশনটি হিট করবেন তখন এটি এই মোড থেকে পরিবেশটিকে পুনরুদ্ধার করে। পুনরুদ্ধার করতে যে সময় লাগে তার মধ্যে একটি নির্দিষ্ট ব্যয় (যেমন ধারকটি পুনরুদ্ধার করুন) এবং একটি অংশ পরিবর্তনশীল ব্যয় (যেমন আপনি যদি নোড মডিউলগুলি ব্যবহার করেন তবে এটি আরও বেশি সময় নিতে পারে)।

বিকাশকারীদের অভিজ্ঞতা এবং সংস্থান ব্যবহারের মধ্যে সেরা মিশ্রণটি নিশ্চিত করতে আমরা ক্রমাগত এই ক্রিয়াকলাপগুলির পারফরম্যান্স পর্যবেক্ষণ করছি। তাই সময়ের সাথে সাথে এই সময়ের উন্নতি আশা করি।

সুসংবাদটি হ'ল উন্নয়নের সময় আপনার কেবল এটির অভিজ্ঞতা হওয়া উচিত। আপনার ফাংশনগুলি প্রায়শই উত্পাদনে ট্রিগার হওয়ার পরে, সম্ভবত তারা আবার কখনও কোনও ঠান্ডা শুরু করতে পারে।


3
মডারেটর দ্রষ্টব্য : এই পোস্টে সমস্ত অফ টপিক মন্তব্যগুলি সরানো হয়েছে। স্পষ্টতার অনুরোধ করতে বা শুধুমাত্র উন্নতির পরামর্শ দেওয়ার জন্য মন্তব্যগুলি ব্যবহার করুন। আপনার যদি সম্পর্কিত তবে ভিন্ন প্রশ্ন থাকে তবে একটি নতুন প্রশ্ন জিজ্ঞাসা করুন এবং প্রসঙ্গটি সরবরাহ করতে সহায়তা করার জন্য এটির একটি লিঙ্ক অন্তর্ভুক্ত করুন।
Bhargav রাও

55

আপডেট মে 2020 ম্যাগানাপের মন্তব্যের জন্য ধন্যবাদ - নোডে 10+ FUNCTION_NAMEপ্রতিস্থাপন করা হয়েছে K_SERVICE( FUNCTION_TARGETএটি ফাংশনটি নিজেই হয়, এটি নাম নয়, প্রতিস্থাপন করা হয় ENTRY_POINT)। নীচের কোড নমুনাগুলি নীচে udpated হয়েছে।

Https://cloud.google.com/funitions/docs/migrating/nodejs-runtimes#nodejs-10- পরিবর্তন এ আরও তথ্য

আপডেট - দেখে মনে হচ্ছে অনেকগুলি সমস্যা process.env.FUNCTION_NAMEএখানে লুকানো ভেরিয়েবল ব্যবহার করে সমাধান করা যেতে পারে : https://github.com/firebase/function-sams/issues/170#issuecomment-323375462

কোড সহ আপডেট করুন - উদাহরণস্বরূপ, আপনার যদি নিম্নলিখিত সূচী ফাইল থাকে:

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

তারপরে আপনার সমস্ত ফাইল লোড হবে এবং সেই ফাইলগুলির সমস্ত প্রয়োজনীয়তাও লোড হবে, যার ফলে প্রচুর ওভারহেড হবে এবং আপনার সমস্ত কার্যের জন্য আপনার বৈশ্বিক সুযোগকে দূষিত করবে।

পরিবর্তে আপনার অন্তর্ভুক্ত পৃথক পৃথক:

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

এটি কেবলমাত্র প্রয়োজনীয় ফাইল (গুলি) লোড করবে যখন সেই ফাংশনটি বিশেষভাবে বলা হয়; আপনাকে আপনার বিশ্বব্যাপী সুযোগকে আরও পরিচ্ছন্ন রাখতে দেয় যার ফলস্বরূপ দ্রুত ঠাণ্ডা-বুট হওয়া উচিত।


এটি নীচে যা করেছি তার থেকে অনেক বেশি সুগন্ধযুক্ত সমাধানের অনুমতি দেওয়া উচিত (যদিও নীচের ব্যাখ্যাটি এখনও ধারণ করে)।


আসল উত্তর

দেখে মনে হচ্ছে যে বিশ্বব্যাপী স্কোপগুলিতে ফাইলগুলির প্রয়োজনীয়তা এবং সাধারণ সূচনাটি হ'ল কোল্ড-বুটের সময় ধীর গতির একটি বিশাল কারণ।

প্রকল্প যেমন আরও কার্যকারিতা লাভ করে বিশ্বব্যাপী সুযোগটি দূষিত হয় আরও বেশি করে সমস্যাটিকে আরও খারাপ করে তোলে - বিশেষত যদি আপনি নিজের ফাংশনগুলিকে পৃথক ফাইলগুলিতে স্কোপ করেন (যেমন Object.assign(exports, require('./more-functions.js'));আপনার মধ্যে ব্যবহার করে) index.js

আমি আমার সমস্ত প্রয়োজনীয়তা নীচে হিসাবে একটি ডিআইডি পদ্ধতিতে স্থানান্তরিত করে এবং তারপরে এটিকে ফাইলের কোনও ফাংশন সংজ্ঞায়নের মধ্যে প্রথম লাইন হিসাবে কল করে কোল্ড-বুট পারফরম্যান্সে বিশাল লাভ দেখতে সক্ষম হয়েছি। উদাহরণ:

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-3- তে উন্নতি দেখেছি। এটি ফাংশনগুলি কম শীতল-বুট করা প্রয়োজন বলে মনে হয় (সম্ভবত কম স্মৃতি ব্যবহারের কারণে?)

দুর্ভাগ্যক্রমে এটি এখনও HTTP ফাংশনগুলি ব্যবহারকারীর মুখোমুখি উত্পাদন ব্যবহারের জন্য সবেমাত্র ব্যবহারযোগ্য করে তোলে।

ফায়ারবেস টিমের প্রত্যাশায় ভবিষ্যতে ফাংশনগুলির সঠিক স্কোপিংয়ের মঞ্জুরি দেওয়ার জন্য কিছু পরিকল্পনা রয়েছে যাতে প্রতিটি ফাংশনের জন্য কেবলমাত্র প্রাসঙ্গিক মডিউলগুলি লোড করা প্রয়োজন।


আরে টাইরিস, সময় ক্রিয়াকলাপের সাথে আমি একই সমস্যার মুখোমুখি হয়েছি, আমি আপনার সমাধানটি বাস্তবায়নের চেষ্টা করছি। শুধু বোঝার চেষ্টা করছি, আরম্ভ করার জন্য কাকে ডাকা ফাংশন এবং কখন?
মনসফফ

হাই @ অ্যাডিরজোয়ারি, আমার আর ডি () ব্যবহারের ব্যাখ্যা এবং আরও কিছু সম্ভবত সম্ভবত সেরা অনুশীলন নয়; এর মানটি মূল সমস্যাটি সম্পর্কে আমার অনুসন্ধানগুলি প্রদর্শন করা। আপনি লুকানো ভেরিয়েবলটি দেখে process.env.FUNCTION_NAMEএবং ফাংশনটির জন্য প্রয়োজনীয় ফাইলগুলি শর্তসাপেক্ষে অন্তর্ভুক্ত করার জন্য এটি ব্যবহার করা থেকে অনেক ভাল । Github.com/firebase/function-sams/issues/… এ মন্তব্য এই কাজের সত্যই একটি ভাল বর্ণনা দেয়! এটি নিশ্চিত করে যে বৈশ্বিক সুযোগগুলি পদ্ধতিগুলি দ্বারা দূষিত নয় এবং অপ্রাসঙ্গিক কার্যাবলী থেকে অন্তর্ভুক্ত রয়েছে।
টাইরিস

1
হাই @ ডেভিডওয়ারইয়েজ, আমি মনে করি না যে এটি আপনার ক্রিয়াকলাপ দু'বার বা সমান্তরালভাবে চলার সম্ভাবনার ক্ষেত্রে সহায়তা করবে। প্রয়োজন হিসাবে ফাংশন অটো স্কেল যাতে একাধিক ফাংশন (একই ফাংশন, বা বিভিন্নগুলি) যে কোনও সময়ে সমান্তরালে চলতে পারে। এর অর্থ আপনাকে ডেটা সুরক্ষা বিবেচনা করতে হবে এবং লেনদেনগুলি ব্যবহার করার বিষয়ে বিবেচনা করতে হবে। : এছাড়াও, সম্ভবত চলমান আপনার ফাংশন উপর এই নিবন্ধটি দেখুন দুইবার cloud.google.com/blog/products/serverless/...
Tyris

1
লক্ষ্য করুন FUNCTIONS_NAME: এখানে ব্যাখ্যা, নোড 6 এবং 8 একমাত্র বৈধ cloud.google.com/functions/docs/... । নোড 10 ব্যবহার করা উচিতFUNCTION_TARGET
মগনাপ

1
@ ম্যাগানাপ আপডেটের জন্য ধন্যবাদ, দেখে মনে হচ্ছে এটি K_SERVICEডকো অনুসারে ক্লাউড. google.com/funitions/docs/migrating/… এ ব্যবহার করা উচিত - আমি আমার উত্তর আপডেট করেছি।
টায়রিস

7

আমি ফায়ার স্টোর ক্লাউড ফাংশনগুলির সাথে একই রকম সমস্যার মুখোমুখি। সবচেয়ে বড় পারফরম্যান্স। বিশেষত প্রাথমিক পর্যায়ে স্টার্টআপগুলির ক্ষেত্রে, যখন আপনি আপনার আদি গ্রাহকদের "আলস্য" অ্যাপ্লিকেশনগুলি দেখার সামর্থ্য না করেন। উদাহরণস্বরূপ একটি সাধারণ ডকুমেন্টেশন জেনারেশন ফাংশন এটি দেয়:

- কার্য সম্পাদন 9522 এমএস নিয়েছে, স্থিতি কোড দিয়ে শেষ হয়েছে: 200

তারপরে: আমার একটি সোজা শর্তাবলী পৃষ্ঠা ছিল। মেঘের ক্রিয়াকলাপগুলির সাথে শীতকালীন শুরুর কারণে কার্যকর হওয়া এমনকি সময়ে সময়ে 10-15 সেকেন্ড সময় নিতে পারে। তারপরে আমি এটিকে অ্যাপেনজিন ধারকটিতে হোস্ট করা নোড.জেএস অ্যাপে সরিয়ে নিয়েছি। সময় নেমে এসেছে ২-৩ সেকেন্ডে।

আমি ফায়ার স্টোরের সাথে মঙ্গডবের অনেকগুলি বৈশিষ্ট্য তুলনা করে চলেছি এবং মাঝে মাঝে আমিও ভাবছি যে আমার পণ্যটির এই প্রাথমিক পর্যায়ে আমারও অন্য একটি ডাটাবেসে স্থানান্তরিত হওয়া উচিত। ফায়ার স্টোরে আমার কাছে সবচেয়ে বড় পরামর্শটি হ'ল ডকুমেন্ট অবজেক্টগুলির অনক্রিট, ট্রিপ কার্যকারিতা।

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

মূলত যদি আপনার সাইটের স্থিতিশীল অংশ থাকে তবে এটি অ্যাপেনজিন এনভায়রনমেন্টে লোড করা যায়, এটি সম্ভবত খারাপ ধারণা নয়।


1
আমি মনে করি না যে ফায়ারবেস ফাংশনগুলি গতিশীল ব্যবহারকারীর মুখোমুখি সামগ্রী হিসাবে প্রদর্শিত হবে purpose পাসওয়ার্ড পুনরায় সেট করার মতো জিনিসের জন্য আমরা কয়েকটি HTTP ফাংশন অল্প পরিমাণে ব্যবহার করি তবে সাধারণভাবে আপনার যদি ডায়নামিক সামগ্রী থাকে তবে এটিকে এক্সপ্রেস অ্যাপ হিসাবে অন্য কোথাও পরিবেশন করুন (বা কোনও ভিন্ন ভাষা ব্যবহার করুন)।
টায়রিস

2

আমি এই জিনিসগুলি পাশাপাশি করেছি, যা কার্য সম্পাদন করার পরে কর্মক্ষমতা উন্নত করে, তবে শীতল শুরুটি আমাকে হত্যা করছে। অন্যান্য সমস্যার মুখোমুখি হ'ল একটি কর্স, কারণ কাজটি পেতে মেঘ ফাংশনে দুটি ট্রিপ লাগে। আমি নিশ্চিত যে আমি এটি ঠিক করতে পারি, যদিও।

আপনার যখন প্রথম দিকে (ডেমো) পর্যায়ে কোনও অ্যাপ থাকে যখন এটি ঘন ঘন ব্যবহার করা হয় না, তখন পারফরম্যান্স দুর্দান্ত হতে পারে না। এটি এমন একটি বিষয় যা বিবেচনা করা উচিত, প্রাথমিক পণ্য হিসাবে আগাম গ্রহণকারীদের সম্ভাব্য গ্রাহক / বিনিয়োগকারীদের সামনে তাদের সেরাটি দেখা উচিত। আমরা প্রযুক্তিটি পছন্দ করতাম তাই আমরা পুরানো চেষ্টা-ও-সত্য ফ্রেমওয়ার্কগুলি থেকে মাইগ্রেশন করেছিলাম, তবে আমাদের অ্যাপ্লিকেশনটি এই মুহুর্তে বেশ স্বচ্ছল বলে মনে হচ্ছে। এটিকে আরও ভাল দেখানোর জন্য আমি কয়েকটি ওয়ার্ম-আপ কৌশল চেষ্টা করতে যাচ্ছি


আমরা প্রতিটি একক ক্রিয়াকলাপটি জাগিয়ে তুলতে ক্রোন-জব পরীক্ষা করছি। সম্ভবত এই পদ্ধতির আপনাকে খুব সাহায্য করে।
জেসেস ফুয়েন্তেস

আরে @ জেসেসফুয়েন্টেস আমি কেবল ভাবছিলাম যে ফাংশন জাগানো আপনার পক্ষে কাজ করে। উন্মাদ সমাধানের মতো শোনাচ্ছে: ডি
আলেকজান্ডার জাভালি

1
হাই @ আলেকজান্দ্র, দুঃখের বিষয় আমাদের কাছে এখনও এটি করার সময় নেই, তবে এটি আমাদের শীর্ষ অগ্রাধিকার তালিকায় রয়েছে। যদিও এটি তাত্ত্বিকভাবে কাজ করা উচিত। সমস্যাটি অনকেল ফাংশনগুলির সাথে আসে, যা ফায়ারবেস অ্যাপ থেকে চালু করা প্রয়োজন। প্রতি মিনিটে ক্লায়েন্টের কাছ থেকে তাদের কল করতে পারে? আমরা দেখব.
জেসেস ফুয়েন্তেস

1
@ আলেকজান্ডার স্ট্যাকওভারফ্লো এর বাইরে আমাদের কি কথোপকথন হবে? আমরা একে অপরকে নতুন পদ্ধতির সাহায্য করতে পারি।
জেসেস ফুয়েন্তেস

1
@ আলেকজান্ডার আমরা এখনও এই 'জাগো' কার্যক্রমের পরীক্ষা করিনি তবে আমরা ইতিমধ্যে আমাদের ফাংশনগুলি ইউরোপ-ওয়েস্ট 1 তে স্থাপন করেছি। তবুও, অগ্রহণযোগ্য সময়।
জেসেস ফুয়েন্তে

0

আপডেট / সম্পাদনা: নতুন সিনট্যাক্স এবং আপডেটগুলি আসছে MAY2020

আমি কেবল একটি প্যাকেজ নামে পরিচিত প্রকাশ করেছি better-firebase-functions, এটি স্বয়ংক্রিয়ভাবে আপনার ফাংশন ডিরেক্টরিটি অনুসন্ধান করে এবং আপনার রফতানির অবজেক্টের সমস্ত পাওয়া ফাংশনকে সঠিকভাবে বাসা বেঁধে রাখে, যখন শীতল-বুট কার্যকারিতা উন্নত করার জন্য একে অপরের থেকে ফাংশনগুলি পৃথক করে দেয়।

যদি আপনি অলস-লোড করেন এবং মডিউল স্কোপের মধ্যে প্রতিটি ক্রিয়াকলাপের জন্য আপনার প্রয়োজনীয় নির্ভরতাগুলি ক্যাশে করেন তবে আপনি দ্রুত বর্ধমান প্রকল্পের জন্য আপনার কার্যগুলি সর্বোত্তমভাবে দক্ষ রাখার সবচেয়ে সহজ এবং সহজ উপায় খুঁজে পাবেন।

import { exportFunctions } from 'better-firebase-functions'
exportFunctions({__filename, exports})

আকর্ষণীয় .. আমি কোথায় 'ভাল-ফায়ারবেস-ফাংশন' এর রেপো দেখতে পাব?
জেরিওয়েল

1
github.com/gramstr/better-firebase-funifications - দয়া করে এটি পরীক্ষা করে দেখুন এবং আপনার কী মনে হচ্ছে তা আমাকে জানান! পাশাপাশি অবদান রাখতে নির্দ্বিধায় :)
জর্জ 43g
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.