محتوای Firestore همراه را از CDN ارائه دهید

بسیاری از برنامه‌ها در صفحه اول بارگذاری، محتوای یکسانی را به همه کاربران ارائه می‌دهند. برای مثال، یک سایت خبری ممکن است آخرین اخبار را نشان دهد، یا یک سایت تجارت الکترونیک ممکن است پرفروش‌ترین اقلام را نمایش دهد.

اگر این محتوا از Cloud Firestore ارائه شود، هر کاربر هنگام بارگذاری برنامه، یک پرس و جوی جدید برای همان نتایج ارسال می‌کند. از آنجا که این نتایج بین کاربران ذخیره نمی‌شوند، برنامه کندتر و گران‌تر از حد لازم است.

راه حل: بسته‌های نرم افزاری

بسته‌های Cloud Firestore به شما این امکان را می‌دهند که بسته‌های داده را از نتایج پرس‌وجوهای رایج در backend با استفاده از Firebase Admin SDK جمع‌آوری کنید و این حباب‌های از پیش محاسبه‌شده را که در یک CDN ذخیره شده‌اند، ارائه دهید. این به کاربران شما تجربه بارگذاری اولیه بسیار سریع‌تری می‌دهد و هزینه‌های پرس‌وجوی Cloud Firestore شما را کاهش می‌دهد.

در این راهنما Cloud Functions برای تولید بسته‌ها (bundles) و Firebase Hosting برای ذخیره‌سازی پویا و ارائه محتوای بسته‌ها (bundles) استفاده خواهیم کرد. اطلاعات بیشتر در مورد بسته‌ها (bundles) در راهنماها موجود است.

ابتدا یک تابع HTTP عمومی ساده ایجاد کنید تا ۵۰ «داستان» آخر را جستجو کند و نتیجه را به عنوان یک بسته ارائه دهد.

نود جی اس
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 پیکربندی کنید. با این پیکربندی، Firebase Hosting CDN محتوای بسته را مطابق با تنظیمات حافظه پنهان تعیین شده توسط تابع ابری ارائه می‌دهد. هنگامی که حافظه پنهان منقضی می‌شود، با فعال کردن مجدد تابع، محتوا را تازه‌سازی می‌کند.

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
  // ...
}

صرفه‌جویی تخمینی

یک وب‌سایت خبری را در نظر بگیرید که روزانه ۱۰۰۰۰۰ کاربر دارد و هر کاربر در بار اول ۵۰ خبر مهم را بارگذاری می‌کند. بدون هیچ گونه ذخیره‌سازی، این منجر به ۵۰ ضربدر ۱۰۰۰۰۰ = ۵۰۰۰۰۰۰ بار خواندن سند در روز از Cloud Firestore می‌شود.

حال فرض کنید سایت از تکنیک بالا استفاده می‌کند و آن ۵۰ نتیجه را تا ۵ دقیقه در حافظه پنهان (cache) ذخیره می‌کند. بنابراین به جای بارگذاری نتایج پرس‌وجو برای هر کاربر، نتایج دقیقاً ۱۲ بار در ساعت بارگذاری می‌شوند. مهم نیست چند کاربر به سایت می‌رسند، تعداد پرس‌وجوها به Cloud Firestore ثابت می‌ماند. به جای ۵،۰۰۰،۰۰۰ خواندن سند، این صفحه از ۱۲ ضربدر ۲۴ ضربدر ۵۰ = ۱۴،۴۰۰ خواندن سند در روز استفاده می‌کند. هزینه‌های اضافی اندک برای میزبانی Firebase و Cloud Functions به راحتی با صرفه‌جویی در هزینه Cloud Firestore جبران می‌شود.

در حالی که توسعه‌دهنده از صرفه‌جویی در هزینه سود می‌برد، بزرگترین ذینفع کاربر است. بارگذاری این ۵۰ سند از CDN میزبانی فایربیس به جای بارگذاری مستقیم از Cloud Firestore می‌تواند به راحتی ۱۰۰ تا ۲۰۰ میلی‌ثانیه یا بیشتر از زمان بارگذاری محتوای صفحه را کاهش دهد. مطالعات بارها نشان داده‌اند که صفحات سریع به معنای کاربران شادتر هستند.