响应式架构简介

为什么企业级软件难以开发

  在介绍响应式编程技术会使软件开发工作变得简单之前,让我们先了解一下开发企业级软件为何如此之难。当然,你可能在开发企业级软件时遇到过各种难题,如需要经常使用的数据库出问题、应用程序服务器拖慢了你开发的软件的运行速度,或者更为严重的情况,你使用的编程语言带来了问题。这些问题是普遍存在的。

  根据领域驱动设计(DDD)实践,使用端口和适配器(也称为六边形)架构,可以简化开发企业级软件的工作。要实现完整的企业级应用程序,必须考虑架构、设计、配置、实现和组件的详细部署工作,如图所示

  事实上,即使对于大多数资深架构师和开发者来说,这也是一项需要花费数个月才能完成的工作,更何况那些初中级开发者呢?将这项工作交给初中级开发者完成,你是否会放心?将这样复杂的工作交给初中级开发者来做显然是有风险的。每位开发者都需要从头至尾了解并熟练掌握的工作的数量是惊人的。

领域事件

  持久存储的领域事件代表了业务领域中发生的事情。它们能够传输领域模型中出现过的情况,它们的信息量很大,而且只要你处理领域事件,就需要用到它们。领域事件仅是一种结果。每个领域事件都是作为在领域中执行的某个命令的输出结果而被创建的。在命令模式(GoF)中,应用程序中的对象表达了用户或应用程序的目的,从而实现业务操作。一旦该目的被实现,那么获得的结果就是领域事件。如果你向系统(如浏览器、智能手机、云计算、消息系统等)输入命令,就会获得Actor对象和领域事件。因而,你最终实现的是“响应式堆栈”和Actor模型,如下图所示。

什么是Actor模型?

  使Actor对象能够像第一类值一样被处理,并通过消息传递功能加强了Actor对象之间的通信操作。Actor是一种无锁的并发代理对象,而且执行它们的线程通常不会被阻塞,所以使用Actor对象设计的应用程序能够完美地利用系统的基础线程资源。

Actor模型应用程序仅需要关注下列几个重要概念。

  • 接收哪些类型的消息一一命令和/或事件?发出哪些类型的消息一一命令和/或事件?
  • 为了回应接收到的消息,应用程序应对其当前状态做出哪些改变?

响应式应用程序简介

  定义:响应式应用程序具有较好的响应性、韧性和灵活性,而且应该是由消息驱动的,从而能够使用户获得实时操作的感觉。

响应式应用程序的目的:

  • 对用户和其他应用程序组件做出回应:响应式应用程序的响应时间应符合或高于非功能性需求。
  • 对失效情况做出回应:响应式软件应通过使韧性成为本身的重要特征,从而获得恢复任何类型组件的能力。
  • 对加载操作做出回应:响应式程序应通过以独立方式管理离散资源(如系统实体),努力避免出现资源争用情况。这种设计方式能够使系统拥有韧性和高吞吐量。
  • 对消息做出回应:响应式应用程序的基础设计思想是通过其核心的异步消息传递模式,实现消息驱动模式。

响应式应用程序的关键特性

响应性

  响应式应用程序必须像用户界面的功能需求一样具备响应性。这些功能需求包括实时用户界面的功能需求,实时用户界面允许多个用户同时执行重叠的编辑操作。而且,即使出现故障,响应性也必须仍然存在。通过被观察者和观察者模型可以实现响应性;被观察者和观察者模型是指当系统发生改变时,系统有能力通知对该改变感兴趣的一方或多方。该模型需要使用能够根据用户消耗资源的数量进行调整的事件流和可视化模型,而不是使用根据业务操作调整的系统模型。

韧性

  应用程序拥有故障恢复的能力。响应式应用程序通过监督较低层级的响应式组件来预测故障情况。这种模式拥有异步操作边界,而且能够将故障具体化为消息,并通过重要的专用消息通道发送[Read-Write]。监督者会被赋予对被监督组件的故障做出回应的能力。正确的回应可能是彻底停止故障组件,也可能是重新启动故障组件,还可能是通过忽略故障原因来命令故障组件继续运行。监督者甚至可以选择使本身失效,从而使它的监督者能够选择上述恢复操作之一。
  这种方式倾向于将故障隔离在它们出现的应用程序区域中,从而使程序员能够以对症下药的方式处理它们。同时这还能够保护应用程序的其他组成部分,避免故障以连锁反应的方式影响一个或多个不相关的应用程序区域。

