共用方式為


ADO.NET 粒紋持續性

Orleans 中的關聯式儲存體後端程式碼以一般 ADO.NET 功能為建置基礎,因此與資料庫廠商無關。 Orleans 資料儲存體配置已說明於執行階段資料表中。 連接字串已設定完成,如 Orleans 設定指南所說明。

若要讓 Orleans 程式碼與指定的關聯式資料庫後端搭配運作,必須符合下列條件:

  1. 必須將適當的 ADO.NET 程式庫載入程序中。 您應按常規加以定義,例如,透過應用程式組態中的 DbProviderFactories 元素。
  2. 透過選項中的 Invariant 屬性來設定 ADO.NET 非變異值。
  3. 資料庫必須存在並且與程式碼相容。 這可藉由執行廠商特定的資料庫建立指令碼來完成。 如需詳細資訊,請參閱 ADO.NET 組態

ADO.NET 粒紋儲存體提供者可讓您將粒紋狀態儲存在關聯式資料庫中。 目前支援下列資料庫:

  • SQL Server
  • MySQL/MariaDB
  • PostgreSQL
  • Oracle

首先,請安裝基底套件:

Install-Package Microsoft.Orleans.Persistence.AdoNet

請參閱 ADO.NET 組態 文章,以取得設定資料庫的相關資訊,包括對應的 ADO.NET 非變異值和安裝指令碼。

以下是如何透過 ISiloHostBuilder 設定 ADO.NET 儲存體提供者的範例:

var siloHostBuilder = new HostBuilder()
    .UseOrleans(c =>
    {
        c.AddAdoNetGrainStorage("OrleansStorage", options =>
        {
            options.Invariant = "<Invariant>";
            options.ConnectionString = "<ConnectionString>";
            options.UseJsonFormat = true;
        });
    });

基本上,您只需要設定資料庫廠商特定的連接字串和識別廠商的 Invariant 即可 (請參閱 ADO.NET 組態)。 您也可以選擇資料儲存格式,可以是二進位 (預設)、JSON 或 XML。 雖然二進位是最精簡的選項,但此格式不透明,且您將無法讀取或處理資料。 JSON 是建議選項。

您可以透過 AdoNetGrainStorageOptions 設定下列屬性:

/// <summary>
/// Options for AdoNetGrainStorage
/// </summary>
public class AdoNetGrainStorageOptions
{
    /// <summary>
    /// Define the property of the connection string
    /// for AdoNet storage.
    /// </summary>
    [Redact]
    public string ConnectionString { get; set; }

    /// <summary>
    /// Set the stage of the silo lifecycle where storage should
    /// be initialized.  Storage must be initialized prior to use.
    /// </summary>
    public int InitStage { get; set; } = DEFAULT_INIT_STAGE;
    /// <summary>
    /// Default init stage in silo lifecycle.
    /// </summary>
    public const int DEFAULT_INIT_STAGE =
        ServiceLifecycleStage.ApplicationServices;

    /// <summary>
    /// The default ADO.NET invariant will be used for
    /// storage if none is given.
    /// </summary>
    public const string DEFAULT_ADONET_INVARIANT =
        AdoNetInvariants.InvariantNameSqlServer;

    /// <summary>
    /// Define the invariant name for storage.
    /// </summary>
    public string Invariant { get; set; } =
        DEFAULT_ADONET_INVARIANT;

    /// <summary>
    /// Determine whether the storage string payload should be formatted in JSON.
    /// <remarks>If neither <see cref="UseJsonFormat"/> nor <see cref="UseXmlFormat"/> is set to true, then BinaryFormatSerializer will be configured to format the storage string payload.</remarks>
    /// </summary>
    public bool UseJsonFormat { get; set; }
    public bool UseFullAssemblyNames { get; set; }
    public bool IndentJson { get; set; }
    public TypeNameHandling? TypeNameHandling { get; set; }

    public Action<JsonSerializerSettings> ConfigureJsonSerializerSettings { get; set; }

    /// <summary>
    /// Determine whether storage string payload should be formatted in Xml.
    /// <remarks>If neither <see cref="UseJsonFormat"/> nor <see cref="UseXmlFormat"/> is set to true, then BinaryFormatSerializer will be configured to format storage string payload.</remarks>
    /// </summary>
    public bool UseXmlFormat { get; set; }
}

ADO.NET 持續性具有管理資料版本的功能,並且可使用任意應用程式規則和串流來定義任意 (還原) 序列化程式,但目前沒有任何方法可將其公開給應用程式程式碼。

ADO.NET 持續性原理

