Kami sedang mengerjakan aplikasi yang menggunakan fungsi cloud firebase baru. Apa yang saat ini terjadi adalah transaksi dimasukkan ke dalam node antrian. Dan kemudian fungsi menghapus simpul itu dan meletakkannya di simpul yang benar. Ini telah dilaksanakan karena kemampuan untuk bekerja secara offline.
Masalah kita saat ini adalah kecepatan fungsinya. Fungsinya sendiri membutuhkan waktu sekitar 400ms, jadi tidak apa-apa. Namun terkadang fungsinya memakan waktu sangat lama (sekitar 8 detik), sementara entri sudah ditambahkan ke antrian.
Kami menduga bahwa server membutuhkan waktu untuk boot, karena ketika kami melakukan tindakan sekali lagi setelah yang pertama. Ini membutuhkan waktu lebih sedikit.
Apakah ada cara untuk mengatasi masalah ini? Di sini saya menambahkan kode fungsi kami. Kami curiga tidak ada yang salah dengan itu, tetapi kami menambahkannya untuk berjaga-jaga.
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;
}
sumber
Jawaban:
firebaser di sini
Sepertinya Anda mengalami apa yang disebut cold start dari fungsi tersebut.
Jika fungsi Anda belum dijalankan dalam beberapa waktu, Cloud Functions menempatkannya dalam mode yang menggunakan sumber daya lebih sedikit. Kemudian ketika Anda menekan fungsi itu lagi, itu memulihkan lingkungan dari mode ini. Waktu yang diperlukan untuk memulihkan terdiri dari biaya tetap (mis. Memulihkan kontainer) dan sebagian biaya variabel (mis. Jika Anda menggunakan banyak modul node, mungkin perlu waktu lebih lama).
Kami terus memantau kinerja operasi ini untuk memastikan perpaduan terbaik antara pengalaman pengembang dan penggunaan sumber daya. Jadi, perkirakan waktu-waktu ini akan meningkat seiring waktu.
Kabar baiknya adalah Anda seharusnya hanya mengalami ini selama pengembangan. Setelah fungsi Anda sering dipicu dalam produksi, kemungkinan besar fungsi tersebut tidak akan pernah mengalami start cold lagi.
sumber
Perbarui Mei 2020 Terima kasih atas komentar oleh maganap - di Node 10+
FUNCTION_NAME
diganti denganK_SERVICE
(FUNCTION_TARGET
apakah fungsinya sendiri, bukan namanya, digantiENTRY_POINT
). Contoh kode di bawah ini telah di udpasi di bawah ini.Info selengkapnya di https://cloud.google.com/functions/docs/migrating/nodejs-runtimes#nodejs-10-changes
Pembaruan - sepertinya banyak dari masalah ini dapat diselesaikan menggunakan variabel tersembunyi
process.env.FUNCTION_NAME
seperti yang terlihat di sini: https://github.com/firebase/functions-samples/issues/170#issuecomment-323375462Perbarui dengan kode - Misalnya, jika Anda memiliki file indeks berikut:
Kemudian semua file Anda akan dimuat, dan semua persyaratan file tersebut juga akan dimuat, mengakibatkan banyak overhead dan mencemari cakupan global Anda untuk semua fungsi Anda.
Alih-alih memisahkan penyertaan Anda sebagai:
Ini hanya akan memuat file yang diperlukan ketika fungsi itu secara khusus dipanggil; memungkinkan Anda untuk menjaga cakupan global Anda jauh lebih bersih yang seharusnya menghasilkan cold-boots yang lebih cepat.
Ini seharusnya memungkinkan solusi yang jauh lebih rapi daripada yang saya lakukan di bawah (meskipun penjelasan di bawah masih berlaku).
Jawaban Asli
Sepertinya memerlukan file dan inisialisasi umum yang terjadi dalam lingkup global adalah penyebab besar perlambatan selama cold-boot.
Saat proyek mendapatkan lebih banyak fungsi, cakupan global semakin tercemar sehingga masalah menjadi lebih buruk - terutama jika Anda menskalakan fungsi ke dalam file terpisah (seperti dengan menggunakan
Object.assign(exports, require('./more-functions.js'));
di fileindex.js
.Saya telah berhasil melihat keuntungan besar dalam kinerja boot dingin dengan memindahkan semua kebutuhan saya ke metode init seperti di bawah ini dan kemudian menyebutnya sebagai baris pertama di dalam definisi fungsi apa pun untuk file itu. Misalnya:
Saya telah melihat peningkatan dari sekitar 7-8 ke 2-3 saat menerapkan teknik ini ke proyek dengan ~ 30 fungsi di 8 file. Ini juga tampaknya menyebabkan fungsi perlu di-boot dingin lebih jarang (mungkin karena penggunaan memori yang lebih rendah?)
Sayangnya ini masih membuat fungsi HTTP hampir tidak dapat digunakan untuk penggunaan produksi yang dihadapi pengguna.
Berharap tim Firebase memiliki beberapa rencana di masa mendatang untuk memungkinkan pelingkupan fungsi yang tepat sehingga hanya modul yang relevan yang perlu dimuat untuk setiap fungsi.
sumber
process.env.FUNCTION_NAME
dan menggunakannya untuk menyertakan file yang diperlukan untuk fungsi itu secara bersyarat. Komentar di github.com/firebase/functions-samples/issues/… memberikan deskripsi yang sangat bagus tentang cara kerja ini! Ini memastikan bahwa cakupan global tidak tercemar dengan metode dan termasuk dari fungsi yang tidak relevan.FUNCTIONS_NAME
hanya valid dengan node 6 dan 8, seperti yang dijelaskan di sini: cloud.google.com/functions/docs/… . Node 10 harus digunakanFUNCTION_TARGET
K_SERVICE
sesuai dengan doco di cloud.google.com/functions/docs/migrating/… - Saya telah memperbarui jawaban saya.Saya menghadapi masalah serupa dengan fungsi cloud firestore. Yang terbesar adalah kinerja. Khususnya dalam kasus permulaan tahap awal, ketika Anda tidak mampu memberi pelanggan awal untuk melihat aplikasi yang "lamban". Fungsi pembuatan dokumentasi sederhana misalnya memberikan ini:
- Eksekusi fungsi membutuhkan waktu 9522 ms, selesai dengan kode status: 200
Kemudian: Saya memiliki halaman syarat dan ketentuan yang tegas. Dengan fungsi cloud, eksekusi karena start yang dingin akan memakan waktu 10-15 detik bahkan pada waktu tertentu. Saya kemudian memindahkannya ke aplikasi node.js, dihosting di wadah appengine. Waktunya telah turun menjadi 2-3 detik.
Saya telah membandingkan banyak fitur mongodb dengan firestore dan terkadang saya juga bertanya-tanya apakah selama fase awal produk saya ini, saya juga harus pindah ke database yang berbeda. Adv terbesar yang saya miliki di firestore adalah fungsi pemicu onCreate, onUpdate objek dokumen.
https://db-engines.com/en/system/Google+Cloud+Firestore%3BMongoDB
Pada dasarnya jika ada bagian statis dari situs Anda yang dapat dipindahkan ke lingkungan appengine, mungkin bukan ide yang buruk.
sumber
Saya telah melakukan hal-hal ini juga, yang meningkatkan kinerja setelah fungsinya dihangatkan, tetapi permulaan yang dingin membunuh saya. Salah satu masalah lain yang saya temui adalah dengan cors, karena diperlukan dua perjalanan ke fungsi cloud untuk menyelesaikan pekerjaan. Saya yakin saya bisa memperbaikinya.
Saat Anda memiliki aplikasi dalam fase awal (demo) dan tidak sering digunakan, kinerjanya tidak akan bagus. Ini adalah sesuatu yang harus dipertimbangkan, karena pengadopsi awal dengan produk awal perlu tampil terbaik di depan calon pelanggan / investor. Kami menyukai teknologinya sehingga kami bermigrasi dari kerangka kerja lama yang telah dicoba dan benar, tetapi aplikasi kami tampaknya cukup lamban pada saat ini. Selanjutnya saya akan mencoba beberapa strategi pemanasan agar terlihat lebih baik
sumber
UPDATE / EDIT: sintaks baru dan pembaruan akan datang MAY2020
Saya baru saja menerbitkan sebuah paket bernama
better-firebase-functions
, itu secara otomatis mencari direktori fungsi Anda dan dengan benar menyarangkan semua fungsi yang ditemukan di objek ekspor Anda, sambil mengisolasi fungsi satu sama lain untuk meningkatkan kinerja boot dingin.Jika Anda lazy-load dan cache hanya dependensi yang Anda butuhkan untuk setiap fungsi dalam lingkup modul, Anda akan menemukan bahwa itu adalah cara termudah dan termudah untuk menjaga fungsi Anda tetap efisien secara optimal melalui proyek yang berkembang pesat.
sumber