瞭解大規模的讀取與寫入

請參閱這份文件,在建構應用程式架構以實現高效能和可靠性時做出明智的決策。本文件包含進階 Cloud Firestore 主題。如果您剛開始使用 Cloud Firestore,請改為參閱快速入門指南

Cloud Firestore 是可擴充的彈性資料庫,適用於 Firebase 和 Google Cloud 的行動裝置、網頁和伺服器開發作業。讓您輕鬆開始使用 Cloud Firestore,並編寫功能豐富且功能強大的應用程式。

為了確保應用程式能繼續維持與資料庫大小和流量增加,建議您先瞭解 Cloud Firestore 後端的讀取和寫入機制。您也必須瞭解讀取和寫入資料與儲存空間層的互動方式,以及可能影響效能的基礎限制。

開始建構應用程式之前,請參閱下列各節瞭解最佳做法。

瞭解高階元件

下圖顯示與 Cloud Firestore API 要求相關的高階元件。

高階元件

Cloud Firestore SDK 和用戶端程式庫

Cloud Firestore 支援不同平台的 SDK 和用戶端程式庫。雖然應用程式可以直接向 Cloud Firestore API 發出 HTTP 和遠端程序呼叫 (RPC) 呼叫,但用戶端程式庫提供了抽象層,可簡化 API 使用方式並實行最佳做法。也可能提供離線存取、快取等其他功能。

Google Front End (GFE)

這是所有 Google 雲端服務通用的基礎架構服務。GFE 會接受傳入的要求,並將要求轉送至相關的 Google 服務 (在本例中為 Firestore 服務)。它也提供其他重要功能,包括防範阻斷服務攻擊。

Cloud Firestore 服務

Cloud Firestore 服務會檢查 API 要求,包括驗證、授權、配額檢查和安全性規則,並管理交易。這項 Cloud Firestore 服務包含與讀取和寫入資料儲存層互動的儲存空間用戶端

Cloud Firestore 儲存層

Cloud Firestore 儲存空間層負責儲存資料和中繼資料,以及 Cloud Firestore 提供的關聯資料庫功能。以下各節說明資料在 Cloud Firestore 儲存層中的組織方式,以及系統的資源調度方式。瞭解資料整理方式有助於設計可擴充的資料模型,並進一步瞭解 Cloud Firestore 的最佳做法。

索引鍵範圍和分割

Cloud Firestore 是 NoSQL 文件資料庫您可以將資料儲存在「文件」中,文件是以「集合」的階層分類。每份文件的集合階層和文件 ID 都會轉譯為單一索引鍵。文件會按照這個索引鍵,按字母順序儲存和按照字母順序儲存。我們使用「索引鍵範圍」一詞,是指按照字母順序排列的連續金鑰範圍。

一般 Cloud Firestore 資料庫過大,無法容納單一實體機器。在某些情況下,資料上的工作負載對單個機器無法處理。為了處理大型工作負載,Cloud Firestore 會將資料分區,並分成多部儲存並透過多部機器或儲存伺服器提供。這些分區會在資料庫資料表的區塊中,以稱為分割的索引鍵範圍進行。

同步複製

請注意,系統一律會自動同步複製資料庫。資料分割的備用資源位於不同的可用區中,即使可用區無法存取,仍可持續使用。持續複製到分割的不同副本是由用於共識的 Paxos 演算法管理。系統會選擇每個分割的一個備用資源做為 Paxos 領導者,負責處理分割的寫入作業。同步複製功能讓您隨時都能從 Cloud Firestore 讀取最新版本的資料。

整體成果是一個可擴充且可用性高的系統,無論工作量繁重和規模過大,都能提供低延遲的讀取和寫入功能。

資料版面配置

Cloud Firestore 是無結構定義的文件資料庫。但是在內部,資料主要會在儲存空間層的兩個關聯資料庫式資料表中配置資料,如下所示:

  • 文件表格:文件會儲存在這個表格中。
  • 索引表格:如果索引項目可以有效取得結果,並依索引值排序,則會儲存在這個表格中。

下圖顯示分組的 Cloud Firestore 資料庫資料表可能呈現的樣貌。分割會在三個不同的可用區中複製,每個分段都有獲派的 Paxos 領導者。

