阿卡接口_在阿卡的协调

本文介绍了如何在Akka中管理Actor的生命周期,包括Actor池、Akka HTTP的使用以及协调Actor。通过示例展示了如何利用Actor的问与说模式、创建Actor以及监督策略来实现高效的资源管理。文章还提到了在系统中限制Actor数量以避免线程池耗尽的问题。
摘要由CSDN通过智能技术生成

阿卡接口

这是一系列关于同步客户端集成与异步系统(第五柱1, 2, 3, 4 )。 在这里,我们将看到如何管理参与者的生命周期,以便我们的服务可以有效地使用可用资源。

生命周期

角色,线程,对象,资源……它们在生命周期中都具有不同的状态。 其中一些状态是内部的,它们在受到外部刺激时会影响实体的行为。 但是,状态转换应由外部实体处理:创建,错误恢复和处置。

演员池

很久以前,依赖项注入向我们表明,对象不应该负责创建其依赖项。 将这些问题外部化到工厂中可使代码更具可测试性,松散耦合和可读性。 无论使用DI框架还是穷人的依赖注入,我们都需要不同的创建策略。 Guice Scopes是一个很好的示例,它说明了如何为每个应用程序创建一个实例(@Singleton)或为每个范围创建一个实例(@SessionScoped和@RequestScoped)。

通常,系统资源稀缺,创建成本高或负载过重。 这意味着我们既负担不起Singleton的负担,也负担不起Spring中的Prototype之类的无限创造策略。 一个很好的例子是线程池

使用工作线程可以最大程度地减少线程创建所带来的开销。 线程对象使用大量内存,在大型应用程序中,分配和取消分配许多线程对象会产生大量内存管理开销。

Akka Actor非常轻巧。 如果我们知道可以Swift处理掉它们,那么我们可以负担得起创造数百万个它们的费用。 但是,用例不是这种情况:

fsm

如您所见,有限状态机(FSM)参与者将等待,直到Items服务完成删除项目为止。 重要的是要注意,参与者正在等待,但没有阻止。 Actor附加到内部具有线程池的Dispatcher 。 这些线程池具有有限数量的线程。 阻止其中一个参与者将意味着很快耗尽线程。 在此特定示例中,我们要限制参与者的数量,而不是线程。 也许是矫kill过正,但是本系列文章的重点主要是教育性的。 让我们看一下具有适当抽象级别的服务图。

协调图

Akka HTTP

Akka HTTP是一个基于Spray的库,用于创建HTTP集成层。 正如您在我们的代码中看到的那样,Akka HTTP提供了非常强大且易于阅读的路由DSL:

val deleteItem = get {
    path("item" / JavaUUID) { itemId =>
      onComplete(deleteItem(itemId)) {
        case Success(Result(Right(_))) =>
          complete(StatusCodes.OK)
        case Success(Result(Left(Timeout(errorMessage)))) =>
           complete(StatusCodes.GatewayTimeout)
        // many other cases we won't cover here
      }
    }
  }

  private def deleteItem(itemId: UUID)= itemCoordinator ask ItemReported(itemId)

在此片段中,我想强调一下问与说模式 。 只是为了澄清,这是Akka模式,与惊人的“告诉,不要问”原理无关告诉模式涉及触发消息并忘记响应。 在这种方法中,信息沿一个方向流动。 但是对于我们的情况,我们对Ask模式感兴趣。 当我们通过询问模式向演员发送消息时,将来会以超时为最终响应,从而创建了未来。 如文档所述:

与ask一样,使用ask将向接收方Actor发送一条消息,并且接收方actor必须使用sender()进行回复! 进行回复以完成返回的Future值。 ask操作涉及创建一个内部actor来处理此回复,该回复需要有一个超时时间,之后该超时时间必须销毁以防止泄漏资源。 请参阅下文。

First actor ->
  val future = myActor.ask("hello")(5 seconds)

Second actor ->
  sender() ! result

协调演员

让我们看一下Item Coordinator代码:

override def receive: Receive = {
  case itemReported: ItemReported =>
    if (actorPool.isEmpty)
      sender() ! Result(Left("No actors available"))
    else {
      actorPool.get() forward ItemReported
    }

  case Result(_) =>
    sender() ! FlushItemFSM
    actorPool.putBack(sender())
}

sender方法公开发送消息的ActorRef 。 如果角色池已用尽,我们需要与Route角色进行通信,我们将无法满足该请求。 否则,我们将检索池中的参与者之一,然后转发收到的消息。 转发允许我们保留原始发件人。 FSM将其工作结果传达给正在等待由问号模式限制的Route角色。

协调图

FSM需要协调器的引用,因为它负责管理FSM的生命周期。 协调器向FSM发送一条消息,告知其刷新其内部状态。 同时将FSM放回池中。

创造演员

请记住,FSM如何通知其工作已完成:

private def finishWorkWith(message: Any) = {
   replyTo ! message
   coordinator ! message
   goto(Idle)
}

replyTo是在接收第一条ItemReported消息时使用sender()初始化的变量。 请记住,邮件是转发的,因此发件人是Route Actor。 coordinator是在创建角色时已注入的ActorRef。 我们为此目的使用穷人的依赖注入。 让我们看一下actor工厂的定义:

lazy val itemFSMFactory: (ActorContext, ActorRef) => ActorRef =
 (context, self) => {
   val itemFSM = ItemFSM.props(itemReportedProducer, itemDeletedBus, coordinator = self)
   context.actorOf(itemFSM)
 }

创建Actor Pool时,该工厂将被调用n次(具体取决于池的大小)。

监督演员

我们的协调员负责资源库以及FSM以预期方式完成时的操作。 但是,我们没有谈论演员失败时会发生什么。 Akka有一个内置的机制来处理故障,称为监督 。 有不同的恢复策略,我们将采用“ Restart策略:

override val supervisorStrategy =
  OneForOneStrategy(maxNrOfRetries = 3, withinTimeRange = 15 seconds) {
    case e: Exception =>
      actorPool.putBack(sender())
      SupervisorStrategy.Restart
  }

正如Restart策略文档所述:

丢弃旧的Actor实例,并用新实例替换它,然后恢复消息处理。

该策略已在协调器中定义。 我们如何指定该协调员是要监督的FSM的父级? 记住我们是如何创建FSM的:

context.actorOf(itemFSM)

我们来看一下actorOf的actorOf

创建新演员作为此上下文的子演员

在协调器范围内调用itemFSMFactory 。 每个参与者都有一个上下文,其中包括发送者,自身和不同的元对象。 使用协调者的上下文创建一个actor会将那些actor绑定为父子。

摘要

多亏了Akka的构造和模式,以及Scala的功能和异步优势,我们可以轻松编写协调代码。 在下一篇文章中,我们将介绍如何测试Akka。

第一部分 | 第2部分 | 第3部分 | 第4部分

翻译自: https://www.javacodegeeks.com/2016/06/coordination-in-akka.html

阿卡接口

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值