上篇我们讨论了Akka-Remoting。我们说Akka-Remoting是一种点对点的通讯方式,能使两个不同JVM上Akka-ActorSystem上的两个Actor之间可以相互沟通。Akka-Remoting还没有实现完全的Actor位置透明(location transparency),因为一个Actor还必须在获得对方Actor确切地址信息后才能启动与之沟通过程。Akka-Remoting支持“远程查找”和“远程构建”两种沟通方式。由于篇幅所限,我们只介绍了“远程查找”。在这一篇里我们将会讨论“远程构建”方式。

同样,我们先通过项目结构来分析:

lazy val local = (project in file("."))
.settings(commonSettings)
.settings(
name := "remoteCreateDemo"
).aggregate(calculator,remote).dependsOn(calculator) lazy val calculator = (project in file("calculator"))
.settings(commonSettings)
.settings(
name := "calculator"
) lazy val remote = (project in file("remote"))
.settings(commonSettings)
.settings(
name := "remoteSystem"
).aggregate(calculator).dependsOn(calculator)

远程构建的过程大致是这样的:由local通知remote启动构建Actor;remote从本地库中查找Actor的类定义(class)并把它载入内存。由于驱动、使用远程Actor是在local进行的,所以local,remote项目还必须共享Calculator,包括Calculator的功能消息。这项要求我们在.sbt中用aggregate(calculator)来协同编译。

我们把Calculator的监管supervisor也包括在这个源码文件里。现在这个calculator是个包括监管、功能、消息的完整项目了。Calculator源代码如下:

package remoteCreation.calculator

import akka.actor._
import scala.concurrent.duration._ object Calcultor {
sealed trait MathOps
case class Num(dnum: Double) extends MathOps
case class Add(dnum: Double) extends MathOps
case class Sub(dnum: Double) extends MathOps
case class Mul(dnum: Double) extends MathOps
case class Div(dnum: Double) extends MathOps sealed trait CalcOps
case object Clear extends CalcOps
case object GetResult extends CalcOps def props = Props(new Calcultor)
def supervisorProps = Props(new SupervisorActor)
} class Calcultor extends Actor with ActorLogging {
import Calcultor._ var result: Double = 0.0 //internal state override def receive: Receive = {
case Num(d) => result = d
case Add(d) => result += d
case Sub(d) => result -= d
case Mul(d) => result *= d
case Div(d) =>
val _ = result.toInt / d.toInt //yield ArithmeticException
result /= d
case Clear => result = 0.0
case GetResult =>
sender() ! s"Result of calculation is: $result"
} override def preRestart(reason: Throwable, message: Option[Any]): Unit = {
log.info(s"Restarting calculator: ${reason.getMessage}")
super.preRestart(reason, message)
}
} class SupervisorActor extends Actor {
def decider: PartialFunction[Throwable,SupervisorStrategy.Directive] = {
case _: ArithmeticException => SupervisorStrategy.Resume
} override def supervisorStrategy: SupervisorStrategy =
OneForOneStrategy(maxNrOfRetries = , withinTimeRange = seconds){
decider.orElse(SupervisorStrategy.defaultDecider)
} val calcActor = context.actorOf(Calcultor.props,"calculator") override def receive: Receive = {
case msg@ _ => calcActor.forward(msg)
} }

与上一个例子的”远程查找式“相同,remote需要为Remoting公开一个端口。我们可以照搬.conf配置文件内容:remote/src/main/resources/application.conf

akka {
actor {
provider = remote
}
remote {
enabled-transports = ["akka.remote.netty.tcp"]
netty.tcp {
hostname = "127.0.0.1"
port =
}
log-sent-messages = on
log-received-messages = on
}
}

由于远程构建和使用是在local上进行的,在remote上我们只需要启动ActorSystem就行了:

import com.typesafe.config.ConfigFactory
import akka.actor._ object CalculatorRunner extends App {
val remoteSystem = ActorSystem("remoteSystem",ConfigFactory.load("application"))
println("Remote system started.") scala.io.StdIn.readLine()
remoteSystem.terminate() }

Calculator的构建是在localSystem上启动的,我们需要在配置文件中描述远程构建标的(还是未能实现位置透明):local/src/main/resources/application.conf

akka {
actor {
provider = remote,
deployment {
"/calculator" {
remote = "akka.tcp://remoteSystem@127.0.0.1:2552"
}
}
}
remote {
netty.tcp {
hostname = "127.0.0.1",
port=
}
}
}

注意:上面这个/calculator设置实际上指的是SupervisorActor。

现在我们可以在local上开始构建calculator,然后使用它来运算了:

import akka.actor._
import remoteCreation.calculator.Calcultor._
import scala.concurrent.duration._
import akka.pattern._ object RemotingCreate extends App {
val localSystem = ActorSystem("localSystem")
val calcActor = localSystem.actorOf(props,
name = "calculator") //created SupervisorActor import localSystem.dispatcher calcActor ! Clear
calcActor ! Num(13.0)
calcActor ! Mul(1.5) implicit val timeout = akka.util.Timeout( second) ((calcActor ? GetResult).mapTo[String]) foreach println
scala.io.StdIn.readLine() calcActor ! Div(0.0)
calcActor ! Div(1.5)
calcActor ! Add(100.0)
((calcActor ? GetResult).mapTo[String]) foreach println scala.io.StdIn.readLine()
localSystem.terminate() }