資料版面配置

單一區域與多區域

建立資料庫時,您必須選取區域多區域

單一區域位置是特定的地理位置,例如 us-west1。Cloud Firestore 資料庫的資料分割,在所選區域內的不同可用區內具有備用資源,如先前所述。

多區域位置是由一組定義的區域組成,用來儲存資料庫的備用資源。在 Cloud Firestore 的多區域部署中,兩個區域都有資料庫完整資料的完整備用資源。第三個區域具有見證備用資源,這項備用資源不會維護完整的資料,但會做複製作業。透過複製多個區域的資料,即便會遺失整個區域,也能寫入及讀取資料。

如要進一步瞭解區域的位置,請參閱 Cloud Firestore 位置

單一區域與多區域

瞭解 Cloud Firestore 中寫入的生命週期

Cloud Firestore 用戶端可透過建立、更新或刪除單一文件來寫入資料。寫入單一文件時,必須在儲存空間層一次更新文件及其相關索引項目。Cloud Firestore 也支援包含多次讀取和/或寫入一或多份文件的不可分割作業。

針對各種類型的寫入作業,Cloud Firestore 提供關聯資料庫的 ACID 屬性 (完整性、一致性、隔離性和耐用性)。Cloud Firestore 也提供可序列化功能,這表示所有交易都會以序列順序執行。

寫入交易的高階步驟

當 Cloud Firestore 用戶端使用前述任一方法發出寫入或修訂交易時,內部作業會在儲存空間層中做為資料庫讀取/寫入交易執行。這筆交易可讓 Cloud Firestore 提供前述的 ACID 屬性。

做為交易的第一步,Cloud Firestore 會讀取現有文件,並判斷要對「文件」資料表中的資料執行變異作業。

這也包括對索引表進行必要的更新,如下所示:

  • 要加入文件的欄位需要在「索引」表格中對應的插入項目。
  • 如果要從文件中移除欄位,必須在「索引」表格中對應刪除欄位。
  • 已在文件中修改的欄位需要在索引資料表中刪除 (舊值) 和插入 (新值)。

為了計算前述的異動內容,Cloud Firestore 會讀取專案的索引設定。索引設定會儲存專案索引的相關資訊。Cloud Firestore 使用兩種類型的索引:單一欄位與複合。如要進一步瞭解在 Cloud Firestore 中建立的索引,請參閱 Cloud Firestore 中的索引類型

計算異動內容後,Cloud Firestore 會在交易中收集這些變化,然後修訂。

瞭解儲存空間層中的寫入交易

如先前所述,Cloud Firestore 中的寫入作業涉及儲存空間層中的讀取/寫入交易。視資料的版面配置而定,寫入作業可能涉及一或多個分割,如資料版面配置所述。

在下圖中,Cloud Firestore 資料庫在單一可用區中的三個不同儲存伺服器,有八個分割 (標示為 1 至 8),每個分割都會複製到 3 個(或更多) 不同的可用區。每個分段都有一個 Paxos 領導者,針對不同分割區,其分處可能不同。

Cloud Firestore 資料庫分割

假設 Cloud Firestore 資料庫含有下列 Restaurants 集合:

餐廳集

Cloud Firestore 用戶端會透過更新 priceCategory 欄位的值,要求 Restaurant 集合中的文件進行下列變更。

變更為集合中的文件

下列高階步驟說明寫入過程中發生的情況:

  1. 建立讀寫交易。
  2. 從儲存空間圖層的「Documents」(文件) 資料表,讀取 Restaurants 集合中的 restaurant1 文件。
  3. 索引表格中讀取文件的索引。
  4. 計算要對資料執行的變異。這個例子中有五種異動:
    • M1:更新「Documents」資料表中的 restaurant1 資料列,反映 priceCategory 欄位的值變更。
    • M2 和 M3:刪除「索引」資料表中的 priceCategory 舊值資料列,以遞減及遞增的方式排序。
    • M4 和 M5:在索引資料表中插入 priceCategory 新值的資料列,依遞減和遞增順序排列。
  5. 修訂這些異動。

Cloud Firestore 服務中的儲存空間用戶端,會查詢擁有待變更資料列索引鍵的分割。假設分割 3 放送 M1,而分割 6 放送 M2 至 M5。此為分散式交易,將所有這些分割視為參與者。參與者分割可能也包含在讀寫交易中較早讀取的任何其他分割。

下列步驟說明修訂版本中的運作方式:

  1. 儲存空間用戶端會發出修訂版本。修訂版本包含 M1-M5 異動內容。
  2. 雙方將分割 3 和 6 分,即為此交易的參與者。其中一位參與者會選擇協調者,例如分割畫面 3。協調者的工作是確保所有參與者的交易能以不可分割的形式修訂或取消。
    • 這些分割作業的主導備用資源需由參與者和協調者完成。
  3. 每位參與者和協調者都會透過各自的備用資源執行 Paxos 演算法。
    • 領導者會使用備用資源執行 Paxos 演算法。如果大多數備用資源在回應領導者收到 ok to commit 回應,就會達成仲裁。
    • 接著,每位參與者在準備 (兩階段修訂) 的第一階段時,通知協調者。如果任何參與者無法修訂交易,整筆交易為 aborts
  4. 當協調員確定所有參與者 (包括自己) 做好準備後,就會將 accept 交易結果通知所有參與者 (兩階段修訂的第二階段)。在這個階段,每位參與者會將修訂的決定記錄至穩定的儲存空間,然後交易才會完成。
  5. 協調者會回應 Cloud Firestore 中已修訂交易的儲存用戶端。協調者和所有參與者也會對資料套用變異。

修訂生命週期

Cloud Firestore 資料庫規模較小時,單一分割可能會擁有 M1 至 M5 變異項目中的所有金鑰。在這種情況下,交易中只有一個參與者,不必進行前述的兩階段修訂,因此會加快寫入速度。

多區域寫入

在多區域部署中,將備用資源分散於各個區域可提升可用性,但會產生效能成本。不同區域的備用資源之間的通訊需要較長的往返時間。因此,與單一區域部署相比,Cloud Firestore 作業的基準延遲時間略長許多。

我們設定備用資源的方式,讓分割作業的領導地一律保留在主要區域中。主要區域是指流量從該區域傳入 Cloud Firestore 伺服器的區域。這種主管階層決策可以縮短 Cloud Firestore 中的儲存體用戶端與備用資源負責人 (或多重分割交易的協調員) 之間的通訊延遲。

Cloud Firestore 中的每項寫入作業也涉及與 Cloud Firestore 中即時引擎的某些互動。如要進一步瞭解即時查詢,請參閱「大規模瞭解即時查詢」一文。

瞭解 Cloud Firestore 中讀取作業的生命週期

本節將深入說明 Cloud Firestore 中的非即時讀取作業。在內部,Cloud Firestore 伺服器會在兩個主要階段處理大部分的查詢:

  1. 「索引」資料表的單一範圍掃描
  2. 根據先前的掃描結果,「Documents」(文件) 資料表中的點查詢
在 Cloud Firestore 中,某些查詢可能需要較少的處理量或處理量 (例如印度查詢)。

從儲存空間層讀取資料後,系統會在內部使用資料庫交易,確保讀取作業的一致性。不過,與用於寫入的交易不同,這些交易不會鎖定,而是選擇時間戳記,然後執行該時間戳記的所有讀取作業。因為這些物件不會取得鎖定,因此不會封鎖並行的讀寫交易。如要執行這筆交易,Cloud Firestore 中的儲存空間用戶端會指定時間戳記範圍,讓儲存空間層瞭解如何選擇讀取時間戳記。在 Cloud Firestore 中,儲存空間用戶端所選的時間戳記範圍類型取決於讀取要求的讀取選項。

瞭解儲存空間層中的讀取交易

本節說明讀取的類型,以及讀取方式在 Cloud Firestore 儲存空間層的處理方式。

強式讀取

根據預設,Cloud Firestore 讀取作業具有同步一致性。這種同步一致性意味著 Cloud Firestore 讀取作業會傳回最新的資料版本,該版本會反映所有在讀取開始之前修訂的寫入作業。

