Cloud Firestore 的最佳做法

建構使用 Cloud Firestore 的應用程式時,您可以快速參考本文章所列的最佳做法。

資料庫位置

建立資料庫執行個體時,請選取最靠近使用者和運算資源的資料庫位置。網路跳躍範圍越廣,發生錯誤的機率就越高,查詢延遲時間也會增加。

如要盡可能提高應用程式可用性和耐用性,請選取多區域位置,並將重要的運算資源放置在至少兩個區域。

選取區域位置可降低成本,如果應用程式對延遲時間較為敏感,則可縮短寫入延遲時間,或是與其他 GCP 資源共置

文件 ID

  • 避免使用文件 ID ...
  • 請勿在文件 ID 中使用 / 斜線。
  • 請勿使用單調遞增的文件 ID,例如:

    • Customer1Customer2Customer3...
    • Product 1Product 2Product 3、...

    這種依序 ID 可能會導致熱點影響延遲時間。

欄位名稱

  • 請避免在欄位名稱中使用以下字元,因為這些字元需要額外逸出:

    • .
    • [ 左方括號
    • ] 右方括號
    • * 星號
    • ` 倒引號

索引

減少寫入延遲時間

造成寫入延遲的主要原因是索引扇形擴散。減少索引擴散的最佳做法如下:

  • 設定集合層級索引豁免。預設的簡單做法是停用「遞減」和「陣列索引」。移除未使用的索引值也會降低儲存空間費用

  • 減少交易中的文件數量。如要寫入大量文件,請考慮使用大量寫入器,而非原子批次寫入器。

索引豁免項目

大多數應用程式都可以仰賴自動索引和錯誤訊息連結來管理索引。不過,在下列情況下,您可能需要新增單一欄位豁免條款

案件 說明
大型字串欄位

如果有字串欄位經常包含不用於查詢的長字串值,則可將該欄位排除在索引範圍之外,藉此節省儲存空間費用。

寫入含有序列值的集合速度過快

如果您為集合中的文件建立索引,以便在這些文件之間以序列方式增加或減少欄位 (例如時間戳記),則集合的寫入頻率上限為每秒 500 次。如果您不依據含有序列值的欄位進行查詢,可以將該欄位排除在索引之外,以便略過這項限制。

舉例來說,在寫入頻率高的 IoT 用途中,包含有時間戳記欄位的文件集合可能會接近每秒 500 次寫入的限制。

存留時間欄位

如果您使用TTL (存留時間) 政策,請注意 TTL 欄位必須是時間戳記。系統預設會為 TTL 欄位啟用索引功能,這可能會影響高流量率的效能。最佳做法是為 TTL 欄位新增單一欄位豁免項目。

大型陣列或對應關係欄位

大型陣列或對應欄位可能會接近每個文件 40,000 個索引項目的上限。如果您不是根據大型陣列或對應欄位進行查詢,請將該欄位從索引中排除。

讀取和寫入作業

  • 應用程式更新單一文件的確切最大速率,很大程度上取決於工作負載。詳情請參閱「更新單一文件」。

  • 盡可能以非同步呼叫取代同步呼叫。非同步呼叫可以盡可能降低延遲造成的衝擊。舉例來說,假設應用程式需要文件查詢的結果和查詢結果才能轉譯回應。如果查詢和查詢不具資料相依關係,就不需要同步等待查詢完成再開始查詢。

  • 不可使用位移,請改用游標。使用偏移值只能避免將略過的文件傳回應用程式,但系統仍會在內部擷取這些文件。略過的文件會影響查詢的延遲時間,而且您的應用程式必須支付擷取這些文件所需的讀取作業費用。

交易重試

Cloud Firestore SDK 和用戶端程式庫會自動重試失敗的交易,以處理暫時性錯誤。如果應用程式是透過 RESTRPC API 直接存取 Cloud Firestore,而非透過 SDK,則應實作交易重試功能,以提高可靠性。

即時更新

如要瞭解即時更新的最佳做法,請參閱「瞭解大規模即時查詢」一文。

資源調度設計

以下最佳做法說明如何避免造成爭用問題的情況。

更新單一文件

設計應用程式時,請考慮應用程式更新單一文件的速度。如要瞭解工作負載的效能,最好的方法就是執行負載測試。應用程式更新單一文件的確切最大頻率,很大程度上取決於工作負載。這些因素包括寫入率、請求之間的爭用情形,以及受影響的索引數量。

文件寫入作業會更新文件和任何相關聯的索引,而 Cloud Firestore 會同步在備用資源的仲裁數中套用寫入作業。當寫入速率過高時,資料庫就會開始發生爭用、延遲時間變長或其他錯誤。

讀取、寫入和刪除頻率小,文件範圍有限

請避免高速讀取或寫入字母順序接近的文件,否則應用程式會發生爭用錯誤。此問題稱為資源使用率不均,如果您的應用程式執行以下任一操作,就可能會發生此問題:

  • 高速率建立新文件,並自行分配單調增加的 ID。

    Cloud Firestore 會使用散佈演算法分配文件 ID。如使用自動文件 ID 建立新文件,則應該不會在寫入時遇到資源使用率不均的問題。

  • 在文件數量不多的集合中,以極高的速度建立新文件。

  • 以極高的速度,使用單純增加的欄位 (例如時間戳記) 建立新文件。

  • 以高速刪除集合中的文件。

  • 以極高的速度寫入資料庫,但不逐漸增加流量。

避免略過已刪除的資料

避免跳過近期刪除的資料。如果先前的查詢結果最近已遭到刪除,查詢可能就必須略過大量索引項目。

舉例來說,如果工作負載嘗試找出最早排入佇列的工作項目,就可能需要略過大量已刪除的資料。查詢可能會如下所示:

docs = db.collection('WorkItems').order_by('created').limit(100)
delete_batch = db.batch()
for doc in docs.stream():
  finish_work(doc)
  delete_batch.delete(doc.reference)
delete_batch.commit()

每次執行這項查詢時,系統會掃描所有最近刪除文件的 created 欄位索引項目。這會減緩查詢的速度。

如要改善效能,請使用 start_at 方法找出最佳起點。例如:

completed_items = db.collection('CompletionStats').document('all stats').get()
docs = db.collection('WorkItems').start_at(
    {'created': completed_items.get('last_completed')}).order_by(
        'created').limit(100)
delete_batch = db.batch()
last_completed = None
for doc in docs.stream():
  finish_work(doc)
  delete_batch.delete(doc.reference)
  last_completed = doc.get('created')

if last_completed:
  delete_batch.update(completed_items.reference,
                      {'last_completed': last_completed})
  delete_batch.commit()

注意:上述範例使用單調遞增欄位,這是高寫入率的反模式。

增加流量

您應該逐漸增加傳送至新集合或字典順序相近文件的流量,讓 Cloud Firestore 有足夠時間為流量增加做好準備。建議您一開始傳送至新集合的流量不要超過每秒 500 項作業,接著每 5 分鐘增加 50% 的流量。您也可以以類似的方式提高寫入流量,但請注意 Cloud Firestore 標準限制。請確保作業在整個索引鍵範圍內均勻分佈。這就是「500/50/5」規則。

將流量遷移至新的集合

如果您要將應用程式流量從一個集合遷移至另一個集合,逐步增加流量就顯得格外重要。處理這項遷移作業的簡單方法,就是從舊集合讀取,如果文件不存在,則從新集合讀取。不過,這可能會導致新集合中字典順序相近的文件流量突然增加。Cloud Firestore 可能無法有效率地為流量增加的新集合做好準備,尤其是當流量不足時。

如果您對同一個集合中的多份文件變更文件 ID,也可能會發生類似問題。

將流量遷移至新集合的最佳策略取決於您的資料模型。以下所舉的策略範例稱為「平行讀取」。您需要判斷這項策略是否適用於您的資料,而平行作業在移轉階段對成本造成的影響會是相當重要的考量因素。

平行讀取

如要在將流量遷移至新集合時實作平行讀取,請先從舊集合讀取資料。如果文件遺失,請從新的集合讀取。大量讀取不存在的文件可能會導致資源使用率不均,因此請務必逐步增加新集合的負載。比較好的策略是將舊文件複製到新集合,然後刪除舊文件。逐漸增加平行讀取,確保 Cloud Firestore 能處理新集合的流量。

要逐漸增加新集合的讀取或寫入,可行策略之一是使用決定性的使用者 ID 雜湊隨機選取嘗試寫入新文件的使用者百分比。請務必避免函式或使用者行為扭曲使用者 ID 雜湊結果。

同時,請執行批次工作,將舊文件中的所有資料複製到新集合。批次工作應避免寫入連續文件 ID,以避免資源使用率不均。批次工作完成後,您就只能讀取新集合。

這個策略的進階版是一次只移轉一小批使用者。在使用者文件中新增一個欄位,用於追蹤該名使用者的遷移狀態。根據使用者 ID 的雜湊碼選取一批使用者。使用批次工作為該批使用者遷移文件,並在遷移期間為使用者使用平行讀取。

請注意,除非您在移轉階段同時寫入新舊實體,否則無法輕易復原。這會增加 Cloud Firestore 所產生的費用。

隱私權

  • 避免將機密資訊儲存在 Cloud 專案 ID 中。專案結束後,專案 ID 仍有可能保留下來。
  • 為遵守資料法規,我們建議您不要在文件名稱和文件欄位名稱中儲存機密資訊。

防止未經授權的存取

使用 Cloud Firestore Security Rules 防止未經授權的資料庫作業。舉例來說,使用規則可避免惡意使用者反覆下載整個資料庫的情況。

進一步瞭解如何使用 Cloud Firestore Security Rules