ADO.NET 支援的持續性儲存體有以下準則:

  1. 確保業務關鍵資料安全無虞並可供存取,同時維護資料、資料格式和程式碼演進。
  2. 運用廠商特定和儲存體特定功能。

其實質意義就是依循 ADO.NET 實作目標,以及 ADO.NET 特定儲存提供者中已新增、可讓儲存體中的資料成形的一些實作邏輯。

除了一般儲存體提供者功能以外,ADO.NET 提供者還具備內建功能,能夠:

  1. 在處於往返狀態時,將儲存體資料從一種格式變更為另一種格式 (例如,從 JSON 變更為二進位)。
  2. 以任意方式形成要儲存或從儲存體中讀取的型別。 這可讓狀態的版本持續演進。
  3. 將資料從資料庫中串流出來。

1.2. 都可根據任意決策參數來套用,例如粒紋識別碼粒紋型別承載資料

如此,您就可以選擇序列化格式 (例如簡單二進位編碼 (SBE)) 並實作 IStorageDeserializerIStorageSerializer。 內建序列化程式已使用下列方法建置:

序列化程式實作後,必須新增至 AdoNetGrainStorage 中的 StorageSerializationPicker 屬性。 以下是 IStorageSerializationPicker 的實作。 依預設,將使用 StorageSerializationPicker。 您可在 RelationalStorageTests 參考變更資料儲存格式或使用序列化程式的範例。

目前尚無方法可存取架構建立的 AdoNetGrainStorage,因此無法將序列化選擇器公開給 Orleans 應用程式。

設計的目標

1.允許使用任何具有 ADO.NET 提供者的後端

這應盡可能廣泛涵蓋適用於 .NET 的後端,這是內部部署安裝的一項要素。 ADO.NET 概觀會列出部分提供者,但並非全都會列出,例如 Teradata 就未列出。

2.保有適時調整查詢和資料庫結構的可能性,即使部署正在執行亦然

在許多情況下,伺服器和資料庫都是由與用戶端有合約關係的第三方裝載的。 虛擬化裝載環境的效能因非預期因素 (例如鄰近干擾或硬體故障等) 而出現波動,並非罕見情形。 我們可能無法改變和重新部署 Orleans 二進位檔 (基於合約原因) 甚或應用程式二進位檔,但資料庫部署參數通常是可調整的。 要變更標準元件 (例如 Orleans 二進位檔),需要以更冗長的程序在指定的情況下進行最佳化。

3.可讓您使用廠商特定和版本特定功能

廠商在其產品中實作了不同的延伸模組和功能。 當這些功能可供使用時,就該妥善運用。 這些功能包括 PostgreSQL 中的原生 UPSERTPipelineDB,以及 SQL Server 中的 PolyBase原生編譯資料表和預存程序

4.得以將硬體資源最佳化

設計應用程式時,常可能會預期哪些資料需要比其他資料更快插入,以及哪些資料更有可能放入冷儲存體中,以節省成本 (例如,將資料分置於 SSD 和 HDD)。 其他考量包括資料的實體位置 (某些資料可能較昂貴或較為安全,例如 SSD RAID 比 HDD RAID 昂貴),或其他決策基礎。 與第 3 點相關,某些資料庫提供特殊的資料分割配置,例如 SQL Server 資料分割資料表和索引

這些準則在整個應用程式生命週期中均適用。 考量到 Orleans 本身的其中一個準則是高可用性,應該要能夠在不干擾 Orleans 部署的情況下調整儲存體系統,或能夠根據資料和其他應用程式參數調整查詢。 如需動態變更的範例,可以參考 Brian Harry 的部落格文章

資料表較小時,查詢計劃幾乎無關緊要。 若是中型資料表,則查詢計劃堪用就行,但當資料表十分龐大 (數百萬個或數十億個資料列) 時,即便查詢計劃只有些微變化,也會讓您備感棘手。 因此,對於敏感性查詢我們會提供大量提示。

5.不臆測組織中使用的工具、程式庫或部署程序

許多組織都有一組特定的慣用資料庫工具,例如 DacpacRed Gate。 部署資料庫時有可能需要特定權限或人員,例如具備 DBA 角色的人員。 通常這意味著還需具備目標資料庫配置,且需草擬應用程式將產生用來估計負載的查詢。 可能有些程序 (可能受業界標準影響) 會要求進行以指令碼為基礎的部署。 這可透過在外部指令碼中處理查詢和資料庫結構來達成。

6.使用載入 ADO.NET 程式庫和功能所需的一組基本介面功能

這樣不但快速,又能降低 ADO.NET 程式庫實作不一致的可能性。

7.使設計可分區化

只要有利,就應使設計易於分區化,例如在關聯式儲存體提供者中。 舉例來說,這意味著不使用資料庫相關的資料 (例如 IDENTITY)。 區分資料列資料的資訊,應僅以實際參數的資料為基礎。