从代码上看构建calculator(SupervisorActor)过程与普通的Actor构建没分别,所有细节都放在配置文件里了。但是,要注意actorOf的name必须与配置文档中的设置匹配。

试运行结果与上一个例子相同。值得注意的是实际远程构建的是一个SupervisorActor。Calculator的构建是SupervisorActor构建的其中一部分。从运算结果看:这个SupervisorActor也实现了它的功能。

下面是这次示范的源代码:

local/build.sbt

azy val commonSettings = seq (
name := "RemoteCreateDemo",
version := "1.0",
scalaVersion := "2.11.8",
libraryDependencies := Seq(
"com.typesafe.akka" %% "akka-actor" % "2.5.2",
"com.typesafe.akka" %% "akka-remote" % "2.5.2"
)
) lazy val local = (project in file("."))
.settings(commonSettings)
.settings(
name := "remoteCreateDemo"
).aggregate(calculator).dependsOn(calculator) lazy val calculator = (project in file("calculator"))
.settings(commonSettings)
.settings(
name := "calculator"
) lazy val remote = (project in file("remote"))
.settings(commonSettings)
.settings(
name := "remoteSystem"
).aggregate(calculator).dependsOn(calculator)

calculator/calculator.scala

package remoteCreation.calculator

import akka.actor._
import scala.concurrent.duration._ object Calcultor {
sealed trait MathOps
case class Num(dnum: Double) extends MathOps
case class Add(dnum: Double) extends MathOps
case class Sub(dnum: Double) extends MathOps
case class Mul(dnum: Double) extends MathOps
case class Div(dnum: Double) extends MathOps sealed trait CalcOps
case object Clear extends CalcOps
case object GetResult extends CalcOps def props = Props(new Calcultor)
def supervisorProps = Props(new SupervisorActor)
} class Calcultor extends Actor with ActorLogging {
import Calcultor._ var result: Double = 0.0 //internal state override def receive: Receive = {
case Num(d) => result = d
case Add(d) => result += d
case Sub(d) => result -= d
case Mul(d) => result *= d
case Div(d) =>
val _ = result.toInt / d.toInt //yield ArithmeticException
result /= d
case Clear => result = 0.0
case GetResult =>
sender() ! s"Result of calculation is: $result"
} override def preRestart(reason: Throwable, message: Option[Any]): Unit = {
log.info(s"Restarting calculator: ${reason.getMessage}")
super.preRestart(reason, message)
}
} class SupervisorActor extends Actor {
def decider: PartialFunction[Throwable,SupervisorStrategy.Directive] = {
case _: ArithmeticException => SupervisorStrategy.Resume
} override def supervisorStrategy: SupervisorStrategy =
OneForOneStrategy(maxNrOfRetries = , withinTimeRange = seconds){
decider.orElse(SupervisorStrategy.defaultDecider)
} val calcActor = context.actorOf(Calcultor.props,"calculator") override def receive: Receive = {
case msg@ _ => calcActor.forward(msg)
} }

remote/src/main/resources/application.conf

akka {
actor {
provider = remote
}
remote {
enabled-transports = ["akka.remote.netty.tcp"]
netty.tcp {
hostname = "127.0.0.1"
port =
}
log-sent-messages = on
log-received-messages = on
}
}

remote/CalculatorRunner.scala

package remoteCreation.remote
import com.typesafe.config.ConfigFactory
import akka.actor._ object CalculatorRunner extends App {
val remoteSystem = ActorSystem("remoteSystem",ConfigFactory.load("application"))
println("Remote system started.") scala.io.StdIn.readLine()
remoteSystem.terminate() }

local/src/main/resources/application.conf

akka {
actor {
provider = remote,
deployment {
"/calculator" {
remote = "akka.tcp://remoteSystem@127.0.0.1:2552"
}
}
}
remote {
netty.tcp {
hostname = "127.0.0.1",
port=
}
}
}

local/RemotingCreation.scala

import akka.actor._
import remoteCreation.calculator.Calcultor._
import scala.concurrent.duration._
import akka.pattern._ object RemotingCreate extends App {
val localSystem = ActorSystem("localSystem")
val calcActor = localSystem.actorOf(props,
name = "calculator") //created SupervisorActor import localSystem.dispatcher calcActor ! Clear
calcActor ! Num(13.0)
calcActor ! Mul(1.5) implicit val timeout = akka.util.Timeout( second) ((calcActor ? GetResult).mapTo[String]) foreach println
scala.io.StdIn.readLine() calcActor ! Div(0.0)
calcActor ! Div(1.5)
calcActor ! Add(100.0)
((calcActor ? GetResult).mapTo[String]) foreach println scala.io.StdIn.readLine()
localSystem.terminate() }

