Cloud Firestore 的最佳做法

建構使用 Cloud Firestore 的應用程式時,請將下列最佳做法做為快速參考資料。

資料庫位置

建立資料庫執行個體時,請選取最靠近使用者和運算資源的資料庫位置。網路躍點越遠就越容易發生錯誤,且會增加查詢延遲。

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

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

文件 ID

  • 請避開文件 ID ...
  • 請勿在文件 ID 中使用 / 正斜線。
  • 請勿使用單純增加的文件 ID,例如:

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

    這類連續 ID 可能會導致熱點,進而影響延遲時間。

欄位名稱

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

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

索引

縮短寫入延遲時間

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

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

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

索引豁免

對於大多數應用程式,您可以依賴自動建立索引,以及任何錯誤訊息連結來管理索引。不過,在下列情況下,您可能會想新增單一欄位豁免

案件 說明
大型字串欄位

如果字串欄位經常保存您不常用於查詢的長字串值,您可以免除該欄位的索引,藉此節省儲存空間費用。

集合的寫入頻率很高,且集合中的文件含有序列值

如果您為集合中文件之間依序遞增或遞減的欄位建立索引 (例如時間戳記),則該集合的寫入頻率上限為每秒 500 次寫入。如果不是根據具有連續值的欄位查詢,可以將該欄位排除在索引之外,藉此略過這項限制。

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

存留時間欄位

如果您使用 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