Cloud Firestore 的最佳做法

在構建使用 Cloud Firestore 的應用程序時,請使用此處列出的最佳做法作為快速參考。

數據庫位置

創建數據庫實例時,選擇最接近您的用戶和計算資源的數據庫位置。影響深遠的網絡躍點更容易出錯並增加查詢延遲。

為了最大限度地提高應用程序的可用性和耐用性,請選擇一個多區域位置並將關鍵計算資源放置在至少兩個區域中。

選擇一個區域位置以降低成本,如果您的應用程序對延遲敏感,則可以降低寫入延遲,或者與其他 GCP 資源共存

文檔 ID

  • 避免使用文檔 ID ...
  • 避免在文檔 ID 中使用/正斜杠。
  • 不要使用單調遞增的文檔 ID,例如:

    • Customer1 , Customer2 , Customer3 , ...
    • Product 1 , Product 2 , Product 3 , ...

    這種順序 ID 可能會導致影響延遲的熱點

字段名稱

  • 避免在字段名稱中使用以下字符,因為它們需要額外的轉義:

    • .時期
    • [左括號
    • ]右括號
    • *星號
    • `反引號

索引

  • 避免使用過多的索引。過多的索引會增加寫入延遲並增加索引條目的存儲成本

  • 請注意,具有單調遞增值的索引字段(例如時間戳)可能會導致熱點,從而影響具有高讀寫率的應用程序的延遲。

指數豁免

對於大多數應用程序,您可以依靠自動索引以及任何錯誤消息鏈接來管理您的索引。但是,您可能希望在以下情況下添加單字段豁免

案子描述
大字符串字段

如果您有一個字符串字段通常包含您不用於查詢的長字符串值,您可以通過免除該字段的索引來降低存儲成本。

對包含具有順序值的文檔的集合的高寫入率

如果您索引一個在集合中的文檔之間按順序增加或減少的字段(如時間戳),則對集合的最大寫入速率為每秒 500 次寫入。如果您不根據具有順序值的字段進行查詢,則可以使該字段免於索引以繞過此限制。

例如,在具有高寫入率的 IoT 用例中,包含具有時間戳字段的文檔的集合可能接近每秒 500 次寫入的限制。

大型數組或映射字段

大型數組或映射字段可以接近每個文檔 40,000 個索引條目的限制。如果您不是基於大型數組或映射字段進行查詢,則應將其排除在索引之外。

讀寫操作

  • 避免每秒多次寫入文檔。有關詳細信息,請參閱單個文檔的更新

  • 在可用的情況下使用異步調用而不是同步調用。異步調用將延遲影響降至最低。例如,考慮一個在呈現響應之前需要文檔查找結果和查詢結果的應用程序。如果查找和查詢沒有數據依賴關係,則無需同步等待查找完成後再啟動查詢。

  • 不要使用偏移量。相反,使用cursors 。使用偏移量只能避免將跳過的文檔返回到您的應用程序,但這些文檔仍會在內部檢索。跳過的文檔會影響查詢的延遲,並且您的應用程序需要為檢索它們所需的讀取操作付費。

事務重試

Cloud Firestore SDK 和客戶端庫會自動重試失敗的事務以處理暫時性錯誤。如果您的應用直接通過RESTRPC API 而不是通過 SDK 訪問 Cloud Firestore,則您的應用應實施事務重試以提高可靠性。

實時更新

為獲得最佳快照偵聽器性能,請保持文檔較小並控制客戶端的讀取率。以下建議提供了最大化性能的指南。超出這些建議可能會導致通知延遲增加。

推薦細節
降低快照偵聽器流失率

避免頻繁攪動偵聽器,尤其是當您的數據庫處於大量寫入負載時

理想情況下,您的應用程序應在打開與 Cloud Firestore 的連接後立即設置所有必需的快照偵聽器。設置初始快照偵聽器後,應避免在同一連接中快速添加或刪除快照偵聽器。

為確保數據一致性,Cloud Firestore 需要從其源數據中啟動每個新的快照偵聽器,然後趕上新的變化。根據數據庫的寫入速率,這可能是一項昂貴的操作。

如果您經常向引用添加或刪除快照偵聽器,您的快照偵聽器可能會遇到延遲增加。通常,對於相同數量的數據,持續連接的偵聽器比在該位置附加和分離偵聽器的性能更好。為獲得最佳性能,快照偵聽器的生命週期應為 30 秒或更長。如果您在應用中遇到偵聽器性能問題,請嘗試跟踪應用的偵聽和取消偵聽,以確定它們是否發生得太頻繁。

限制每個客戶端的快照偵聽器

100

將每個客戶端的快照偵聽器數量保持在 100 以下。

限制集合寫入速率

1,000 次操作/秒

將單個集合的寫入操作速率保持在 1,000 次操作/秒以下。

限制單個客戶端推送率

1 個文檔/秒

將數據庫推送到單個客戶端的文檔速率保持在 1 個文檔/秒以下。

限制全局客戶端推送率

1,000,000 份文件/秒

將數據庫向所有客戶端推送的文檔速率保持在 1,000,000 個文檔/秒以下。

這是一個軟限制。 Cloud Firestore 不會阻止您超過此閾值,但會極大地影響性能。

限制單個文檔的有效負載

10 KiB/秒

將單個客戶端下載的最大文檔大小保持在 10 KiB/秒以下。

限制全局文檔有效負載

1 GiB/秒

將所有客戶端下載的最大文檔大小保持在 1 GiB/秒以下。

限制每個文檔的字段數

100

您的文檔應包含少於 100 個字段。

了解 Cloud Firestore 標準限制

請記住Cloud Firestore 的標準限制

請特別注意文檔每秒寫入 1 次的限制以及每個數據庫 1,000,000 個並發連接的限制。這些是 Cloud Firestore 不會阻止您超出的軟限制。但是,超過這些限制可能會影響性能,具體取決於您的總讀寫速率。

雲函數

啟用每秒超過 2,000 個 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的hash選擇一批用戶進行遷移。使用批處理作業為該批用戶遷移文檔,並在遷移過程中為用戶使用並行讀取。

請注意,除非您在遷移階段同時對新舊實體進行雙重寫入,否則無法輕鬆回滾。這會增加產生的 Cloud Firestore 費用。

防止未經授權的訪問

使用 Cloud Firestore 安全規則防止對您的數據庫進行未經授權的操作。例如,使用規則可以避免惡意用戶重複下載整個數據庫的情況。

詳細了解如何使用 Cloud Firestore 安全規則