.NET分布式大规模计算利器-Orleans(一)
写在前面
Orleans是基于Actor模型思想的.NET领域的框架,它提供了一种直接而简单的方法来构建分布式大规模计算应用程序,而无需学习和应用复杂的并发或其他扩展模式。我在2015年下半年开始应用Orleans,当时公司的交易系统采用的架构就是基于Orleans框架的,其展现出来的高性能、高并发以及惊人的稳定性深深地吸引了我,也让我认识到了传统三层无状态架构的缺陷。本文主要关注Orleans的思想基础,Actor模型及其应用。
Orleans思想基础:Actor模型
传统三层无状态架构的缺陷
在讨论Actor模型之前,我们可以先讨论一下传统三层架构在当前高并发环境中所面临的尴尬境遇。
三层架构包括表示层、业务逻辑层或者叫做中间层、数据访问层(也就是存储层),其架构图如下所示:
正如我们在实践中所知道的那样,中间层和数据访问层在伸缩性方面有着很大的限制,同时存储层常常会成为系统的瓶颈,这就意味着整套系统也会因为存储层的限制而变得低效。通常的做法是在中间层与存储层中间加一层缓存逻辑出来,以提升系统性能,但是很快就会遇到存储层与缓存层的数据一致性问题,这无疑为开发人员和运维人员增加了额外的工作量。
试想一下,如果我们中间层本身就携带着状态或者简单来说中间层与缓存层是合二为一的,那么我们的系统性能是不是就提升了一个级别,答案是肯定的。那么该如何去做呢?那就是我们需要考虑使用另外一套系统设计架构:Actor模型。
Actor模型
Actor模型允许建立一个有状态的中间层,其内存级的读写性能和特定于相关领域的业务实体行为,确保了系统的高性能以及数据的一致性。Actor模型天然的拥有着面向对象的程序设计功能。在实践中我们应该把主要精力放到组件之间的消息传递,而不是对象的属性和内部行为。
Actor模型作为一种用于处理并发计算的数学模型,它将Actor对象用作并发计算的通用基元,它也是一种重要的软件设计思想,它在架构、设计、实现以及组件之间的消息传递方面有着非常好的应用,也更好的发挥了多核计算机的潜力。通过创建新的Actor对象,可以在计算操作的生命周期中以抽象方式提高系统的分布性。
Actor作为一种计算实体,它会对收到的消息做出回应,并且还会在内部做其他一些事情:
- 向其他Actor对象发送消息
- 创建一定数量的新Actor对象
- 设置对下一条消息做出的回应方式
下图展示了多种Actor模型的交互示例
Actor模型具有以下特点:
- 通过异步消息方式进行通信:使消息就像从一个Actor对象传输到了另一个Actor对象(通过MailBox交互,这跟CSP的通信模式完全不同,有兴趣的朋友可以自行查阅)
- 状态机:Actor模型支持有限状态机
- 独立性:多个Actor对象之间不会共享状态
- 无锁的并发处理方式:由于Actor不会共享状态,且在同一时刻只处理一条消息,因而无需使用锁策略,这极大的提高了Actor系统的性能
- 并行性:当顶级Actor将任务分拆后发送给多个下级Actor后,可以使用Actor模型的并行处理方式
- 位置透明:可以使用抽象引用表示Actor对象的地址
- Future/Promise对象:这是对异步操作的发送与接收方式,以表示异步操作的完成结果
Orleans对Actor的应用
Actor平台(例如Erlang和Akka)在简化分布式系统编程方面向前迈了一步。但是,由于提供的抽象和系统服务的水平相对较低,它们仍然使开发人员承担着许多分布式系统的复杂性。主要包括开发用于管理Actor的生命周期,处理分布式簇,处理Actor的失败和恢复,放置Actor以及由此产生的管理分布式资源的应用程序代码。要为应用程序中的这些问题构建正确的解决方案,这就开发人员的要求就非常高了,必须是分布式系统专家级别的。
为了减少这些问题的发生,Orleans框架引入了虚拟Actor的新型抽象,它解决了许多复杂的分布式系统问题,例如可靠性和分布式资源管理,从而使开发人员摆脱了那些麻烦。同时,Orleans运行时使应用程序能够获得高性能,可靠性和可伸缩性。
Orleans对Actor的实现特点:
- Orleans Actor无处不在:无法明确创建或销毁它。它的生命周期超越了其任何内存对象的生命周期,因此也超越了任何特定服务器的生命周期。
- Orleans Actor会自动实例化:如果没有Actor的内存实例,则发送给Actor的消息会促使在可用服务器上创建一个新实例。作为运行时资源管理的一部分,将自动回收未使用的Actor实例。Actor永远不会失败:如果服务器崩溃了,下一条发送给运行在故障服务器上的Actor的消息将会促使Orleans自动在另一台服务器上重新实例化该Actor ,从而无需应用程序来监督和显式重新创建已经挂掉的Actor。
- Actor实例的位置对于应用程序代码是透明的,从而大大简化了编程。
- Orleans可以自动创建同一个无状态Actor的多个实例,从而无缝扩展热门Actor。
虚拟Actor的引入,相当于为开发者提供了一个虚拟的内存空间,使开发人员可以调用系统中的任何角色,无论它是否存在于内存中。虚拟化依赖于从虚拟角色映射到当前运行的物理实例的间接寻址。运行时通过一个分布式目录支持间接寻址,该目录将Actor标识映射到其当前物理位置。Orleans通过使用该映射的本地缓存来最小化间接寻址的运行时开销。这个策略被证明是非常有效的。在我们的生产服务中,缓存命中率通常远远超过90%。
下图展示了微软对Orleans的应用
参考链接:https://www.microsoft.com/en-us/research/project/orleans-virtual-actors/
.NET分布式大规模计算利器-Orleans(一)的更多相关文章
- GPU---并行计算利器
转载请引用:GPU---并行计算利器 源于阿里巴巴CCO<猿来如此>分享 1 GPU是什么 如图1所示,这台PC机与普通PC机不同的是这里插了7张显卡,左下角是显卡,在中间的就是GPU芯片 ...
- BloomFilter–大规模数据处理利器(转)
BloomFilter–大规模数据处理利器 Bloom Filter是由Bloom在1970年提出的一种多哈希函数映射的快速查找算法.通常应用在一些需要快速判断某个元素是否属于集合,但是并不严格要求1 ...
- BloomFilter–大规模数据处理利器
转自: http://www.dbafree.net/?p=36 BloomFilter–大规模数据处理利器 Bloom Filter是由Bloom在1970年提出的一种多哈希函数映射的快速查找算法. ...
- BloomFilter ——大规模数据处理利器
BloomFilter——大规模数据处理利器 Bloom Filter是由Bloom在1970年提出的一种多哈希函数映射的快速查找算法.通常应用在一些需要快速判断某个元素是否属于集合,但是并不严格要求 ...
- 明风:分布式图计算的平台Spark GraphX 在淘宝的实践
快刀初试:Spark GraphX在淘宝的实践 作者:明风 (本文由团队中梧苇和我一起撰写,并由团队中的林岳,岩岫,世仪等多人Review,发表于程序员的8月刊,由于篇幅原因,略作删减,本文为完整版) ...
- JStorm 是一个分布式实时计算引擎
alibaba/jstorm JStorm 是一个分布式实时计算引擎. JStorm 是一个类似Hadoop MapReduce的系统, 用户按照指定的接口实现一个任务,然后将这个任务递交给JStor ...
- Math.net,.net上的科学计算利器
F#在科学计算领域的应用,包括部分语法介绍. Math.net,.net上的科学计算利器 摘要: .net上科学计算个人觉得首选numpy和scipy for dotnet.因为这两个库用户数量已经非 ...
- Spark是一种分布式的计算方案
Spark的安装基于HDFS,所以我们要设置hadoop的配置文件,所以spark的存储不是其主要的功能点,而spark作为分布式生态中的角色是一种计算模式(其他 的计算 模式,比如MR,Storm, ...
- 【并行计算-CUDA开发】GPU---并行计算利器
1 GPU是什么 如图1所示,这台PC机与普通PC机不同的是这里插了7张显卡,左下角是显卡,在中间的就是GPU芯片.显卡的处理器称为图形处理器(GPU),它是显卡的"心脏",与CP ...
随机推荐
- HTTP请求包和响应包
HTTP请求包 HTTP响应包
- 四、Ansible的Galaxy包管理器
一.什么是Ansible Galaxy? Ansible Galaxy是Ansible的第三方插件管理和安装工具,其实就是包管理软件.作用类似于Ubuntu的apt,Centos的yum,Python ...
- flask入门 七行代码讲解
# 导包 从flask里面导入Flask这个对象.from flask import Flask # 实例化一个对象,app = Flask(__name__) # 里面的 __name__ 是为了定 ...
- 谈谈JVM垃圾回收
概述 Java运行时区域中,程序计数器,虚拟机栈,本地方法栈三个区域随着线程的而生,随线程而死,这几个区域的内存分配和回收都具备确定性,不需要过多考虑回收问题.而Java堆和方法区则不一样,一个接口的 ...
- Vue中 父子传值 数据丢失问题
在Vue中,父子组件传值,子组件通过props接收父组件传递的数据 父组件 questionList : 传递数据参数 questionsLists: 传递数据源 子组件 porps 接收父组件方式 ...
- jqGrid根据数据动态设置rowList
superme.rowList = [10,20,50,100]; superme.rowNum = 20; 全局属性 loadComplete : function (data) { if(data ...
- volatile、Synchronized实现变量可见性的原理,volatile使用注意事项
变量不可见的两个原因 Java每个线程工作都有一个工作空间,需要的变量都是从主存中加载进来的.Java内存模型如下(JMM): 线程访问一个共享的变量时,都需要先从主存中加载一个副本到自己的工作内存中 ...
- Java多线程的中断原理和 interrupt() 几个方法简介
上节讲到,线程被 wait() 通知后进入等待池,可以由本线程的 interrupt() 方法解救,使本线程可以去重新竞争锁等等.是如何实现的呢? 实际上,中断仅仅是在线程对象做一个标记而已,称为中断 ...
- nvm的安装与配置和基本使用(学习总结)
nvm是来管理node的一个工具,为了方便使用不同版本的node.js运行环境,我们应该学习如何使用他 nvm安装方式 1.下载nvm,大家可以去github上下载,但因为github的CDN被墙,访 ...
- Java中指令重排
/** * 指令重排:代码执行顺序与预期不一致 (发生在前后行代码无联系时) * 目的:提高性能 * */ public class HappenBefore { private static int ...