بسیاری از برنامه ها محتوای یکسانی را در بارگذاری صفحه اول به همه کاربران ارائه می دهند. به عنوان مثال یک سایت خبری ممکن است آخرین داستان ها را نشان دهد، یا یک سایت تجارت الکترونیک ممکن است موارد پرفروش را نشان دهد.
اگر این محتوا از Cloud Firestore ارائه شود، هر کاربر هنگام بارگیری برنامه، یک درخواست جدید برای نتایج یکسان صادر می کند. از آنجایی که این نتایج بین کاربران ذخیره نمیشوند، برنامه کندتر و گرانتر از آن چیزی است که باید باشد.
راه حل: بسته نرم افزاری
بستههای Cloud Firestore به شما این امکان را میدهند که بستههای داده را از نتایج جستجوی رایج در پشتیبان با استفاده از Firebase Admin SDK جمعآوری کنید و این حبابهای از پیش محاسبهشده را در حافظه پنهان در یک CDN ارائه دهید. این به کاربران شما تجربه بارگیری اولیه بسیار سریعتری را میدهد و هزینههای جستجوی Cloud Firestore شما را کاهش میدهد.
در این راهنما Cloud Functions برای تولید بستهها و Firebase Hosting برای ذخیرهسازی پویا و ارائه محتوای بسته استفاده میکنیم. اطلاعات بیشتر در مورد بسته ها در راهنماها موجود است.
ابتدا یک تابع HTTP عمومی ساده ایجاد کنید تا 50 آخرین "داستان" را پرس و جو کنید و نتیجه را به عنوان یک بسته ارائه کنید.
Node.js
exports.createBundle = functions.https.onRequest(async (request, response) => { // Query the 50 latest stories const latestStories = await db.collection('stories') .orderBy('timestamp', 'desc') .limit(50) .get(); // Build the bundle from the query results const bundleBuffer = db.bundle('latest-stories') .add('latest-stories-query', latestStories) .build(); // Cache the response for up to 5 minutes; // see https://firebase.google.com/docs/hosting/manage-cache response.set('Cache-Control', 'public, max-age=300, s-maxage=600'); response.end(bundleBuffer); });
جاوا
package com.example; import com.google.auth.oauth2.GoogleCredentials; import com.google.cloud.firestore.Firestore; import com.google.cloud.firestore.FirestoreBundle; import com.google.cloud.firestore.Query.Direction; import com.google.cloud.firestore.QuerySnapshot; import com.google.cloud.functions.HttpFunction; import com.google.cloud.functions.HttpRequest; import com.google.cloud.functions.HttpResponse; import com.google.firebase.FirebaseApp; import com.google.firebase.FirebaseOptions; import com.google.firebase.cloud.FirestoreClient; import java.io.BufferedWriter; import java.io.IOException; public class ExampleFunction implements HttpFunction { public static FirebaseApp initializeFirebase() throws IOException { if (FirebaseApp.getApps().isEmpty()) { FirebaseOptions options = FirebaseOptions.builder() .setCredentials(GoogleCredentials.getApplicationDefault()) .setProjectId("YOUR-PROJECT-ID") .build(); FirebaseApp.initializeApp(options); } return FirebaseApp.getInstance(); } @Override public void service(HttpRequest request, HttpResponse response) throws Exception { // Get a Firestore instance FirebaseApp app = initializeFirebase(); Firestore db = FirestoreClient.getFirestore(app); // Query the 50 latest stories QuerySnapshot latestStories = db.collection("stories") .orderBy("timestamp", Direction.DESCENDING) .limit(50) .get() .get(); // Build the bundle from the query results FirestoreBundle bundle = db.bundleBuilder("latest-stores") .add("latest-stories-query", latestStories) .build(); // Cache the response for up to 5 minutes // see https://firebase.google.com/docs/hosting/manage-cache response.appendHeader("Cache-Control", "public, max-age=300, s-maxage=600"); // Write the bundle to the HTTP response BufferedWriter writer = response.getWriter(); writer.write(new String(bundle.toByteBuffer().array())); } }
سپس Firebase Hosting را پیکربندی کنید تا با تغییر firebase.json
این تابع Cloud را ارائه و ذخیره کند. با این پیکربندی، Firebase Hosting CDN محتوای بسته را مطابق تنظیمات حافظه پنهان تنظیم شده توسط Cloud Function ارائه می کند. هنگامی که حافظه پنهان منقضی شود، با فعال کردن مجدد تابع، محتوا را تازه می کند.
firebase.json
{
"hosting": {
// ...
"rewrites": [{
"source": "/createBundle",
"function": "createBundle"
}]
},
// ...
}
در نهایت در برنامه وب خود، محتوای همراه را از CDN واکشی کنید و آن را در Firestore SDK بارگیری کنید.
// If you are using module bundlers.
import firebase from "firebase/app";
import "firebase/firestore";
import "firebase/firestore/bundle" // This line enables bundle loading as a side effect.
async function fetchFromBundle() {
// Fetch the bundle from Firebase Hosting, if the CDN cache is hit the 'X-Cache'
// response header will be set to 'HIT'
const resp = await fetch('/createBundle');
// Load the bundle contents into the Firestore SDK
await db.loadBundle(resp.body);
// Query the results from the cache
// Note: omitting "source: cache" will query the Firestore backend.
const query = await db.namedQuery('latest-stories-query');
const storiesSnap = await query.get({ source: 'cache' });
// Use the results
// ...
}
پس انداز تخمینی
یک وب سایت خبری را در نظر بگیرید که روزانه 100000 کاربر دریافت می کند و هر کاربر همان 50 خبر برتر را در بارگذاری اولیه بارگذاری می کند. بدون هیچ گونه ذخیره سازی، این امر منجر به 50 x 100،000 = 5،000،000 خواندن سند در روز از Cloud Firestore می شود.
حال فرض کنید سایت تکنیک بالا را اتخاذ کرده و آن 50 نتیجه را حداکثر تا 5 دقیقه در حافظه پنهان نگه می دارد. بنابراین به جای بارگیری نتایج پرس و جو برای هر کاربر، نتایج دقیقاً 12 بار در ساعت بارگذاری می شوند. مهم نیست که چند کاربر به سایت وارد می شوند، تعداد پرس و جوها به Cloud Firestore ثابت می ماند. به جای 5,000,000 خواندن سند، این صفحه از 12 x 24 x 50 = 14,400 خواندن سند در روز استفاده می کند. هزینه های اضافی کوچک برای میزبانی Firebase و Cloud Functions به راحتی با صرفه جویی در هزینه Cloud Firestore جبران می شود.
در حالی که توسعه دهنده از صرفه جویی در هزینه سود می برد، بزرگترین ذینفع، کاربر است. بارگیری این 50 سند از CDN میزبانی Firebase به جای مستقیماً از Cloud Firestore می تواند به راحتی 100-200 میلی ثانیه یا بیشتر از زمان بارگذاری محتوای صفحه را حذف کند. مطالعات بارها نشان داده اند که صفحات سریع به معنای کاربران شادتر است.