Orleans 本身的設(shè)計(jì)是一個(gè)分布式的框架,多個(gè) Silo 構(gòu)成集群,Grains 分布在多個(gè) Silo 中。一旦一個(gè) Silo 掛了,原來(lái)歸屬這個(gè) Silo 的 Grains 會(huì)自動(dòng)在其他 Silo 中激活。生產(chǎn)環(huán)境下還是需要以集群方式來(lái)部署。

在[ Orleans 解決并發(fā)之痛(二):Grain 狀態(tài)] (http://www.itdecent.cn/p/ccd9cffa77bf)文章中提到內(nèi)存存儲(chǔ)State是不靠譜的,同樣,以內(nèi)存方式存儲(chǔ)集群中 Silo 的成員關(guān)系也是不靠譜的,所以本文使用 SQL Server 來(lái)做 Silo 的成員關(guān)系存儲(chǔ),以內(nèi)存方式存儲(chǔ)成員關(guān)系存在主節(jié)點(diǎn)之說(shuō),其他節(jié)點(diǎn)的啟動(dòng)必須依賴主節(jié)點(diǎn)的啟動(dòng)狀態(tài),但以 Azure Table、SQL Server 、ZooKeeper、Consul 等存儲(chǔ)成員關(guān)系,所有的 Silo 都是平等的,不需要等待誰(shuí)。
之前在 Orleans 解決并發(fā)之痛(一):?jiǎn)尉€程 Demo 中是以內(nèi)存存儲(chǔ)集群成員關(guān)系的,有興趣可以返回查看。
這篇文章的 Demo 是 Orleans 解決并發(fā)之痛(二):Grain 狀態(tài) 的基礎(chǔ)上完成的,所以在原來(lái)代碼的基礎(chǔ)上做一些調(diào)整即可。我們會(huì)啟動(dòng)3個(gè) Silo,構(gòu)建成一個(gè)集群環(huán)境,實(shí)際上提供3個(gè)配置文件即可,配置文件稍做修改就可實(shí)現(xiàn)。
Silo 配置文件
OrleansConfiguration1.xml:
<?xml version="1.0" encoding="utf-8" ?>
<OrleansConfiguration xmlns="urn:orleans">
<Globals>
<SystemStore SystemStoreType="SqlServer"
DeploymentId="OrleansTest"
DataConnectionString="Server=.;Database=OrleansStorage;User ID=sa;Password=123456;" />
<StorageProviders>
<Provider Type="Orleans.Storage.AdoNetStorageProvider"
Name="OrleansStorage"
AdoInvariant="System.Data.SqlClient"
DataConnectionString="Server=.;Database=OrleansStorage;User ID=sa;Password=123456;" />
</StorageProviders>
</Globals>
<Defaults>
<Networking Address="localhost" Port="11111" />
<ProxyingGateway Address="localhost" Port="30000" />
</Defaults>
</OrleansConfiguration>
OrleansConfiguration2.xml 和 OrleansConfiguration3.xml 除了 Networking 、ProxyingGateway 配置有所區(qū)別,其他完全一樣。
OrleansConfiguration2.xml:
<Networking Address="localhost" Port="11112" />
<ProxyingGateway Address="localhost" Port="30001" />
OrleansConfiguration3.xml:
<Networking Address="localhost" Port="11113" />
<ProxyingGateway Address="localhost" Port="30002" />
這次配置文件中引入了一個(gè) SystemStore 節(jié)點(diǎn):
SystemStoreType:存儲(chǔ)的類型;如:AzureTable、SqlServer、ZooKeeper等;
DeploymentId:部署的唯一 Id 標(biāo)識(shí),具有相同的 DeploymentId 的 Silo 會(huì)加入一個(gè)集群中;
DataConnectionString:連接字符串;
3臺(tái) Silo 啟動(dòng)成功后,在 OrleansStorage 庫(kù)的 OrleansMembershipTable 表中會(huì)記錄下成員關(guān)系:

Client配置文件
ClientConfiguration.xml:
<?xml version="1.0" encoding="utf-8" ?>
<ClientConfiguration xmlns="urn:orleans">
<SystemStore SystemStoreType ="SqlServer"
DeploymentId="OrleansTest"
DataConnectionString="Data Source=.;Database=OrleansStorage;User ID=sa;Password=123456;"
AdoInvariant="System.Data.SqlClient" />
</ClientConfiguration>
Client 通過(guò) DeploymentId 標(biāo)識(shí)連接 Silo 集群。具體最終調(diào)用那個(gè) Silo 完成方法的調(diào)用,由其內(nèi)部調(diào)配。當(dāng)某一臺(tái) Silo 掛了,Grain 會(huì)重新在另一個(gè) Silo 上激活,達(dá)到高可用狀態(tài)。
Client 的測(cè)試代碼:
我們用一個(gè)死循環(huán),創(chuàng)建很多 Grain,來(lái)觀察 Silo 控制臺(tái)的輸出效果
var random = new Random();
while (true)
{
Thread.Sleep(1000);
var grainId = random.Next().ToString();
var grain = GrainClient.GrainFactory.GetGrain<IPersonGrain>("Test-" + grainId);
grain.SayHelloAsync();
}
測(cè)試結(jié)果:
從控制臺(tái)輸出結(jié)果來(lái)開(kāi),每臺(tái) Silo 上 Grain 的分配還是比較均勻的

當(dāng)殺掉一個(gè) Silo 后,服務(wù)依然是正常運(yùn)行,具體 Grain 是否重新被分配有興趣可以測(cè)試一下:
