akka 微服务软件框架_使用Akka创建弹性软件

akka 微服务软件框架

在本文中,我将向您介绍Akka的幕后故事,但不是从技术角度上讲-可以通过查看源代码来满足好奇心-而是向您展示其指导原则的发展背后的驱动力是。 尽管这些想法并不新鲜,但我希望我可以为您提供有关它们如何连接的新观点。

弹性是什么意思?

让我们面对现实:失败的确发生了。 无论您多么努力,总会有另外一种情况您没有预见到,而您的测试却没有揭示出来。 因此,问题不在于“如何避免失败”,而在于“如何应对失败”。 牛津词典将复原力定义为:

  1. 物质或物体弹回形状的能力; 弹性
  2. 从困难中Swift恢复的能力; 韧性

此类困难的日常例子(可能会使您的应用程序的某些部分变形)包括临时无法使用的数据库服务器,想要使用该出色产品的每个人所引入的负载峰值,不正确的用户输入(以某种方式使其无法使用)。该子例程现在被阻塞了。 理想情况下,从这些情况下恢复应该是自动的,以便尽快恢复正常服务。

在这种情况下,恢复力意味着必须对故障进行区分:如果可以避免的话,一个发生故障的组件不得拆卸其他组件。 服务级别可能会降低,也许某些功能暂时不可用,但是应用程序的其余部分仍然可以运行。 一旦停止了蔓延,必须将其扑灭,必须重新启动发生故障的组件,或者启动对备用系统的故障转移。 这些过程需要自动且可靠,因为它们会捕获所有计划外的故障案例。 组件的功能恢复后,即可恢复与其他组件的正常协作。

松耦合是关键

从刚刚提出的观点来看,很明显组成一个弹性应用程序的各个组件不能牢固地耦合,也不能紧密地纠缠在一起。 故障恢复后,有关另一组件内部状态的所有知识都将变得无效,从而使一个组件容易受到另一组件的故障的影响。 松散耦合对象的想法是一个非常古老的想法,例如在Smalltalk-80中实现的,其中一个对象(保持状态)只能使用消息与其他对象通信。 这种抽象是很自然的,因为它与人类的互动方式相匹配:我们不从字面上看对方的大脑,而是通过口头和非语言交流来交换信息。 松散耦合的关键特征是内部状态无法直接访问,并且所有交互作用都由保护层(该行为即对象的行为)来介导。

在不将Java类的变量字段直接暴露给外部调用者的常见实践中,仍然可以看到此原理的影子。 取而代之的是,我们在IDE的帮助下反身生成getter和setter。 但是,这些不会产生松散耦合,正如我接下来将要演示的那样。

主流的面向对象语言的另一个特性是,调用对象的行为(称为方法)是同步发生的,因此结果值可立即用于调用代码,并且所有副作用都在方法调用返回时发生。 这样做的问题是,它不允许对象不可用:任何外部调用者都必须立即对答案感到满意,如果当前不可能,则唯一的选择是通过引发异常来升级失败。 然后,调用者必须处理此异常,从而触发故障恢复。 因此,呼叫者负责知道如何执行此操作,这类似于说每个客户都必须能够修理自动售货机。 即使没有直接访问私有状态,这也会导致对象之间的相当强的耦合。

因此,松散耦合要求组件通过异步发送彼此的消息进行通信,并在将来的某个时间点以其他消息的形式接收可能的答复。 如果您是第一次在这种情况下考虑“组件==对象”,这对您来说似乎很奇怪,但是实际上,这种技术已经在较高的层次上应用了很长时间。 企业体系结构中的不同组件或服务通常使用消息代理和队列来分离,因此可以通过将传入请求存储在消息传递基础结构中并在服务备份时恢复处理来桥接服务的失败和恢复。 另一个示例是服务之前无处不在的RESTful HTTP接口,其中客户端发送HTTP请求消息,服务器使用HTTP回复消息进行应答。

