如何评价微软的orleans框架

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何评价微软的orleans框架相关的知识,希望对你有一定的参考价值。

参考技术A Orleans相比于Akka家族这些Actor框架而言有几大特点:
Virtual Actors: 当你在上层编程的时候,你可以永远假设和你通讯的Actor是活着的,这对于大大简化应用层的逻辑,不言而喻。
Production ready:微软用Orleans基本上实现了Xbox几个核心游戏的后端(Halo,战争机器4等等),这些后端集群规模据我所知远远大于现在任何Akka的产业界部署。
Performance: 在提供了Virtual Actor这个概念和高度Scalability的条件下,Orleans依然可以达到相对的高性能,低延迟,这个还是很令人吃惊的。当然了,这里面有一部分原因是C#的具有非常好的Code-Generation以及和C#/C++ Interplay的能力,从而让Orleans的序列化,数据处理等瓶颈模块上有相对好的性能表现。例如说,嵌入FlatBuffer这种下一代序列化库很简单。
Active community: 据我所知,现在Orleans社区贡献的代码量已经超过50%了。一个活跃的社区说明了很多问题。Orleans是Github上第四火的.Net项目。
MIT License:这个可以说是最灵活的一个开源许可证,尤其是对于公司用户。

假如你试图写一个分布式中后端系统,并有以下的设计要求,那么Orleans会是一个不错的选项:
高可用(故障处理效率是可以调的系统参数)
高扩展(10s-1000s服务器)
相对低延迟(毫秒级别)
充分性能(100K左右的服务器消息吞吐量) - 在升级为DotNetty后将有潜力上升到1M级别。
云部署 - DotNet Core 1.0 RTM的支持很快实现。部署到Linux集群将很快成为现实。

Orleans框架------基于Actor模型生成分布式Id

一、Actor简介

actor模型是一种并行计算的数学模型。 响应于收到的消息,演员可以:做出决定,创建更多Actor,发送更多消息,并确定如何响应接收到的下一条消息。 演员可以修改自己的状态,但只能通过消息相互影响(避免需要任何锁)。

     actor是一个计算实体,当其收到消息时,可以并发执行如下操作:

   1. 发送有限数量的消息给其他actor

   2. 创建有限数量的新actor

   3. 指定收到下一消息时的行为

   在Orleans中使用的是虚拟Actor方式,详细:http://dotnet.github.io/orleans/Documentation/Introduction.html

    详细参见: https://en.wikipedia.org/wiki/Actor_model

 

二、Orleans框架

      Orleans是一个框架,可以直接构建分布式大规模计算应用程序,而无需学习和应用复杂的并发或其他缩放模式。 它是由Microsoft Research创建的,旨在用于云端。

Orleans已被Microsoft Azure广泛应用于微软的几个产品集团,其中最着名的是343个行业,作为所有Halo 4和Halo 5云服务的平台,以及越来越多的其他公司。

  特性:

    1、默认可扩展
           奥尔良处理构建分布式系统的复杂性,使您的应用程序能够扩展到数百台服务器。
    2、低延迟
           奥尔良允许您保持内存所需的状态,因此您的应用程序可以快速响应传入的请求。

    3、简化并发

          Orleans允许您编写简单的单线程C#代码,通过actor之间的异步消息传递来处理并发。

 

 

三、生成流水号项目实战

      1、场景

          现在系统基于分布式服务开发,数据在客户端处理后提交到服务端入库,但是由于多个系统间的并发而流水号全部在一张表,每次都是先select在update 高并发容易直接死锁。

     如图:

 

 

     2、基于Orleans的actor

        将每条数据改造成一个Actor,由个Actor之间的状态来保证流水号的递增,这样即使单个流水号访问量大只要扩展Orleans的soli即可。

 

四、关键代码:

         1、利用初始化SerialNumberStorgeProvider初始化管理Grain的状态

 

 

    
public class SerialNumberStorgeProvider : IStorageProvider { public Logger Log { get; set; } public string Name { get; set; } public Task ClearStateAsync(string grainType, GrainReference grainReference, IGrainState grainState) { return TaskDone.Done; } public Task Close() { return TaskDone.Done; } public Task Init(string name, IProviderRuntime providerRuntime, IProviderConfiguration config) { this.Name = nameof(SerialNumberStorgeProvider); this.Log = providerRuntime.GetLogger(this.Name); return TaskDone.Done; } public Task ReadStateAsync(string grainType, GrainReference grainReference, IGrainState grainState) { Console.WriteLine("获取种子信息"); var SerialNumber = grainReference.GetPrimaryKeyString(); using (var db = new DBContext()) { var query = db.SerialNumbers.AsNoTracking().FirstOrDefault(o => o.Name.Equals(SerialNumber)); if (query != null) grainState.State = query; else { db.SerialNumbers.Add(new SerialNumberInfo { Name = grainReference.GetPrimaryKeyString(), Number = 1 }); db.SaveChanges(); grainState.State = new SerialNumberInfo { Name = grainReference.GetPrimaryKeyString(), Number = 1 }; } } return TaskDone.Done; } public async Task WriteStateAsync(string grainType, GrainReference grainReference, IGrainState grainState) { var model = grainState.State as SerialNumberInfo; using (var db = new DBContext()) { var query = db.SerialNumbers.FirstOrDefault(o => o.Name.Equals(model.Name)); query.Number = model.Number; await db.SaveChangesAsync(); } } }

   

2、Grain获取流水号的实现  
[StorageProvider(ProviderName = "SerialNumberStorgeProvider")]
    public class SerialNumberGrain : Grain<SerialNumberInfo>, ISerialNumberGrain
    {
        /// <summary>
        /// 获取多个流水号
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        public Task<List<long>> GetMutilSerialNumber(int number)
        {
            if (number == 0) { number = 1; }

            List<long> list = new List<long>();
            for (int i = 1; i <= number; i++)
            {
                this.State.Number += 1;
                list.Add(this.State.Number);
            }
            this.WriteStateAsync();
            return Task.FromResult(list);
        }

        /// <summary>
        /// 获取单个流水号
        /// </summary>
        /// <returns></returns>
        public Task<long> GetSerialNumber()
        {
            this.WriteStateAsync();
            return Task.FromResult(this.State.Number);
        }
    }

 


最后,最多说一句,在测试的时候发现如果不适用如下这种方式,并发时会发生Task调度异常

 

 

源码地址:https://github.com/liyang-live/MakeSerialNumber

 

    参考资料:http://dotnet.github.io/orleans/index.html

                     http://www.cnblogs.com/joab/p/5657851.html

                     https://github.com/dotnet/orleans

以上是关于如何评价微软的orleans框架的主要内容,如果未能解决你的问题,请参考以下文章

Microsoft Orleans 之 入门指南

Orleans简介

Orleans的集群构建

Orleans框架-从示例代码开始

Orleans3.0

Orleans框架------基于Actor模型生成分布式Id