灵活性

  每当我们思考可伸缩性时,总是会横向或纵向扩展思考范围。纵向可伸缩性可以通过添加拥有更多中央处理器(CPU)的高性能计算机实现,每台计算机都拥有多核处理器(如IntelXeon Phi处理器)和大量的内存。横向可伸缩性可以通过添加多台提供日常服务的服务器实现,每台服务器都应拥有中等性能的CPU(如一块或两块Intel i7 Quad Core 4700HQ处理器)。
  当然,为了满足特定的可伸缩性需求,也可以同时使用这两种扩展方式。但从实践的观点看,灵活性比可伸缩性更为重要,因为灵活性还意味着通过调整满足当前应用程序的需求。也就是说,可能需要在非高峰时间通过调整使用较少的计算资源。不论增加计算资源还是减少计算资源,你编写的软件都应该全天候提供与预期相符的响应性。灵活性能够提供这项支持,因为灵活性意味着根据需求进行调整,这种调整方式是响应性的核心。
  响应式组件的消息驱动特性和它们的位置透明性都为根据需求调整应用程序提供了帮助,即实现了应用程序的灵活性。

消息驱动

  系统组件仅会在收到消息时做出回应,所以系统能够使用可用线程运行应用程序中必须立刻对消息做出回应,当前没有正在对消息做出回应的组件不会占用宝贵的CPU资源。消息的类型包括命令消息、文档消息和事件消息。响应式应用程序中的组件会通过异步消息传递模式,接收其他组件发送的消息,所以能够自然而然地降低各种组件之间的接口和时间耦合性。响应式组件能够选择以独立方式对每条消息做出回应的方式,所以它们能够做好接收预期内消息的准备工作。这就进一步降低了发送消息组件和接收消息组件接口的耦合性,因为客户端无须知道发送消息的次序。响应式组件本身是小型的类似原子的单元,而且它们在同一时刻仅会对一条异步消息做出回应,所以它们能够排除所有锁策略。

企业级应用程序

  也许你所在的企业项目正处在项目的初始阶段。使用“普通”企业级软件开发工具可能已经获取了一些成果,但为了达到策略应用程序的目标,还必须进一步扩大这些成果。可以考虑使用Actor型来满足刚性和之前看起来遥不可及的需求。除了性能和可伸缩性需求外,还需要创建软件模型,以便反映业务预测的心智模型。领域驱动设计(DDD)就是专门用于支持SIS(DDD)开发的。
  此外,当你面对新的企业策略挑战时,必定需要整合企业中已经存在的系统。开发企业策略解决方案和整合各种企业系统工作中的一个要点是对工具的选择。通常,架构师会选择不使任何人失去工作的解决方案。这些解决方案通常是膨胀的、缓慢的、不具备可伸缩性的、无弹性的并且昂贵的。当前这些常见的解决方案已经受到了挑战,而你的目标就是在这类膨胀的解决方案中,寻找精炼的、成本效益高的处理方式。

了解Actor模型

Actor是一种计算实体,它会对收到的消息做出回应,并且可以做下列事情:

  • 向其他Actor对象发送一定数量的消息。
  • 创建一定数量的新Actor对象,设定对下一条消息做出的回应方式。

  执行这些操作的次序不分先后,而且可以通过并行方式执行它们。在功能齐全的Actor系统中,所有事物都是Actor对象。这意味着我们通常使用的基本数据类型(如字符串和整型)都是Actor对象。最实用的模式是设计一种将Actor对象用作特殊类型系统组件的Actor系统。在这种系统中,Actor对象的尺寸比整型值大,但也不会比整型值的尺寸超出太多。要确定Actor对象的适当尺寸,可将它们视为专门化的应用服务,如单个的领域模型实体或小型的领域模型集合

