我們為什麼要遠離資料庫生成的ID?- Tugberk Ugurlu

banq發表於2019-01-27

在我們當前為團隊構建SQL Server資料目錄的過程中,我們正在最佳化我們的解耦工程工作。有一些具體的因素對我們非常重要,從根本上說,這歸結為兩個核心原則,我希望每個軟體工程專業人士都會同意:
  • 我們不希望我們的複雜性隨著我們在系統中新增更多功能而線性增長,隨著我們在業務和價值信心方面的增長,這將極大地降低我們的速度。
  • 我們希望能夠適應不斷變化的需求和需求,以滿足新客戶需求,效能,新查詢模型,業務模式變更等各方面的需求。換句話說,我們希望能夠交換我們系統中的任何元件都有一個更合適的元件,適合當今的需求,而不是過去的需求。

這如何影響永續性?
考慮到這個高層原則,我們不希望將自己耦合到特定的資料庫引擎以實現狀態永續性。實際上,這意味著我們不會將永續性特定問題洩漏到我們的領域層中。我們想要實現這一目標的主要原因與我們今天對真理的看法可能使我們依賴某種資料庫技術(如SQL Server)這一事實有關,但不確定這將滿足未來的能力需求。
當我們想要提供一個真正可審計的系統時,就會出現這方面的具體例子。根據該特定要求,能夠使用有界上下文來持久發生領域事件而不是儲存當前狀態(也稱為事件源)更有意義。這將需要根本不同的儲存需求。

伺服器與資料庫的ID生成
許多資料儲存系統(如SQL Server)都有方法為每個記錄生成唯一識別符號(例如行,文件等)。自動增量鍵允許在將新記錄插入表中時生成唯一編號。因此,每次我們要建立新記錄時,資料庫引擎都會自動建立主鍵,並且它有責任確保此鍵對錶是唯一的。

但是,資料庫技術可以為我們的領域聚合生成識別符號的假設再次將我們與資料儲存系統聯絡起來。

如果我們想要更改一個沒有生成自動增量主鍵功能的資料儲存系統,該怎麼辦?我們做不到。而且,每個資料儲存系統具有不同的生成這些主鍵識別符號的方式,這可能導致我們最終得到不同的基元型別。除此之外,這些型別的Key可能不適用於分散式系統。例如,當我們在SQL Server資料庫中有一個生成主鍵的表時,我們沒有一種簡單的方法可以在分散式環境中水平擴充套件該表。

透過讓領域層的消費者(即透過命令和查詢與領域層通訊的傳輸層)實現唯一的聚合識別符號生成,可以克服這些問題。

這減少了環境依賴性,這反過來又讓我們不依賴於資料庫來生成Id。這種方法還有另一個好處:它可以支援分發。例如,我們可以將一個表分割槽到兩個物理SQL Server上,並分攤查詢成本。如果我們有一個自動增量鍵,這對SQL Server不起作用。

我們決定做什麼?
基於這些事實,我們決定讓領域層的消費者為領域聚合生成識別符號。我們將這些識別符號表示為領域層中的64位無符號整數。領域消費者可以根據其上下文自由決定它的表示形式(例如,ASP.NET Core MVC可以序列化識別符號string,以便使其客戶端易於使用資源物件等)。

為什麼是64位整數,為什麼不是UUID?
最後,您可能想知道為什麼64位整數。這裡的主要目的是讓我們能夠在聚合根中生成唯一識別符號。考慮到幾乎每個平臺都有靜態API(例如Guid.NewGuid()在.NET等),UUID是非常便宜的方法。UUID最大的痛苦是儲存系統在儲存和索引方面的成本。這對我們來說不是什麼大問題。但是,已經建立了將唯一識別符號生成為更有效的原始型別(如分散式系統中的64位整數)的方法。Twitter Snowflake演算法就是其中之一,這使得我們選擇64位整數優於UUID。我們正在使用來自Rob Janssen的開源IdGen庫,這是一款適用於.NET的Twitter Snowflake-like ID生成器。

 

相關文章