共用方式為


Orleans 中的最佳實踐

Orleans 建置是為了大幅簡化分散式可擴充應用程式的建置,特別是針對雲端。 Orleans 發明虛擬演員模型,作為針對雲端情境最佳化的演員模型的演進。

粒(虛擬執行者)是基於Orleans的應用程式的基底建置組塊。 它們會封裝應用程式實體的狀態和行為,並維護其生命週期。 Orleans 的程式設計模型及其運行時的特性對某些類型的應用程式比其他類型更為適合。 本檔旨在擷取一些在 中 Orleans運作良好且經過驗證的應用程式模式。

適合的應用程式

請考慮 Orleans 下列時機:

  • 大量鬆散結合的實體(數億、數百萬、數十億甚至萬億)。 若要將數位放在檢視方塊中,只要該總數的子集在任何時間點都處於作用中狀態, Orleans 就可以輕鬆地為地球上的每一個人建立粒紋。
    • 範例:使用者配置檔、採購單、應用程式/遊戲會話、庫存。
  • 實體夠小,足以進行單個線程處理。
    • 範例:判斷是否應該根據目前的價格購買股票。
  • 工作負載是互動式的。
    • 範例:請求-回應、開始/監控/完成。
  • 預期或可能需要多個伺服器。
    • Orleans 在藉由新增伺服器擴展的叢集上運行。
  • 不需要全域協調,或一次在少數實體之間進行較小的規模協調。
    • 擴展性和執行效能是藉由平行化和分散大量主要是獨立的任務來達成的,並且不需要任何單一的同步點。

不適合的應用程式

Orleans 不太適合用於以下情況:

  • 必須在實體之間共用記憶體。
    • 每個顆粒都會維護其狀態,不應被分享。
  • 少數大型實體可能會多線程。
    • 在單一服務中支援複雜邏輯時,微服務可能是較佳的選項。
  • 需要全域協調和/或一致性。
    • 這種全域協調會嚴重限制以Orleans為基礎的應用程式的效能。 Orleans 是專為輕鬆調整為全球規模而建置的,不需要進行深入的手動協調。
  • 長時間執行的作業。
    • 批次作業、單一指令多個數據 (SIMD) 工作。
    • 這取決於應用程式的需求,而且可能適合 Orleans。

穀物概覽

  • 穀粒看起來像物品。 不過,它們是分散的、虛擬的和非同步的。
  • 它們鬆散結合,孤立,主要是獨立。
    • 每個粒子都被封裝,並且其狀態可以獨立於其他粒子維持。
    • 顆粒會獨立出現故障。
  • 避免粒紋之間的閒聊通訊。
    • 直接記憶體使用的成本明顯低於訊息傳遞。
    • 非常活潑的穀物可能更適合結合成單一穀物。
    • 必須考慮參數和序列化的複雜性和大小。
    • 反序列化兩次的代價可能比重新傳送二進位訊息更高。
  • 避免瓶頸的穀物。
    • 單一協調器/資料庫/監控器。
    • 如有需要,請執行分段匯總。

非同步性

  • 沒有執行緒阻塞:所有項目都必須是非同步(工作非同步編程(TAP))。
  • await 是撰寫異步作業時要使用的最佳語法。
  • 常見案例:
    • 傳回具體值:

    • return Task.FromResult(value);

    • 傳回相同類型的Task

    • return foo.Bar();

    • awaitTask 繼續執行:

      var x = await bar.Foo();
      
      var y = DoSomething(x);
      
      return y;
      
    • 展開:

      var tasks = new List<Task>();
      
      foreach (var grain in grains)
      {
          tasks.Add(grain.Foo());
      }
      await Task.WhenAll(tasks);
      
      DoMoreWork();
      

穀物的實施

  • 絕對不要在粒紋內執行線程封鎖作業。 本地計算以外的所有作業都必須是明確的異步操作。
    • 範例:同步等候輸入輸出操作或網路服務呼叫、鎖定、執行等待條件的過長迴圈等等。
  • 使用 StatelessWorkerAttribute時機:
    • 功能作業,例如解密、解壓縮,以及轉送之前的處理。
    • 在多次激活中只需要 本地 穀物時。
    • 範例:先在本機管道內執行階段性聚合。
  • 根據預設,粒子非重入。
    • 死結可能會因為呼叫周期而發生。
    • 範例:
    • 谷物自有其特質。
    • Grain A 呼叫 B,B 呼叫 C,C 接著呼叫 A (A -> B -> C -> A)。
    • 穀物 A 呼叫穀物 B,同時穀物 B 也在呼叫穀物 A (A -> B -> A)。
    • 超時設定用來自動解除死結。
    • ReentrantAttribute 可用來允許粒紋類別重新進入。
    • 不過,重新進入仍然是單個線程,但它可能會交錯(在工作之間分割處理/記憶體)。
    • 處理交錯會增加容易出錯的風險。
  • 遺產:
    • Grain 類別繼承自基底類別。 晶粒介面(一或多個)可以新增到每個晶粒。
    • 可能需要釐清,才能在多個粒紋類別中實作相同的介面。
  • 支援泛型。

粒子狀態保持性

Orleans' 粒紋狀態持續性 API 的設計目的是方便使用,並提供可延伸的儲存功能。

  • Orleans.IGrainState 是由包含應在穀物物件的持久狀態中保存字段的 .NET 介面擴充而成。
  • 使用 IPersistentState< TState > 來持久化 Grain,由 Grains 類別透過擴展在基類中新增強類型的State屬性來實現。
  • 初始Grain<TGrainState>.ReadStateAsync()會在呼叫ActiveAsync()粒子之前自動發生。
  • 當粒紋的狀態物件資料變更時,粒紋應該呼叫 Grain<TGrainState>.WriteStateAsync()
    • 一般而言,通常在 grain 方法的結尾呼叫 State.WriteStateAsync() 來傳回 Write 承諾。
    • 儲存提供者 可以 嘗試批次寫入以提升效率,但行為協議和組態與單元所使用的儲存 API 是獨立的(正交)。
    • 定時器是定期寫入更新的替代方法。
    • 定時器可讓應用程式判斷允許的「最終一致性」/無狀態數量。
    • 時間(立即/無/分鐘)也可以控制何時更新。
    • PersistentStateAttribute 裝飾類別與其他粒紋類別一樣,只能與一個儲存提供者相關聯。
    • StorageProvider(ProviderName = “name”) 屬性會將粒紋類別與特定提供者產生關聯。
    • <StorageProvider> 必須新增至 silo 組態檔,其中也應包含來自 [StorageProvider(ProviderName="name")] 的對應名稱。

儲存體提供者

內建記憶體提供者:

  • Orleans.Storage 包含所有內建的儲存提供者。

  • MemoryStorage (儲存在記憶體中的數據沒有持久持續性) 僅用於 偵錯和單元測試。

  • AzureTableStorage:

    • 使用選擇性 AzureTableStorageOptions.DeleteStateOnClear 的(硬式或虛刪除)設定 Azure 記憶體帳戶資訊。
    • Orleans 串行化程式有效率地將 JSON 資料儲存在一個 Azure 資料表數據格中。
    • 數據大小限制 == Azure 數據行的大小上限,也就是 64 kb 的二進位數據。
    • 社群貢獻的程式碼擴充了多個資料表欄位的使用,將整體最大大小增加到 1MB。

記憶體提供者偵錯秘訣

  • TraceOverride Verbose3 將會記錄記憶體作業的詳細資訊。
    • 更新silo組態檔。
    • 所有提供者的LogPrefix=“Storage”,或使用 “Storage.Memory” / “Storage.Azure” / “Storage.Shard” 的特定類型。

如何處理記憶體作業失敗:

  • 穀物和儲存提供者可以根據需要等候儲存作業,在失敗時進行重試。
  • 未處理的失敗將傳回給呼叫者,客戶端會將其視為未履行的 Promise。
  • 除了初始讀取之外,沒有一個概念會在記憶體作業失敗時自動終結啟用。
  • 重試發生故障的儲存空間不是內建儲存提供者的預設功能。