Actor系统和Actor对象具有下列基本特点

  • 直接通过异步消息传递方式进行通信:如果Actor对象A1要向Actor对象A2发送消息M1,那么Actor对象A1就必须知道Actor对象A2的地址。如果Actor对象A1知道Actor对象A2的地址,那么它就能够直接向Actor对象A2发送消息M1,但Actor对象A2会使用独立线程接收和处理消息M1。换言之,消息M1是通过异步方式被发送给Actor对象A2的。实际上,在发送者Actor对象和接收者Actor对象之间还存在一个间接处理层——邮箱(消息缓存单元)。
  • 状态机:Actor模型支持有限状态机。当Actor对象转换为某个预设状态时,就能够改变对未来接收到的信息的处理模式。通过变为另一种消息处理器,Actor对象就成了一种有限状态机。
  • 无共享:一个Actor对象不会与其他Actor对象或相关组件共享可变状态。
  • 无锁的并发处理方式:因为Actor对象不会共享它们的可变状态,而且它们在同一时刻仅会接收一条消息,所以在对消息做出回应前,Actor对象永远都不需要尝试锁定它们的状态。
  • 并行性:并发处理方式和并行处理方式是不同的概念。并发处理方式是指多个计算操作同时出现。并行处理方式是指以并发处理方式完成单个目标。并行性是通过将单个的复杂处理过程拆分成较小的任务并以并发处理方式执行它们实现的。当等级较高的Actor对象能够将多个任务分派给多个下级Actor对象,或者任务中含有复杂的处理层级时,就适合通过Actor模型使用并行处理方式。
  • Actor对象的系统性:单个Actor对象不具备并行性。Actor对象的量级非常轻,因此在单个系统中创建许多Actor对象是受推荐的处理方式。任何问题都可以通过添加Actor对象来解决。

Action扩展特性(Akka系统)

  • 位置透明性:使用抽象引用代表Actor对象的地址。如果Actor对象A1获得了Actor对象A2的引用,Actor对象A1就能够向Actor对象A2发送消息。提供支持的Actor系统会负责处理传送消息的操作,不论Actor对象A2是位于本地Actor系统还是位于远程Actor系统中。
  • 监督:在Actor对象之间建立依赖关系,父Actor对象监督子(下级)Actor对象。当监督者Actor对象向下级Actor对象分派任务时,就必须对这些下级Actor对象出现的失效情况做出回应。合法的回应包括继续运行、重启和停止下级Actor对象。监督者还可以通过使本身失效从而使失效情况升级,这会将失效控制权上交给监督者的父对象(监督者的监督者)。监督机制适于在并行处理方式中使用,在该方式中监督者会将多个任务分派给多个下级对象,从而形成任务处理层级。
  • Future/Promise对象:这两种对象提供了接收异步操作结果的手段,不论该结果是代表异步操作成功完成还是异步操作出现失效情况。为了管理接收到的结果,系统需要使用特殊的Actor对象(如Future和Promise)。拥有Future对象的组件可以选择以等待/阻塞方式接收结果,也可以选择以异步方式接收结果。

管理不确定性系统

  什么是不确定性,为什么我们要关心它呢?在应用程序开发过程中,不确定性系统是指当使用相同的输入数据多次执行程序时,会输出不同结果的系统。事件驱动的响应式应用程序天生就具有不确定性,实际上,不应将不确定性和不可靠混为一谈,只要你了解了应用程序产生不确定输出结果的情况,就不必过于担心程序的不确定性。具有天生不确定性的是由事件驱动的架构,而Actor模型只不过恰好是一种由事件驱动的架构。而且,通过引入Actor对象(Actor对象本身是一种具有原子确定性的单元),Actor 模型还能够帮助我们推导天生具有不确定性的并发业务系统。因此,真正的决策点是使用无法伸缩的单线程架构设计程序,还是使用可管理的、多线程的、由事件驱动的架构设计程序。

对象性能模型

Actor对象只能根据发送消息才能交互。可通过下列方式获得引用。

  • 初始情况:Actor对象A可能一开始就已经拥有Actor对象B的引用。
  • 父子关系:当Actor对象A创建了Actor对象B后,Actor对象A立刻就获得了Actor对象B的唯一引用。
  • 赠予:当Actor对象A创建了Actor对象B后,Actor对象A可以将Actor对象B的引用赠予其他Actor对象。
  • 介绍:如果Actor对象A拥有Actor对象B和Actor对象C的引用,那么Actor对象A可以通过发送消息使Actor对象B获得Actor对象C的引用。

  Actor对象B可以保留该引用并在将来使用该引用。

Actor模型的明晰性

  利用Actor模型可以大幅度简化企业级应用程序。领域驱动设计(DDD)的主要目标之一,是在软件模型(DDD)中使业务概念变得明确和清晰。另一方面,精简的架构仅含有用户界面和清晰的软件模型。据此甚至能够推断出用户界面也是软件模型的组成部分,因为它反映和表现了业务专家的心智模型(SIS),通过这种方式帮助用户做出重要决策。下图进一步突出了软件模型具有明晰性的重要性。指定消息的接收者是明确的,不论这条消息是命令消息还是事件消息。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容