Akka(9): 分布式运算:Remoting-远程构建式的更多相关文章

  1. Akka(10): 分布式运算:集群-Cluster

    Akka-Cluster可以在一部物理机或一组网络连接的服务器上搭建部署.用Akka开发同一版本的分布式程序可以在任何硬件环境中运行,这样我们就可以确定以Akka分布式程序作为标准的编程方式了. 在上 ...

  2. Akka(13): 分布式运算:Cluster-Sharding-运算的集群分片

    通过上篇关于Cluster-Singleton的介绍,我们了解了Akka为分布式程序提供的编程支持:基于消息驱动的运算模式特别适合分布式程序编程,我们不需要特别的努力,只需要按照普通的Actor编程方 ...

  3. alpakka-kafka(9)-kafka在分布式运算中的应用

    kafka具备的分布式.高吞吐.高可用特性,以及所提供的各种消息消费模式可以保证在一个多节点集群环境里消息被消费的安全性:即防止每条消息遗漏处理或重复消费.特别是exactly-once消费策略:可以 ...

  4. Jenkins 远程构建任务

    开发过程中提交代码以后,如何不登录Jenkins就自动触发jenkins 任务来发布软件版本. 1.首先我们创建一个Jenkins任务. 2.选择"构建触发器"->勾选&qu ...

  5. jenkins构建触发器详解-不登录触发远程构建详解

    利用jenkins的远程构建功能,我们可以使用任何脚本,甚至定制一个Web页来控制Job的执行,但是远程构建你如果直接使用的话,老是需要登录才能执行,如何避免登录?稍微折腾了一下,调通了. 1.首先去 ...

  6. jenkins构建触发器详解-不登录触发远程构建

    利用jenkins的远程构建功能,我们可以使用任何脚本,甚至定制一个Web页来控制Job的执行,但是远程构建你如果直接使用的话,老是需要登录才能执行,如何避免登录?稍微折腾了一下,调通了. 1.首先去 ...

  7. Jenkins进阶-远程构建任务(4)

    开发过程中提交代码以后,如何不登录Jenkins就自动触发jenkins 任务来发布软件版本. 1.首先我们创建一个Jenkins任务. 2.选择"构建触发器"->勾选&qu ...

  8. Linux centos 安装 jenkins & 本地构建jar & 远程构建jar

    一.部署 jenkins 需要的前奏 1.安装 JDK:https://www.cnblogs.com/chuyi-/p/10644440.html 2.安装tomcat:https://www.cn ...

  9. [源码解析] PyTorch 分布式(11) ----- DistributedDataParallel 之 构建Reducer

    [源码解析] PyTorch 分布式(11) ----- DistributedDataParallel 之 构建Reducer 目录 [源码解析] PyTorch 分布式(11) ----- Dis ...

随机推荐

  1. MongoDB Java Driver 3.4操作

    导入jar包 <dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-dr ...

  2. Python 学习——高阶函数 filter 和 sorted

    filter filter函数顾名思义,筛选,通过调用函数进行筛选序列中的满足函数的子项 以实例来说话: 过滤一个序列中所有的偶数,保留奇数 另如下,过滤掉一个序列中的所有空格以及空字符等信息 可以知 ...

  3. C语言模拟实现多态

    一.多态的主要特点 1.继承体系下.继承:是面向对象最显著的一个特性.继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性 和行为,并能扩展新的能力,已有类被称为父类/基类,新增加的类被称作子 ...

  4. hdu4597 Play Game 区间DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4597 全国邀请赛通化赛区第8题--题目重现 思路: 区间DP的思想,想法是队友想出来的,感觉很秒,自己 ...

  5. javascript设计模式详解之策略模式

    接上篇命令模式来继续看下js设计模式中另一种常用的模式,策略模式.策略模式也是js开发中常用的一种实例,不要被这么略显深邃的名字给迷惑了.接下来我们慢慢看一下. 一.基本概念与使用场景: 基本概念:定 ...

  6. 自己编写jQuery动态引入js文件插件 (jquery.import.dynamic.script)

    这个插件主要是结合jquery或者xhr异步请求来使用的,它可以把已经引入过的js文件记录在浏览器内存中,当下次再引入相同的文件就忽略该文件的引入. 此插件不支持浏览器刷新保存数据,那需要利用cook ...

  7. C# 时间格式总结

    C#时间/日期格式大全 C#时间/日期格式大全,C#时间/日期函数大全 有时候我们要对时间进行转换,达到不同的显示效果 默认格式为:2005-6-6 14:33:34 如果要换成成200506,06- ...

  8. LR11 scan correlation 卡死解决方案

    LR11 scan correlation 卡死解决方案 笔者在录制脚本时是勾选Enable correlation during recording的,导致后续每次脚本回放都会弹出scan corr ...

  9. iOS 开发之 protocol Buffer 数据交换

    前言: 从 14 年公司做项目时开始接触 Google 的 protocol Buffer,用了一段时间,后来到新公司就没有机会再使用了,趁着还没完全忘记,记录下. 简介:protocolbuffer ...

  10. mysql5.6 主从复制

    Master 192.168.59.128 Slave 192.168.59.129   默认认为已安装mysql5.6  mysql5.6 rpm安装配置 修改Master my.cnf文件   # ...