当您考虑架构中的服务时,通常这不是几分钟就能完成的事情。 服务通常是多达数百个组件中的一个,而后者已经是一个相当大的应用程序,是一项相当大的工程工作。 现在想象一下,您的服务是在内部以相同的松耦合方式构建的,只是规模较小。 内部对象协作提供服务,每个对象仅解决了整个问题的一小部分。 这些小对象仅通过异步消息传递进行通信,并且如果其中一个失败,其他所有对象都会快乐地继续工作。 这些小物件是阿卡(Akka)的演员, 几分钟内写一个演员是完全合理的。

异步消息传递需要监督

以HTTP服务器为例,很明显,如果出现故障,客户端将不负责恢复服务器的功能。 它只会通过禁用服务或切换到备份服务器,从而实现隔离,在客户端和服务实例之间插入一个隔离 ,来对没有有意义答复的情况做出React。 但是,谁负责重新启动HTTP服务器并使RESTful接口重新联机?

在有弹性的应用程序中,每个组件都必须具有负责处理其故障的主管。 您还可以将两个组件之间的这种关系视为父子关系。 当子项失败时,它会通知父项(或父项通过不断监视其子项来检测到它),并且父项将决定前进的方向,最终恢复子项的功能或将故障升级为自己的父项。 这种方法的重要特征是处理被呼叫者的失败不再是呼叫者的责任; 在自动售货机示例中,除客户外,还有人负责修复它或寻求支持。 将故障处理路径(子级-父级)与业务通信路径(主叫方-被叫方)分离,可能是Actor模型对软件设计的最重要贡献。

由于每个孩子都需要有一个父母,因此所有组成部分都形成了一个监督层次结构,这与大型公司的管理结构不同。 在该层次结构的顶部,您可以找到代表整个工作的象征,将应用程序捆绑在一起的组件,而其失败则表示整个应用程序已经失败。 故障越严重,最终的恢复操作就必须具有更大的破坏性,从而影响应用程序的更大部分。 这有两个结果:

  • 极有可能发生故障的操作应在层次结构中较低的位置执行,以使恢复尽可能快速而简单。
  • 重要的对象状态应在层次结构中尽可能高地保留,以防止其受到上述恢复操作的影响–通常需要将组件重置为已知良好的状态,以使其再次运行,从而丢失所有的状态累积状态。

第二种模式称为错误内核,显而易见的目标是使应用程序的这一核心部分(难于恢复或成本高昂)保持尽可能小和尽可能简单,从而可以很大程度上避免故障。

典型的企业体系结构没有显示出这种同质的监督层次结构:示例HTTP服务器可能受到网络监视工具的监视,并且自动脚本会重新启动它,或者会警告操作员执行手动恢复。 Akka演员以完全同质的方式实施上述形式的强制性父母监督,等级制度一直由演员组成。 (好吧,显然有一个顶级演员的父级不是“真实的”,但这是一个技术细节,尽管很有趣。)每个演员都定义了一个主管策略,该策略确定失败的子演员是否恢复,重新启动(即重置为初始角色)。状态)或完全停止。 而且,如果没有其他帮助,则故障会升级,这意味着主管会自行失败,并将问题交托给自己的父母。

松散耦合的对象可以分布

回顾到目前为止的故事,我介绍了仅通过发送彼此消息进行通信并且不会直接访问彼此的私有内部状态的组件。 通信是异步进行的,因此在呼叫者发送消息与被呼叫者处理消息之间需要一段时间。 这些特性使得可以完全独立地执行这些组件的行为,可能在一个线程上一个接一个地执行-没有在同步方法调用期间通常会遇到的嵌套调用堆栈-但在不同线程上并行执行也是可能的可以依次安排在单个服务器的核心上,甚至安排在不同的网络主机上。 通过不共享组件之间的可变状态来启用后者,从而消除了在具有共享内存的环境中执行的需求。