8.讓設計更易於測試

理想情況下,建立新的後端應該是很容易的,只需將其中一個現有的部署指令碼轉譯成您嘗試設為目標之後端的 SQL 方言、將新的連接字串新增至測試 (採用預設參數)、檢查是否已安裝指定的資料庫,然後對其執行測試即可。

9.將前述幾點納入考量,盡可能以透明化的方式移植新後端的指令碼以及修改已部署的後端指令碼

實現目標

架構 Orleans 無法認知部署特定硬體 (哪些硬體可能會在作用中部署期間變更)、部署生命週期內的資料變更,或在特定情況下才能使用的特定廠商特有功能。 因此,資料庫與 Orleans 之間的介面應以最少量的抽象概念和規則達成這些目標,以力求避免誤用,並且在需要時輕鬆加以測試。 執行階段資料表、叢集管理和具體的成員資格通訊協定實作。 此外,SQL Server 實作包含 SQL Server 的版本特定微調。 資料庫與 Orleans 之間的介面合約定義如下:

  1. 概念是透過 Orleans 特定查詢讀取和寫入資料。 Orleans 在讀取時會對資料行名稱和型別運作,在寫入時則對參數名稱和型別運作。
  2. 實作必須保留輸入和輸出名稱與型別。 Orleans 會使用這些參數依名稱和型別讀取查詢結果。 允許廠商特定和部署特定的微調,並且在符合介面合約的前提下鼓勵參與。
  3. 跨廠商特定指令碼的實作保留條件約束名稱。 這可以簡化疑難排解,因為不同的具體實作間可保有統一的命名。
  4. 版本 – 或應用程式程式碼中的 ETag – 針對 Orleans,這代表唯一的版本。 實際實作的型別若是代表唯一的版本,就不重要。 在實作中,Orleans 程式碼需要帶正負號的 32 位元整數。
  5. 為力求明確並避免語意模糊,Orleans 預期某些查詢應傳回 TRUE as > 0 值或 FALSE as = 0 值。 也就是說,受影響或傳回的資料列數目並不重要。 如果引發錯誤或擲回例外狀況,查詢必須確保整個交易都會復原,並且可傳回 FALSE 或傳播例外狀況。
  6. 目前,只有一個查詢不是單一資料列插入或更新 (請注意,只要相關聯的 SELECT 查詢執行了最後一次寫入,就可以將 UPDATE 查詢取代為 INSERT)。

資料庫引擎支援資料庫內程式設計。 其概念類似於載入可執行指令碼,並叫用指令碼以執行資料庫作業。 在虛擬程式碼中,可將其描述為:

const int Param1 = 1;
const DateTime Param2 = DateTime.UtcNow;
const string queryFromOrleansQueryTableWithSomeKey =
    "SELECT column1, column2 "+
    "FROM <some Orleans table> " +
    "WHERE column1 = @param1 " +
    "AND column2 = @param2;";
TExpected queryResult =
    SpecificQuery12InOrleans<TExpected>(query, Param1, Param2);

這些準則也包含在資料庫指令碼中

套用自訂指令碼的一些想法

  1. 使用 IF ELSE 改變 OrleansQuery 中的指令碼以達到粒紋持續性,以便使用預設 INSERT 來儲存某些狀態,而某些粒紋狀態則可使用記憶體最佳化資料表SELECT 查詢必須據以改變。
  2. 1. 中的概念可運用在其他部署或廠商特定層面,例如將資料分置於 SSDHDD、將某些資料放在加密資料表中,或是透過 SQL-Server-to-Hadoop 甚或連結伺服器插入統計資料。

改變後的指令碼可藉由執行 Orleans 測試套件來測試,或直接在資料庫中使用 SQL Server 單元測試專案或其他工具進行測試。

新增 ADO.NET 提供者的指導方針

  1. 根據前述實現目標一節的指示,新增資料庫安裝指令碼。
  2. 將廠商 ADO 非變異值名稱新增至 AdoNetInvariants,並將 ADO.NET 提供者特定資料新增至 DbConstantsStore。 這些資料 (可能) 會用於某些查詢作業中, 用以選取正確的統計資料插入模式 (即含有或不含 FROM DUALUNION ALL),或執行其他工作。
  3. Orleans 提供了所有系統存放區均適用的完整測試:成員資格、提醒和統計資料。 只要複製並貼上現有的測試類別,並變更 ADO 非變異值名稱,即可新增新資料庫指令碼的測試。 此外,請從 RelationalStorageForTesting 衍生並定義 ADO 非變異值的測試功能。