- 颗粒(Grains)
- Orleans运行时(Orleans Runtime)
- 功能
- 持久化(Persistence)
- 分布式ACID事务(Distributed ACID Transactions)
- 流(Stream)
- 定时器 & 提醒器(Timers & Reminders)
- 灵活的Grain放置(Flexible Grain Placement)
- Grain版本控制 & 异构集群(Grain Versioning & Heterogeneous Cluster)
- 弹性伸缩 & 容错(Elastic Scalability & Fault Tolerance)
- 跨平台运行(Run Anywhere)
- 无状态Worker(Stateless Workers)
- Grain调用过滤器(Grain Call Filters)
- 请求上下文(Request Context)
- 开始吧
- 官方编译
- 社区
- License
- 相关链接
- Orleans起源
Orleans是一个用于构建健壮的、可扩展的分布式应用的跨平台框架。
Orleans将.NET开发者生产力带入了分布式应用的世界,如云服务。Orleans可以将单一的本地部署的服务,扩展为部署在云端的全球分布的、高可用的应用。
Orleans使用了objects、interfaces、async/await以及try/catch等常用的概念,并将它们扩展到多服务器环境上。如此以来,Orleans能帮助那些只有单服务器应用开发经验的开发者,过渡到构建弹性的、可伸缩的云服务和其他分布式应用上。因此,Orleans通常被称为“分布式的.NET”。
该框架由Microsoft Research创建,引进了Virtual Actor Model这一用于构建云时代的新一代分布式系统的新颖方法。Orleans的核心贡献在于它的编程模型,该模型驯服了高度并行的分布式系统固有的复杂性,且不会限制应用的能力,不会对开发者施加繁重的约束(对开发者的要求也没那么高)。
颗粒(Grains)
所有Orleans应用的基本构建模块被称为颗粒(Grain)。Grain即由用户自定义标识(user-defined identity)、行为(behaviour)和状态(state)组成的实体。Grain标识是用户定义的key,使Grain始终处于可调用的状态。Grain可以被其他Grain或外部客户端(如web前端)通过强类型的接口(协议)来调用。每个Grain都是实现了一个或多个这些接口的类的实例。
Grain可以在任何存储系统中,存储其易变性(volatile)和/或持久性(persistent)的状态。如此,Grain隐式地对应用的状态进行了分区,从而实现了自动伸缩,并简化了从故障中恢复的过程。当Grain处于active状态时,其状态会保存在内存中,从而降低获取的延时,并减少数据存储负载。
Orleans运行时(Orleans Runtime)会根据需要自动实例化Grain。一段时间没有被使用的Grain会被自动从内存中移除以释放资源。得益于无论当前Grain是否被加载到了内存里,Orleans都允许通过Grain标识去调用Grain。这个机制也支持故障自动恢复,因为无论何时,调用方不必知道Grain有没有实例化,在哪个服务器上做的实例化。Grain的生命周期由Orleans运行时托管,Orleans运行时负责activating/deactivating这些Grain,并根据需要放置(placing)/定位(locating)这些Grain。允许开发者在写代码时就认为所有Grain一直都在内存里。
总而言之,Grain的以下特性保证了Orleans框架开发的应用具有可伸缩性,可靠性以及较高的性能,同时也不需要开发者为了系统支持分布式而编写复杂的代码:
- 稳定的标识;
- 有状态;
- 生命周期被托管。
示例:物联网云后端
考虑实现一个物联网系统的云后端。该程序需要处理从设备传过来的数据,进行过滤、聚合、汇总等,还需要支持向设备发送命令。在Orleans框架下,可以很自然地用Grain对每个物联网设备进行建模,Grain与它对应的物联网设备就像数字孪生兄弟(digital twin)一样。Grain会将相应设备的最新数据存放在内存中,便于快速查询和处理这些数据,而无需直接与物联网设备进行通信。通过观察和分析设备的时序数据流,Grain可以通过检测设备状态或条件的变化(如测量值超过某个阈值)来触发某个特定的动作。
这就对恒温器建立一个简单的模型:
public interface IThermostat : IGrainWithStringKey
{
Task<List<Command>> OnUpdate(ThermostatStatus update);
}
可通过调用OnUpdate
方法,将来自Web前端的恒温器触发的事件发送给相应的Grain,Grain可以生成一组命令,并可以将命令反馈给相应的物理设备:
var thermostat = client.GetGrain<IThermostat>(id);
return await thermostat.OnUpdate(update);
相同的恒温器Grain可以实现另外一个单独的接口,用于和控制系统进行交互:
public interface IThermostatControl : IGrainWithStringKey
{
Task<ThermostatStatus> GetStatus();
Task UpdateConfiguration(ThermostatConfiguration config);
}
用一个类来实现IThermostat
和IThermostatControl
这两个接口:
public class ThermostatGrain : Grain, IThermostat, IThermostatControl
{
private ThermostatStatus _status;
private List<Command> _commands;
public Task<List<Command>> OnUpdate(ThermostatStatus status)
{
_status = status;
var result = _commands;
_commands = new List<Command>();
return Task.FromResult(result);
}
public Task<ThermostatStatus> GetStatus() => Task.FromResult(_status);
public Task UpdateConfiguration(ThermostatConfiguration config)
{
_commands.Add(new ConfigUpdateCommand(config));
return Task.CompletedTask;
}
}
在这个例子中,Grain类没有保存状态。关于更详细的状态持久化的例子,可以看这篇文档。
Orleans运行时(Orleans Runtime)
Orleans运行时为应用开发实现了Orleas程序的编程模型。运行时的主要组件为筒仓(Silo),是托管Grain的仓储。通常,一组筒仓以集群的方式运行,以实现可伸缩性和容错机制。作为集群运行时,筒仓之间彼此协调分配工作,检测并从故障中恢复。Orleans运行时能使在集群中托管的Grain能够像在同一个单一进程中一样彼此相互通信。
除了核心编程模型之外,筒仓还为Grain提供一组运行时服务,如计时器、提醒器(持久化的计时器)、持久化、事务、流等。详情见下面的功能小节。
Web前端及其他外部客户端通过客户端类库调用集群中的Grain,客户端类库自动管理网络通信。更简单的方式是,客户端和筒仓被托管到同一个进程中去。
Orleans兼容.NET Standard 2.0及以上版本。能够在装有.NET Framework(仅支持Windows)或.NET Core的Windows、Linux和macOS上运行。
功能
持久化(Persistence)
Orleans提供了一个简单的持久化模型。该模型可以确保在处理请求之前,Grain是可用的状态,并能维护不同请求处理过程中使用的相同标识的Grain一致性。Grain可以拥有多个已命名的持久化数据对象,例如,一个保存了用户档案的对象被命名为“profile”,另一个保存了库存清单的对象名为“inventory”。状态可以存储在任何存储系统中,即用户档案和库存清单可以被存储在不同的数据库中。当Grain在运行状态中(应该是说activating时,原文写的是running)时,状态是保持在内存中的,所以处理读取请求时无需访问存储。当Grain的状态需要更新时,调用state.WriteStateAsync()
就可以确保其背后的存储可以得到更新,以此实现持久化和一致性。详情见Grain持久化文档。
分布式ACID事务(Distributed ACID Transactions)
除上述简单的持久化模型外,Grain还支持事务性状态(transactional state)。多个Grain,无论它们的状态实际上存储在哪里,都可以参与到同一个ACID事务中。Orleans的事务是分布式的,去中心化的(即不存在中心化的事务管理器或事务协调器),且支持串行化隔离(serializable isolation)#Isolation_levels)*。关于Orleans事务的详情,见这个文档和这篇论文。
*:数据库一共定义了四种隔离级别,其中串行化隔离是隔离级别最高的,可避免脏读、不可重复读、虚读等情况。
流(Stream)
流可帮助开发者近乎实时地去处理连续的数据。在Orleans中,流是被托管的:Grain或客户端在发布或订阅流之前,无需创建或注册流。这就使得流的生产者、消费者以及代码的基础设施层三者之间耦合度很低。流处理是可靠的:Grain可以存储检查点(checkpoint)(游标),可以在激活期间或之后的任何时间被重置到某个存储过的检查点。流支持向消费者传输批量消息,可以提高传输效率和恢复能力。流处理机制由Azure Event Hubs、Amazon Kinesis或其他类型的队列服务(queueing service)作为制成。任意多个流可以多路复用到数量较少的队列上,并在整个集群中均衡地处理这些数据。
定时器 & 提醒器(Timers & Reminders)
提醒器是Grain的一种持久调度机制(durable scheduling mechanism)。通过使用提醒器,我们可以保证未来能够完成一些操作,哪怕此时此刻Grain还没有被激活。定时器是不被持久化的提醒器,可被用于处理对可靠性要求不高的、频繁出现的事件。详情见调度机制文档。
灵活的Grain放置(Flexible Grain Placement)
当Orleans激活一个Grain时,运行时会决定在哪个服务器(筒仓)上进行激活。这个过程叫做Grain放置。Orleans的放置机制是完全可配置的:开发者可以直接从一组开箱即用的放置策略中选择一种策略,如随机、本地优先、基于负载,也可以配置自定义逻辑。这就使得Grain的放置非常具有灵活性。例如,Grain可以被放置在距离它所操作的资源较近的服务器上,或者它需要进行通讯的其他Grain的服务器上。详情见Grain放置文档。
Grain版本控制 & 异构集群(Grain Versioning & Heterogeneous Cluster)
应用的代码终究会随着时间和业务升级而更新变化,如何将这些变化安全又快捷地升级到生产系统,是一项很大的挑战,特别是在有状态的系统中。在Orleans中,Grain接口支持版本控制。集群会维护一张映射表,记录了哪些Grain的实现对于哪些筒仓是可用的,以及这些实现的版本信息。Orleans运行时会根据这个版本信息与Grain放置策略,结合二者,在路由调用Grain时,做出合适的放置决策。除了支持Grain版本控制,Orleans还支持异构集群。不同的筒仓可以用不同的Grain实现集。详情见Grain版本控制文档。
弹性伸缩 & 容错(Elastic Scalability & Fault Tolerance)
Orleans在设计时就已充分考虑可伸缩性。当有一个新的筒仓加入集群时,Orleans会根据需要去激活它。当某个筒仓由于某个原因(系统规模缩减或节点故障)而需要从集群中移除时,当前筒仓上的Grain会在集群的其他筒仓上被按需重新激活。一个Orleans集群的规模可以被缩小到只有一个单一的筒仓。Orleans支持可伸缩性的同时,也支持容错性:Orleans集群会自动检测各个筒仓是否发生了故障,并让它们快速从故障中恢复。
跨平台运行(Run Anywhere)
Orleans可以运行在任何支持.NET Core或.NET Framework的系统上,包括Windows、Linux、macOS,并支持部署到K8s、虚拟或物理主机,本地或云端,以及PaaS服务如Azure Cloud服务。
无状态Worker(Stateless Workers)
无状态Worker是一种被特殊标记的Grain,这些Grain没有任何关联状态,可以同时被多个筒仓激活。这样就可以提高无状态函数(stateless function)的并行性。详情见无状态Worker颗粒文档。
Grain调用过滤器(Grain Call Filters)
Grain调用过滤器是指多个Grain共同拥有的逻辑。Orleans支持传入和传出调用过滤器。常用的过滤器例子有:授权,日志,遥测,错误处理,等等。
(实际上就是AOP。)
请求上下文(Request Context)
元数据和其他信息可以使用请求上下文在一系列的请求中传递。请求上下文可被用来托管分布式跟踪信息或任何用户定义的值。
开始吧
从入门教程开始。
构建项目
Windows上,运行build.cmd
脚本在本地编译NuGet包,然后从/Artifacts/Release/*
引用NuGet包。可以运行Test.cmd
来执行所有BVT(版本验证测试)测试用例,运行TestAll.cmd
来执行所有功能性测试。
Linux和macOS上,运行build.sh
脚本或dotnet build ./OrleansCrossPlatform.sln
来构建Orleans。
官方编译
最近的稳定的、生产环境适用的版本在这里。
Nightly版本发布在https://dotnet.myget.org/gallery/orleans-ci。这些版本可以通过所有功能性测试,但是没有像稳定版或在NuGet上预发行的版本那么经过充分测试。
在项目中使用nightly构建包
如果要使用nightly构建包,用任意一种方法添加MyGet源:
在.csproj文件中添加这一段:
<RestoreSources>
$(RestoreSources);
https://dotnet.myget.org/F/orleans-ci/api/v3/index.json;
</RestoreSources>
在解决方案目录下新建一个名为NuGet.config的文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="orleans-ci" value="https://dotnet.myget.org/F/orleans-ci/api/v3/index.json" />
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>
社区
- 通过在GtiHub上开一个新issue或在Stack Overflow上开一个新问题来提问。
- 在Gitter上聊天。
- Orleans博客。
- 关注推特@msftorleans。
- GitHub上的Orleans社区贡献页面,上面有很多社区项目,如监视器、设计模式、存储提供器等等。
- Orleans代码贡献规范。
License
MIT License
相关链接
- Microsoft Research project home
- 论文:Orleans: Distributed Virtual Actors for Programmability and Scalability
- Orleans官网
- 社区贡献相关
Orleans起源
Orleans是在Microsoft Research创建的,设计为在云端使用。自2011年始,已被多个微软的产品组广泛应用于云端和内部的产品,最知名的是游戏工作室,如Halo 4和5、Gears of War 4背后的343 Industries和The Coalition团队,还有一些其他公司。
2015年1月,Orleans开源,此后吸引了众多开发者,他们形成了.NET生态系统中最活跃的开源社区之一。在社区开发人员和微软Orleans团队的积极合作中,新增和改进的feature与日俱增。Microsoft Research也在继续与Orleans团队合作,推出新的重要功能,如地理分布、索引和分布式事务等,正在推动最新技术的发展。对于许多.NET开发人员而言,Orleans已是构建分布式系统和云服务的首选框架。