暂时考虑一下:从对弹性软件设计的渴望开始,我们获得了很适合在多个网络节点上分布的对象。 从另一方面来看,系统的容错能力需要冗余的硬件,因为即使最可靠的服务器也最终会出现故障。 因此,面对节点故障,甚至需要分发应用程序才能实现弹性。

弹性的另一个令人惊讶的结果是,由于与监督相关的通信,它要求引入并发性,但同时又为我们提供了管理它的工具。 通信对象安全地封装了它们的私有状态,并提供了一个自然的边界,在该边界内,所有处理是连续且一致的(一个消息接一个消息),并且不需要在您自己的代码级别上用于管理并发程序中的同步的可怕实用程序。 迄今为止,Akka核心的发展已换来了这家出色的酒店,为Akka团队带来了非常可喜的挑战。

在Akka中,参与者的分配是完全透明的,甚至使其成为部署选择。 这意味着您使用actor编写应用程序,然后通过配置将监督层次结构的一部分部署在协作网络节点上,或将某些actor分组以在同一线程池上执行。 Actor使用ActorRefs相互发送消息,ActorRefs是不可变的句柄,可以自由共享和传递这些句柄,无论指定的目标actor是位于同一JVM还是位于不同的网络主机上,都可以公开相同的消息语义。

分布式监管要求集群支持

子角色与父对象之间的与故障相关的通信也通过消息执行,但是如果父对象生活在不同的网络节点上,并且某人恰好在该孩子需要帮助时有人通过网络电缆跳闸,该怎么办? 您的直觉可能是,失败消息将需要进行缓冲,直到重新插入电缆然后重新发送为止,并且对父级的答复也是如此。 这与发生的情况非常接近,但实际情况要复杂一些,因为即使父计算机永远无法访问,Akka也需要保持应用程序运行,例如,由于其电源最终被放弃。 在这种情况下,父计算机上的actor被视为已停止,在这种情况下,这意味着失败的子actor也将被停止(以及孙子等); 毕竟,没有父母就没有演员。 复杂的部分是,其他网络节点也可能与该计算机协作,而当前无法从孩子的节点访问该计算机,而这些其他节点仍可以与父计算机进行通信(因为网络电缆毕竟有故障) 。 需要在所有协作节点之间一致地做出是否应声明该机器上的所有参与者停止的决定。

这是Akka的群集支持输入的地方。 它管理所有协作集群节点的一致成员身份列表,并且无需任何中央主节点即可做到这一点。 相反,它是基于Dynamo的思想构建的,并使用八卦协议传播共享的成员身份信息。 每个节点都使用心跳消息监视多个对等方的活动,如果心跳暂停时间超过可配置的阈值,则会在静默节点无法访问的其他消息中散布单词。 通过将无法访问的节点标记为“关闭”(自动/编程或手动)将其从群集中移除后,所有剩余节点将分别将已移除节点上的所有参与者视为已停止,并通知其父节点并递归停止其子参与者。

父母与孩子之间的监管链接并不是集群服务的唯一受益者:每个参与者都可以监视集群中任何其他参与者的生命周期,以便在其他参与者停止活动时接收消息。 在正常情况下,这是通过目标参与者在其报废过程中发送这些消息来实现的,但是由于集群的作用,如果目标参与者由于其节点崩溃或变得不可访问而实际上无法执行这些动作,它也可以工作。

结论

通过将应用程序分为松散耦合的组件并将故障作为编程模型的基本部分来接受,可以实现弹性,该模型通过监督明确表示和解决。 这就是为什么我坚信Actor模型 (特别是在Akka中实施的强制性父母监督)是开发弹性应用程序的主要工具。 另一个好处是,基于角色的应用程序自然可以在水平和垂直方向上进行扩展,因为基本抽象非常适合于分发。 如果您想更深入地阅读这些主题,尤其是技术细节以及如何开始编写基于actor的应用程序组件,请参阅在线文档

翻译自: https://www.infoq.com/articles/resilient-software-with-akka/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

akka 微服务软件框架

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值