새로운 Firebase 클라우드 기능을 사용하는 애플리케이션을 개발 중입니다. 현재 일어나고있는 것은 트랜잭션이 큐 노드에 배치된다는 것입니다. 그런 다음 함수는 해당 노드를 제거하고 올바른 노드에 넣습니다. 이것은 오프라인으로 작업 할 수 있기 때문에 구현되었습니다.
현재 문제는 함수의 속도입니다. 함수 자체는 약 400ms가 걸리므로 괜찮습니다. 그러나 항목이 이미 대기열에 추가 된 동안 함수에 매우 긴 시간 (약 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;
}
답변
여기 firebaser
소위 콜드 스타트 기능을 경험 한 것 같습니다.
함수가 한동안 실행되지 않으면 Cloud Functions는 더 적은 리소스를 사용하는 모드로 전환합니다. 그런 다음 기능을 다시 누르면이 모드에서 환경이 복원됩니다. 복원에 걸리는 시간은 고정 비용 (예 : 컨테이너 복원)과 부분 가변 비용 (예 : 많은 노드 모듈을 사용하는 경우 더 오래 걸릴 수 있음)으로 구성됩니다.
우리는 개발자 경험과 리소스 사용 간의 최상의 혼합을 보장하기 위해 이러한 작업의 성능을 지속적으로 모니터링하고 있습니다. 따라서이 시간이 시간이 지남에 따라 개선 될 것으로 기대하십시오.
좋은 소식은 개발 중에 만 이것을 경험해야한다는 것입니다. 기능이 프로덕션에서 자주 트리거되면 다시 콜드 스타트를 할 가능성이 거의 없습니다.
답변
2020 년 5 월 업데이트 maganap의 의견을 보내 주셔서 감사합니다-Node 10+ FUNCTION_NAME
에서 K_SERVICE
( FUNCTION_TARGET
은 함수 자체가 이름이 아니라ENTRY_POINT
입니다.). 아래 코드 샘플은 아래에 업데이트되었습니다.
https://cloud.google.com/functions/docs/migrating/nodejs-runtimes#nodejs-10-changes 에서 자세한 정보
업데이트 -https process.env.FUNCTION_NAME
: //github.com/firebase/functions-samples/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
.
필자는 모든 요구 사항을 아래와 같이 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-8 초에서 2-3 초로 개선 된 것을 보았습니다. 이로 인해 함수가 콜드 부팅되는 빈도가 줄어드는 것 같습니다 (아마도 메모리 사용량이 적기 때문일까요?).
불행히도 이것은 여전히 HTTP 기능을 사용자가 직면하는 프로덕션 용도로 거의 사용할 수 없게 만듭니다.
Firebase 팀이 향후 적절한 기능 범위 지정을 허용하여 각 기능에 대해 관련 모듈 만로드하면되는 몇 가지 계획이 있기를 바랍니다.
답변
Firestore 클라우드 기능과 유사한 문제에 직면하고 있습니다. 가장 큰 것은 성능입니다. 특히 초기 고객이 “부진한”앱을 볼 여유가없는 초기 단계의 스타트 업의 경우. 예를 들어 간단한 문서 생성 기능은 다음을 제공합니다.
-함수 실행에 9522ms 소요, 상태 코드 : 200으로 완료
그때 : 나는 전면적 인 이용 약관 페이지를 가지고있었습니다. 클라우드 기능을 사용하면 콜드 스타트로 인한 실행에 때때로 10-15 초가 걸립니다. 그런 다음 appengine 컨테이너에서 호스팅되는 node.js 앱으로 옮겼습니다. 시간이 2-3 초로 단축되었습니다.
나는 mongodb의 많은 기능을 firestore와 비교해 왔으며 때로는 제품의 초기 단계에서 다른 데이터베이스로 이동해야할지 궁금합니다. 내가 firestore에서 가진 가장 큰 진보는 문서 객체의 onCreate, onUpdate 트리거 기능이었습니다.
https://db-engines.com/en/system/Google+Cloud+Firestore%3BMongoDB
기본적으로 앱 엔진 환경으로 오프로드 할 수있는 사이트의 정적 부분이 있다면 좋지 않을 수 있습니다.
답변
기능이 예열되면 성능이 향상되지만 콜드 스타트가 나를 죽이고 있습니다. 내가 만난 다른 문제 중 하나는 cors와 관련된 것입니다. 작업을 완료하려면 클라우드 기능으로 두 번 이동해야하기 때문입니다. 그래도 고칠 수 있다고 확신합니다.
앱을 자주 사용하지 않는 초기 (데모) 단계에 있으면 성능이 좋지 않을 것입니다. 초기 제품을 가진 얼리 어답터는 잠재 고객 / 투자자 앞에서 가장 잘 보일 필요가 있기 때문에 이것은 고려해야 할 사항입니다. 우리는 기술이 마음에 들었 기 때문에 기존의 검증 된 프레임 워크에서 마이그레이션했지만이 시점에서는 앱이 상당히 느려 보입니다. 다음으로 더보기 좋게 만들기 위해 몇 가지 준비 전략을 시도해 보겠습니다.
답변
업데이트 / 편집 : 2020 년 5 월 새로운 구문 및 업데이트 예정
방금이라는 패키지를 게시 better-firebase-functions
했습니다. 자동으로 함수 디렉터리를 검색하고 찾은 모든 함수를 내보내기 개체에 올바르게 중첩하는 동시에 콜드 부팅 성능을 향상시키기 위해 함수를 서로 분리합니다.
모듈 범위 내에서 각 함수에 필요한 종속성 만 지연로드하고 캐시하는 경우 빠르게 성장하는 프로젝트에서 함수를 최적의 상태로 유지하는 가장 간단하고 쉬운 방법입니다.
import { exportFunctions } from 'better-firebase-functions'
exportFunctions({__filename, exports})