Orleans解决并发之痛(二):Grain状态
Grains是Orleans應(yīng)用程序的構(gòu)建塊,它們是彼此孤立的原子單位,分布的,持久的, 一個(gè)典型的Grain是有狀態(tài)和行為的一個(gè)單實(shí)例,每個(gè)Grain實(shí)例的在單線程內(nèi)執(zhí)行,Grain之間共享數(shù)據(jù)通過消息傳遞,Grains是由Silo自動(dòng)化管理。
Grain之間傳遞消息過程中也可能出現(xiàn)死鎖的情況,如:Grain A發(fā)送消息給Grain B,并等待它的完成,此時(shí)Grain B發(fā)送一個(gè)消息給Grain A,也等待其完成,這時(shí)候出現(xiàn)相互等待而造成死鎖。Orleans對(duì)Grain之間產(chǎn)生的死鎖問題解決也是非常簡(jiǎn)單的,只需要在Grain上加[Reentrant]屬性,具體可查看官方Concurrency。
Grain狀態(tài)有好幾種存儲(chǔ)方式,比如:AzureTableStorage、AzureBlobStorage、SQLStorage、MemoryStorage ?等,我們還可以自定義存儲(chǔ)。MemoryStorage在測(cè)試項(xiàng)目使用沒問題,但實(shí)際生產(chǎn)環(huán)境要使用其他持久存儲(chǔ)的方式,因?yàn)橐坏┮粋€(gè)Silo被關(guān)閉,內(nèi)存存儲(chǔ)的狀態(tài)將會(huì)消失。
在分布式下,State的使用可以減少很多對(duì)數(shù)據(jù)庫層面的壓力。當(dāng)然也不是所有的Grain都推薦使用State,還是看實(shí)際業(yè)務(wù)需求。我們可以想象一個(gè)場(chǎng)景,一個(gè)商品的庫存如果保存在State中,所有請(qǐng)求都共享這個(gè)State,在判斷是否有剩余商品的時(shí)候是不是就不需要每次都去查詢數(shù)據(jù)庫了?
定義接口
public interface IPersonGrain : IGrainWithStringKey {Task SayHelloAsync(); }實(shí)現(xiàn)接口
public class PersonGrain : Grain, IPersonGrain {public Task SayHelloAsync(){string primaryKey = this.GetPrimaryKeyString();Console.WriteLine($"{primaryKey} said hello!");return Task.CompletedTask;} }為了實(shí)現(xiàn)狀態(tài)存儲(chǔ),我們需要?jiǎng)?chuàng)建一個(gè)class:
public class PersonGrainState {public bool SaidHello { get; set; } }修改代碼,實(shí)現(xiàn)的PersonGrain不應(yīng)該再繼承Grain,而是Grain<T>
[StorageProvider(ProviderName = "OrleansStorage")] public class PersonGrain : Grain<PersonGrainState>, IPersonGrain {public async Task SayHelloAsync(){string primaryKey = this.GetPrimaryKeyString();bool saidHelloBefore = this.State.SaidHello;string saidHelloBeforeStr = saidHelloBefore ? " already" : null;Console.WriteLine($"{primaryKey}{saidHelloBeforeStr} said hello!");this.State.SaidHello = true;await this.WriteStateAsync();} }第一次調(diào)用這個(gè)方法的時(shí)候this.State.SaidHello為false,輸出'xxx said hello!'。然后我們通過WriteStateAsync修改SaidHello為true,當(dāng)?shù)诙伪徽{(diào)用的時(shí)候,從State里取出的SaidHello已經(jīng)變成了true,則輸出'xxx already said hello!'
Orleans 提供了非常簡(jiǎn)單的API來處理持久化裝狀態(tài),看方法名就知道什么啥意思了,WriteStateAsync()、ReadStateAsync() 、 ClearStateAsync()。
同時(shí)在PersonGrain加了一個(gè)StorageProvider屬性,參數(shù)ProviderName賦值為OrleansStorage,這里需要對(duì)Silo的配置文件(OrleansConfiguration.xml)做調(diào)整,添加StorageProviders配置,Type表示存儲(chǔ)方式,Name表示名稱,程序內(nèi)指定的ProviderName需要和配置中這個(gè)名稱保持一致。
注意:
當(dāng)Name為Default時(shí),如果某個(gè)Grain使用Default來存儲(chǔ),可以不需要加StorageProvider屬性。StorageProviders下可以有多個(gè)Provider,每個(gè)Provider的Type可以不一樣,每個(gè)Grain指定的存儲(chǔ)方式也可以不一樣,ProviderName指定是誰就用誰存儲(chǔ)。
為了驗(yàn)證Grain之間是獨(dú)立的,在Client加入以下代碼:
var joe = GrainClient.GrainFactory.GetGrain<IPersonGrain>("Joe"); joe.SayHelloAsync(); joe.SayHelloAsync();var sam = GrainClient.GrainFactory.GetGrain<IPersonGrain>("Sam"); sam.SayHelloAsync(); sam.SayHelloAsync();測(cè)試結(jié)果:
Test Result
SQL Server 持久存儲(chǔ)State
上面提到State以內(nèi)存存儲(chǔ)的方式并不適合生產(chǎn)環(huán)境,那下面我們使用SQL Server來實(shí)現(xiàn)。
在Silo程序集中安裝依賴包:
Install-Package Microsoft.Orleans.OrleansSqlUtils Install-Package System.Data.SqlClient創(chuàng)建數(shù)據(jù)庫和表:
在SQL Server中創(chuàng)建一個(gè)數(shù)據(jù)庫,命名如:OrleansStorage(隨意);
在解決方案下找到目錄:packages\Microsoft.Orleans.OrleansSqlUtils.1.5.0\lib\net461\SQLServer,目錄下有一個(gè).sql文件,在OrleansStorage數(shù)據(jù)庫下執(zhí)行這個(gè)sql腳本即可;
修改OrleansConfiguration.xml的StorageProviders節(jié)點(diǎn)為:
<StorageProviders><Provider Type="Orleans.Storage.AdoNetStorageProvider"Name="OrleansStorage"AdoInvariant="System.Data.SqlClient"DataConnectionString="Server=.;Database=OrleansStorage;User ID=sa;Password=123456;"/> </StorageProviders>
重新啟動(dòng)Silo和Client:
執(zhí)行完成后查看數(shù)據(jù)庫中表Storage的內(nèi)容,數(shù)據(jù)的值是二進(jìn)制是方式存儲(chǔ)。
storage
之后不管重啟多少次,輸出的結(jié)果都是 "xxx already saild hello!" 。
參考鏈接:
Actor模型
Orleans
案例Demo-OrleansState
相關(guān)文章:?
.NET的Actor模型:Orleans
微軟分布式云計(jì)算框架Orleans(1):Hello World
微軟分布式云計(jì)算框架Orleans(2):容災(zāi)與集群(1)
Aaron Stannard談Akka.NET 1.1
使用Akka.net開發(fā)第一個(gè)分布式應(yīng)用
Orleans入門例子
Orleans例子再進(jìn)一步
Orleans稍微復(fù)雜的例子—互動(dòng)
Orleans簡(jiǎn)單配置
Orleans配置---持久化
Orleans—一些概念
Orleans的集群構(gòu)建
Oleans集群之Consul再解釋
Orleans解決并發(fā)之痛(一):單線程
原文地址:http://www.jianshu.com/p/ccd9cffa77bf
.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺(tái)或掃描二維碼關(guān)注
總結(jié)
以上是生活随笔為你收集整理的Orleans解决并发之痛(二):Grain状态的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2017(深圳) .NET技术分享交流会
- 下一篇: ASP.NET Core 运行原理解剖[