Orleans解决并发之痛(二):Grain状态
Grains是Orleans应用程序的构建块,它们是彼此孤立的原子单位,分布的,持久的, 一个典型的Grain是有状态和行为的一个单实例,每个Grain实例的在单线程内执行,Grain之间共享数据通过消息传递,Grains是由Silo自动化管理。
Grain之间传递消息过程中也可能出现死锁的情况,如:Grain A发送消息给Grain B,并等待它的完成,此时Grain B发送一个消息给Grain A,也等待其完成,这时候出现相互等待而造成死锁。Orleans对Grain之间产生的死锁问题解决也是非常简单的,只需要在Grain上加[Reentrant]属性,具体可查看官方Concurrency。
Grain状态有好几种存储方式,比如:AzureTableStorage、AzureBlobStorage、SQLStorage、MemoryStorage 等,我们还可以自定义存储。MemoryStorage在测试项目使用没问题,但实际生产环境要使用其他持久存储的方式,因为一旦一个Silo被关闭,内存存储的状态将会消失。
在分布式下,State的使用可以减少很多对数据库层面的压力。当然也不是所有的Grain都推荐使用State,还是看实际业务需求。我们可以想象一个场景,一个商品的库存如果保存在State中,所有请求都共享这个State,在判断是否有剩余商品的时候是不是就不需要每次都去查询数据库了?
定义接口
public interface IPersonGrain : IGrainWithStringKey
{Task SayHelloAsync();
}
实现接口
public class PersonGrain : Grain, IPersonGrain
{public Task SayHelloAsync(){string primaryKey = this.GetPrimaryKeyString();Console.WriteLine($"{primaryKey} said hello!");return Task.CompletedTask;}
}
为了实现状态存储,我们需要创建一个class:
public class PersonGrainState
{public bool SaidHello { get; set; }
}
修改代码,实现的PersonGrain不应该再继承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();}
}
第一次调用这个方法的时候this.State.SaidHello为false,输出'xxx said hello!'。然后我们通过WriteStateAsync修改SaidHello为true,当第二次被调用的时候,从State里取出的SaidHello已经变成了true,则输出'xxx already said hello!'
Orleans 提供了非常简单的API来处理持久化装状态,看方法名就知道什么啥意思了,WriteStateAsync()、ReadStateAsync() 、 ClearStateAsync()。
同时在PersonGrain加了一个StorageProvider属性,参数ProviderName赋值为OrleansStorage,这里需要对Silo的配置文件(OrleansConfiguration.xml)做调整,添加StorageProviders配置,Type表示存储方式,Name表示名称,程序内指定的ProviderName需要和配置中这个名称保持一致。
注意:
当Name为Default时,如果某个Grain使用Default来存储,可以不需要加StorageProvider属性。StorageProviders下可以有多个Provider,每个Provider的Type可以不一样,每个Grain指定的存储方式也可以不一样,ProviderName指定是谁就用谁存储。
<?xml version="1.0" encoding="utf-8" ?>
<OrleansConfiguration xmlns="urn:orleans"><Globals><SeedNode Address="localhost" Port="11111" /><StorageProviders><Provider Type="Orleans.Storage.MemoryStorage"Name="OrleansStorage" /></StorageProviders></Globals><Defaults><Networking Address="localhost" Port="11111" /><ProxyingGateway Address="localhost" Port="30000" /></Defaults>
</OrleansConfiguration>
为了验证Grain之间是独立的,在Client加入以下代码:
var joe = GrainClient.GrainFactory.GetGrain<IPersonGrain>("Joe");
joe.SayHelloAsync();
joe.SayHelloAsync();var sam = GrainClient.GrainFactory.GetGrain<IPersonGrain>("Sam");
sam.SayHelloAsync();
sam.SayHelloAsync();
测试结果:
Test Result
SQL Server 持久存储State
上面提到State以内存存储的方式并不适合生产环境,那下面我们使用SQL Server来实现。
在Silo程序集中安装依赖包:
Install-Package Microsoft.Orleans.OrleansSqlUtils
Install-Package System.Data.SqlClient
创建数据库和表:
在SQL Server中创建一个数据库,命名如:OrleansStorage(随意);
在解决方案下找到目录:packages\Microsoft.Orleans.OrleansSqlUtils.1.5.0\lib\net461\SQLServer,目录下有一个.sql文件,在OrleansStorage数据库下执行这个sql脚本即可;
修改OrleansConfiguration.xml的StorageProviders节点为:
<StorageProviders><Provider Type="Orleans.Storage.AdoNetStorageProvider"Name="OrleansStorage"AdoInvariant="System.Data.SqlClient"DataConnectionString="Server=.;Database=OrleansStorage;User ID=sa;Password=123456;"/>
</StorageProviders>
重新启动Silo和Client:
执行完成后查看数据库中表Storage的内容,数据的值是二进制是方式存储。
storage
之后不管重启多少次,输出的结果都是 "xxx already saild hello!" 。
参考链接:
Actor模型
Orleans
案例Demo-OrleansState
相关文章:
.NET的Actor模型:Orleans
微软分布式云计算框架Orleans(1):Hello World
微软分布式云计算框架Orleans(2):容灾与集群(1)
Aaron Stannard谈Akka.NET 1.1
使用Akka.net开发第一个分布式应用
Orleans入门例子
Orleans例子再进一步
Orleans稍微复杂的例子—互动
Orleans简单配置
Orleans配置---持久化
Orleans—一些概念
Orleans的集群构建
Oleans集群之Consul再解释
Orleans解决并发之痛(一):单线程
原文地址:http://www.jianshu.com/p/ccd9cffa77bf
.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注
Orleans解决并发之痛(二):Grain状态相关推荐
- Orleans解决并发之痛(五):Web API
通过前面几篇文章的介绍,可能会疑问怎么在实际开发中调用Grain,之前Demo的Client都是基于控制台应用程序,实际开发下可能是基于Web Form.Web API.MVC......,由于一时短 ...
- Orleans解决并发之痛(四):Streams
Orleans 提供了 Stream扩展编程模型.此模型提供了一套API,使处理流更简单和更健壮.Stream默认提供了两种Provider,不同的流类型可能使用不同的Provider来处理,Simp ...
- Orleans解决并发之痛(三):集群
Orleans本身的设计是一个分布式的框架,多个Silo构成集群,Grains分布在多个Silo中.一旦一个Silo挂了,原来归属这个Silo的Grains会自动在其他Silo中激活.生产环境下还是需 ...
- Orleans解决并发之痛(一):单线程
程序在运行过程中有时会莫名其妙出现代码的某些约束或者执行结果和理想状况不一样,正常逻辑怎么会出现这样的情况?到底发生了什么?好像见了鬼!瞬间好无助. 谁来救救我 大多数出现正常逻辑很难解释的时候,我们 ...
- 开发之痛:稳定的测试环境,怎么就那么难
简介:开发之痛:稳定的测试环境,怎么就那么难.对于生产环境,准确.稳定最重要,我们推荐以应用为中心的基于OAM和IaC的实践方式:对于测试环境,隔离.低成本和稳定的依赖是最重要的,我们推荐基于稳定环境 ...
- Nginx 解决WebApi跨域二次请求以及Vue单页面问题
Nginx 解决WebApi跨域二次请求以及Vue单页面问题 参考文章: (1)Nginx 解决WebApi跨域二次请求以及Vue单页面问题 (2)https://www.cnblogs.com/ji ...
- win7系统没有计算机睡眠状态,如何解决win7系统无法进入睡眠状态
在我们使用电脑的时候一般要是一段时间没有去动电脑又不想繁琐的去开机的话,就会给电脑设置睡眠状态来节约电源,这样可以增加电脑使用的寿命,想必有很多的朋友们在安装了win7系统之后,会遇到系统没法进入睡眠 ...
- 锦囊妙计解决elasticsearch集群为red状态
如何是自己搭建的elasticsearch集群,其实是比较容易发生丢失分片的情况的. 1. 如果集群丢失了主分片 则直接呈现红色的健康状态 严重的会影响到对集群的写入,因为如果主分片丢了,但是集群的m ...
- 8-设计模式之行为型模式二(状态模式、观察者模式、中介者模式)
设计模式之行为型模式二(状态模式.观察者模式.中介者模式) 6.5 状态模式 6.5.1 概述 6.5.2 结构 6.5.3 案例实现 6.5.4 优缺点 6.5.5 使用场景 6.6 观察者模式 6 ...
最新文章
- HTML初级知识点总结(2)
- vs 设置调试路径为exe所在的路径
- vue+element-ui实现表格的增删改查
- C语言实现阿姆斯特朗数armstrong number算法(附完整源码)
- 猪年看猪,猪男猪女一共十个。
- MySQL学习笔记_1_MySQL数据库管理系统概述
- WPF 可触摸移动的ScrollViewer控件
- 员工激励手段1+1组合出击
- matlab中bitget函数用法_MATLAB基础函数命令
- 华为linux系统怎么安装爱奇艺,荣耀智慧屏X1怎么安装爱奇艺?怎么安装第三方软件?很简单...
- 剑指offer面试题06. 从尾到头打印链表(辅助栈法)
- python3之urllib代理池
- 微软软件开发技术二十年回顾
- Amnesia失忆症攻略(本篇+later+crowd)
- 短视频sdk:选择一个靠谱的短视频SDK 你需要了解这些
- 安卓广告机带4G一体开发
- WORD 毕设页眉页码目录标题 排版
- win10恢复经典开始菜单_Win10 10月更新发布!全新开始菜单来了,这次你敢更新吗...
- 视频如何加水印文字?
- excel隔行显示不同颜色
热门文章
- JQuery真的不难~第六回 JQ中的异步调用方式
- 解决iPhone网络软件在睡眠情况断线问题
- Xamarin效果第三篇之手机底部弹窗
- C sharp实例:华盾武器门数据接收和解析
- Id都是“とつくとき”这样的怎么爬,在线等,急
- 聊一聊Jmeter的参数化
- 在 .NET 6 Preview 3 ASP.NET Core 更新
- . NET5一出,. NET岗面试普遍喊难,真相是…
- .NET架构小技巧(6)——什么是好的架构
- Dotnet Core IHttpClientFactory深度研究