Phân phát nội dung đi kèm trên Firestore từ một CDN

Nhiều ứng dụng phân phát cùng một nội dung cho tất cả người dùng trong lượt tải trang đầu tiên. Cho ví dụ: trang web tin tức có thể hiển thị các tin bài mới nhất hoặc trang web thương mại điện tử có thể hiển thị các mặt hàng bán chạy nhất.

Nếu nội dung này được phân phát từ Cloud Firestore, mỗi người dùng sẽ phát hành một để nhận được các kết quả tương tự khi họ tải ứng dụng. Bởi vì kết quả không được lưu vào bộ nhớ đệm giữa những người dùng, ứng dụng sẽ chạy chậm hơn và đắt đỏ hơn mức cần thiết.

Giải pháp: Gói

Các gói Cloud Firestore giúp bạn tập hợp các gói dữ liệu từ những truy vấn thông thường kết quả trên phần phụ trợ bằng cách sử dụng SDK quản trị của Firebase và phân phát blob được tính toán trước được lưu vào bộ nhớ đệm trên CDN. Điều này mang lại cho người dùng tải lần đầu nhanh hơn và giảm chi phí truy vấn trên Cloud Firestore.

Trong hướng dẫn này, chúng ta sẽ sử dụng Cloud Functions để tạo các gói và Dịch vụ Lưu trữ Firebase giúp tự động lưu nội dung vào bộ nhớ đệm và phân phát nội dung gói. Xem thêm thông tin về gói có trong hướng dẫn.

Trước tiên, hãy tạo một chức năng HTTP công khai đơn giản để truy vấn 50 "tin bài" mới nhất và phân phát kết quả dưới dạng một gói.

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

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

Tiếp theo, hãy định cấu hình tính năng Lưu trữ Firebase để phân phát và lưu vào bộ nhớ đệm Chức năng đám mây này bằng cách đang sửa đổi firebase.json. Với cấu hình này, CDN lưu trữ Firebase sẽ phân phối nội dung gói theo cài đặt bộ nhớ đệm do Chức năng đám mây. Khi bộ nhớ đệm hết hạn, bộ nhớ đệm sẽ làm mới nội dung bằng cách kích hoạt hàm lại.

firebase.json
{
  "hosting": {
    // ...
    "rewrites": [{
      "source": "/createBundle",
      "function": "createBundle"
    }]
  },
  // ...
}

Cuối cùng, trong ứng dụng web, hãy tìm nạp nội dung đi kèm từ CDN và tải vào SDK Firestore.

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

Mức tiết kiệm theo ước tính

Giả sử một trang web tin tức có 100.000 người dùng mỗi ngày và mỗi người dùng tải cùng 50 tin bài hàng đầu cho nội dung tải ban đầu. Nếu không lưu vào bộ nhớ đệm, điều này sẽ dẫn đến 50 x 100.000 = 5.000.000 lượt đọc tài liệu mỗi ngày từ Cloud Firestore.

Bây giờ, giả sử trang web áp dụng kỹ thuật trên và lưu 50 kết quả đó vào bộ nhớ đệm lên tới 5 phút. Vì vậy, thay vì tải kết quả truy vấn cho mọi người dùng, kết quả được tải chính xác 12 lần mỗi giờ. Bất kể có bao nhiêu người dùng truy cập tại trang web, số lượng truy vấn tới Cloud Firestore vẫn giữ nguyên. Thay vì 5.000.000 lượt đọc tài liệu, trang này sẽ sử dụng kích thước 12 x 24 x 50 = 14.400 tài liệu số lượt đọc mỗi ngày. Các khoản chi phí bổ sung nhỏ cho tính năng Lưu trữ Firebase và Cloud Functions có thể dễ dàng được bù trừ nhờ việc tiết kiệm chi phí trong Cloud Firestore.

Mặc dù việc tiết kiệm chi phí là lợi ích của nhà phát triển, nhưng người thụ hưởng lớn nhất là người dùng. Tải 50 tài liệu này từ CDN lưu trữ Firebase thay vì trực tiếp từ Cloud Firestore có thể dễ dàng cắt từ 100-200 mili giây trở lên từ thời gian tải nội dung của trang. Các nghiên cứu đã nhiều lần chỉ ra rằng các trang có tốc độ nhanh có nghĩa là người dùng hài lòng hơn.