穀物持續性秘訣

晶粒大小:

  • 透過使用 多個較小的粒子 而不是幾個較大的粒子來達成最佳輸送量。 不過,選擇粒紋大小和類型的最佳做法是以 應用程式域模型為基礎。
    • 範例:用戶、訂單等。

外部動態數據:

  • Grains 可以使用 State.ReadStateAsync() 從儲存中重新讀取目前的狀態數據。

  • 定時器也可以用來定期從記憶體重新讀取數據。

    • 功能需求可能基於資訊的適當「陳舊性」。
    • 範例:內容快取粒度。
  • 新增和移除欄位。

    • 記憶體提供者會決定新增和移除其他欄位對其持久化狀態的影響。
    • Azure 數據表不支援結構,且應該會自動調整至新增的欄位。

撰寫自訂提供者:

  • 儲存提供者很容易撰寫,這也是 Orleans 的一個重要擴充元素。
  • API GrainState API 合約會驅動記憶體 API 合約 (Write、 、 ClearReadStateAsync)。
  • 記憶體行為通常是可設定的(批次寫入、硬式或虛刪除等等),並由記憶體提供者定義。

叢集管理

  • Orleans 會自動管理叢集。
    • 失敗的節點(也就是在任何時間都可能會失敗和加入的節點)會自動由 Orleans 處理。
    • 針對叢集協定建立的相同筒倉實例表也可用於診斷。 數據表會保留叢集中所有尋址接收器的歷程記錄。
    • 也有積極或更寬鬆的失敗偵測組態選項。
  • 失敗可以隨時發生,而且是正常發生的。
    • 在穀倉失效時,失效穀倉上啟動的穀物將自動在集群內其他穀倉上重新啟動。
    • 顆粒可能會超時。 例如 Polly 的重試解決方案可協助重試。
    • Orleans 提供訊息傳遞保證,其中每個訊息最多一次傳遞。
    • 呼叫者有責任視需要 重試 任何失敗的呼叫。
    • 常見做法是從用戶端/前端從端對端重試。

部署和生產管理

向外擴展和向內縮減:

  • 監視 Service-Level 合約 (SLA)
  • 新增或移除實例
  • Orleans 會自動重新平衡並利用新的硬體。 不過,當新的筒倉新增至叢集時,啟動的穀粒不會重新平衡。

記錄和測試

  • 記錄、追蹤和監視:
    • 使用相依性注入來記錄日誌

      public HelloGrain(ILogger<HelloGrain> logger)
      {
          _logger = logger;
      }
      
    • Microsoft.Extensions.Logging 用於提供功能性和靈活性的日誌記錄。

正在測試:

  • Microsoft.Orleans.TestingHost NuGet 套件包含 TestCluster 可用來建立記憶體內部叢集,預設由兩個尋址接收器組成,可用來測試粒紋。
  • 如需詳細資訊,請參閱使用 Orleans進行單元測試

疑難排解:

  • 使用 Azure 資料表型成員資格進行開發和測試。
    • 使用 Azure 記憶體模擬器進行本機疑難解答。
    • OrleansSiloInstances 數據表會顯示叢集的狀態。
    • 使用唯一的部署ID(分割區索引鍵)以簡化過程。
  • Silo 未啟動。
    • 檢查 OrleansSiloInstances 以判斷該伺服器實例是否已在那裡註冊。
    • 請確定已針對 TCP 埠開啟防火牆:11111 和 30000。
    • 檢查記錄,包括包含啟動錯誤的額外記錄。
  • 前端 (用戶端) 無法連線到尋址接收器叢集。
    • 用戶端必須裝載在與儲存體相同的服務中。
    • 檢查 OrleansSiloInstances 以確保數據筒倉(閘道)已註冊。
    • 檢查客戶端記錄檔,以確定閘道符合 OrleansSiloInstances 數據表中列出的閘道。
    • 檢查客戶端記錄檔,以驗證用戶端是否能夠連線到一或多個閘道。