單一分割讀取

Cloud Firestore 中的儲存用戶端會查詢擁有待讀取資料列索引鍵的分割。假設需要從前的章節中讀取分割 3 的內容。用戶端會將讀取要求傳送至最近的備用資源,以縮短往返延遲時間。

目前,視所選的備用資源而定,可能會發生下列情況:

  • 讀取要求會傳送至主要備用資源 (可用區 A)。
    • 由於領導者一直處於最新狀態,因此讀取權限會直接繼續進行。
  • 讀取要求會傳送至非主要備用資源 (例如可用區 B)
    • 分割 3 可能會根據其內部狀態得知具有足夠資訊來處理讀取作業,而分割作業會如此。
    • 分割 3 不確定是否已看到最新的資料。它會傳送訊息給領導者,要求取得提供讀取作業所需的最後一筆交易的時間戳記。一旦套用交易,系統就會繼續讀取作業。

接著,Cloud Firestore 會將回應傳回用戶端。

多重分割讀取

如果需要從多個分割中完成讀取,所有分割都會使用相同的機制。從所有分割傳回資料後,Cloud Firestore 的儲存空間用戶端會合併結果。接著,Cloud Firestore 會使用這些資料回應用戶端。

過時讀取

強式讀取是 Cloud Firestore 的預設模式。不過,由於領導者可能需要進行通訊,延遲時間也可能比較長。一般來說,Cloud Firestore 應用程式不需讀取最新版本的資料,而且這項功能可以順利處理幾秒鐘的過時資料。

在這種情況下,用戶端可能會使用 read_time 讀取選項,選擇接收過時的讀取。在這個範例中,讀取作業會在資料位於 read_time 時完成,而最接近的備用資源很可能已驗證在指定 read_time 處有資料。為獲得明顯更好的效能,合理的過時程度值是 15 秒。即使是過時讀取,產生的資料列也會保持一致。

避免使用無線基地台

Cloud Firestore 中的分割功能會自動細分為較小的項目,以便視需要或索引鍵空間展開時,將提供流量的工作分配給更多儲存空間伺服器。為因應多餘流量而建立的分割,即使流量離開流量,仍會保留大約 24 小時。因此,如果流量週期性攀升,分割程序會維持現有比例,並在需要時增加更多分配比例。這些機制可協助 Cloud Firestore 資料庫在流量負載或資料庫規模增加時,自動調度資源。但請留意下列幾項限制。

分割儲存空間和負載需要時間,如果流量速度過快,可能會導致延遲時間過長或超過期限錯誤 (通常稱為「熱點」,而服務正在調整時)。最佳做法是將作業分散到索引鍵範圍,同時提高資料庫中集合的流量 (每秒 500 次操作)。逐步適應後,每五分鐘的流量最多可增加 50%。這個程序稱為 500/50/5 規則,並將資料庫定位為最適合您的工作負載擴充規模。

雖然系統會在負載增加時自動建立分割,但 Cloud Firestore 只會分割索引鍵範圍,直到使用一組專屬的複製儲存伺服器提供單一文件為止。因此,在單一文件上持續進行大量並行作業,可能會導致該文件出現資源使用率不均的情形。如果單一文件的延遲時間持續過長,建議您考慮修改資料模型,藉此分割或複製多份文件的資料。

多項作業嘗試同時讀取及/或寫入同一份文件時,會發生爭用錯誤。

在 Cloud Firestore 中,使用遞增/減少的索引鍵做為文件 ID,且每秒執行大量作業時,就會發生另一個特殊資源使用率不均的情況。流量激增的情況只會移到新建立的拆分,無法促成更多拆分。由於根據預設,Cloud Firestore 會自動將文件中的所有欄位編入索引,因此如果文件欄位的索引空間含有依序增加/減少的值 (例如時間戳記),系統也可能會在索引空間中建立這類移動熱點。

請注意,按照上述做法進行後,Firestore 就能調度資源來因應各種規模的工作負載,您不必調整任何設定。

疑難排解

Firestore 提供 Key Visualizer 診斷工具,專門用於分析使用模式及排解無線基地台問題。

後續步驟