公司物联网项目集成Orleans以支持高并发的分布式业务,对于Orleans也是第一次接触,本文就分享下我的对Orleans的理解。数据库
这里先抛出本身的观点:Orleans 是一个支持有状态云生应用/服务水平伸缩的基于Virtual Actor 模型的.NET分布式框架。编程
下面我会从如下几个关键点,进行阐述:缓存
在讲云生应用以前,咱们来先讲讲传统应用,对于传统应用经常使用的三层结构以下图所示。
性能优化
随着业务的发展,数据库层一般存在瓶颈,为了缓解数据库的压力,通常会优先考虑增长一层缓存层。服务器
而随着业务的继续发展,高并发、大数据量的应用场景逐渐凸显。若是继续在单体应用的基础上进行扩展,能作的无非是增长消息队列、异步、读写分离等机制进行性能优化。整体而言,优化空间不大,但应用的总体复杂度却随着引入的新的技术框架而迅速增长,对于应用的维护,是一个潜在的定时炸弹。架构
这个时候你可能会想,既然单体应用单机部署不能知足需求,我能够作集群啊。经过将单体应用按照分层结构进行纵向分离,将数据库从应用服务器分离,将缓存从应用服务器分离。这样就能够对分离的各个部分进行分别部署,再借助负载均衡完成集群效应。到这一步,你的应用应该能撑一段时间了。并发
这个时候,若是回到业务自己去分析,对于一个复杂应用来讲,一般的性能瓶颈就是几个核心服务上。若是可以对存在性能瓶颈的服务进行伸缩,既能大大提升应用的总体可用性又能提升资源的利用率。那怎么作呢?服务拆分。负载均衡
云生应用就是服务拆分的结果,云生应用最大的特色就是:框架
或者简单来讲,云生应用经过服务拆分支持服务并行,同时各个服务可以快速伸缩以提高系统吞吐量来应对高并发的业务场景。异步
虽然经过服务拆分简化了整个应用的业务复杂度,可是实现的技术复杂度却只增不减。
转向云生应用咱们面对的第一个难题就是:如何进行服务拆分,才能确保其能分布式部署,或者说是水平伸缩?!
有经验的同窗,可能会立马想到,要将应用/服务设计为无状态的。可是这里我要向你讨教几个问题:
你们不妨先停下来思考一下。(欢迎你们在评论中阐述不一样观点。)
这里,我尝试从如下两个角度来谈下本身的见解:
1. 对象
面向对象编程强调的是对现实事物的抽象和封装。经过对事物状态和行为进行抽象而后封装为对象(类),其中状态封装为类的属性、字段,将行为封装为类的方法。这个时候获得的对象是没有生命力的,由于它本质是一个抽象的结果。只有在程序运行中对类进行实例化获得一个对象的实例时,才能够说这个实例对象是有状态和行为的,由于这个状态和行为是其独自持有的,这是一个很是核心的条件。独自持有,换句话说,就是非共享成员。
独自持有非共享的成员就能够说这个对象实例是有状态的吗?
这里面你就要看清状态和有状态的区别!
举个简单例子,大街上你看到一大叔开着豪车,你以为他很富有。“开着豪车”是你即时看到的状态属性。“富有”是你的状态断言。但这个状态断言是一个假设,毕竟多是借的嘛。
怎样才能判定“富有”就是这位大叔拥有的状态呢?很简单,假设一年365天你每天见到他开豪车,那基本八九不离十了。
因此,若是认定一个对象是否有状态,还要看其状态属性是否持久化!
若是你赞成这个观点,那么哪天你看我骑个共享单车,气喘吁吁从你面前通过,就不要简单认为我是苦逼工薪族。毕竟我也是身价上千万,只是偶尔骑个车锻炼锻炼。(身价上千万,昨晚梦到的。)
因此,从对象角度看,一个对象是否有状态的充分必要条件是:
- 对象已实例化(处于运行时)
- 拥有非共享的状态属性
- 状态持久化
那问题来了,咱们常常写的类建立的实例,是有状态的吗?
2. 应用
基于上面的总结,咱们再来从应用的角度来看分析这个问题。
那应用的状态和行为是什么?
首先,只有运行中的应用才有状态和行为。基于这个前提,我的理解运行时应用的状态是应用持有的数据,行为是应用提供的功能。那应用的有无/无状态界定就要看运行时应用持有的数据可否持久化。
以简单的Web分层应用举例 。从逻辑架构上来说应用通常分为三层,表示层、业务层和数据访问层。上层进行状态行为的封装,数据层提供数据的持久化。因此从总体的角度来看,其是一个有状态的应用。但单独来看,咱们不能对每一层进行有/无状态的界定。第一,每一层不能单独运行;第二,分层的目的是为了职责的隔离,每一层负责相应职责的抽象和封装,其输出的是类文件,是对象的集合,没有生命力。
那从物理架构上来说,Web应用能够分开两个部分进行部署:Web实例和MySQL实例。也就是说应用和数据库是能够分开部署的。这个时候Web实例就是无状态的。那咱们通常常说的无状态服务实际上是就是从这个拆分的角度来讲的。
理清完服务拆分的核心问题后,咱们不得不来处理第二个棘手的问题:如何解决云生应用高并发的应用场景呢?
那首先咱们须要明确处理高并发的难点在哪?第一个是高性能,第二个就是:资源竞争致使的数据一致性问题。对于第一个难点,经过水平扩展服务能够化解;对于第二个难点,通常就是采用锁机制,而对于云生分布式的应用场景下,处理手段就更加复杂,可能须要使用分布式锁,而这种作法,大大下降了应用的总体响应性能。那有没有更好的解决方案,既兼顾性能又能够确保数据一致性呢?
有,借助Actor模型。
简单来说:Actor模型 = 状态 + 行为 + 消息。一个应用/服务由多个Actor组成,每一个Actor都是一个独立的运行单元,拥有隔离的运行空间,在隔离的空间内,其有独立的状态和行为,不被外界干预,Actor之间经过消息进行交互,而同一时刻,每一个Actor只能被单个线程执行,这样既有效避免了数据共享和并发问题,又确保了应用的伸缩性。
另外Actor基于事件驱动模型进行异步通讯,性能良好。且位置透明,不管Actor是在本机亦或是在集群中的其余机器,均可以直接进行透明调用。
所以Actor模型赋予了应用/服务的生命力(有状态)、高并发的处理能力和弹性伸缩能力。
对于Actor模型,业界已经有系列的实现框架,好比Erlang、Akka。然而Actor模型做为一个偏底层的技术框架,对于开发者来讲,须要有必定分布式应用的开发经验,才能用好Actor(包括Actor的生命周期管理,状态管理等等)。为了进一步简化分布式编程,微软的研究人员引入了 Virtual Actor 模型概念,简单来说Virtual Actor模型是对Actor模型的进一步封装和抽象。
其与Actor模型的最大的区别在于,Actor的物理实例彻底被抽象出来,并由Virtual Actor所在的运行时自动管理。
Orleans 就是做为一款面向.NET的Virtual Actor模型的实现框架,提供了开发者友好的编程方式,简化了分布式应用的开发成本。在Orleans中Virtual Actor由Grain来体现。
Orleans中核心优点:开发效率高、透明可伸缩。
开发效率高具体表现为:
透明可伸缩体现为:
这篇文章,就简单写到这里,对于Orleans的详细介绍后续会结合实际项目输出更系统的应用细节,下次再见。