Akka是一种消息驱动运算模式,它实现跨JVM程序运算的方式是通过能跨JVM的消息系统来调动分布在不同JVM上ActorSystem中的Actor进行运算,前题是Akka的地址系统可以支持跨JVM定位。Akka的消息系统最高境界可以实现所谓的Actor位置透明化,这样在Akka编程中就无须关注Actor具体在哪个JVM上运行,分布式Actor编程从方式上跟普通Actor编程就不会有什么区别了。Akka的Remoting是一种点对点的跨JVM消息通道,让一个JVM上ActorSystem中的某个Actor可以连接另一个JVM上ActorSystem中的另一个Actor。两个JVM上的ActorSystem之间只需具备TCP网络连接功能就可以实现Akka Remoting了。Akka-Remoting还没有实现完全的位置透明化,因为用户还必须在代码里或者配置文件里指明目标Actor的具体地址。
Akka-Remoting提供了两种Actor之间的沟通方法:
1、远程查找:通过路径Path查找在远程机上已经创建存在的Actor,获取ActorRef后进行沟通
2、远程创建:在远程机上直接创建Actor作为沟通对象
Akka-Remoting的主要应用应该是把一些任务部署到远程机上去运算。发起方(Local JVM)在这里面的主要作用是任务分配,有点像Akka-Router。我们可以用下面的例子来示范:模拟一个计算器,可以进行连续的加减乘除,保留累计结果。我们会把这个计算器部署到远程机上,然后从本机与之沟通分配运算任务及获取运算结果。这个计算器就是个简单的Actor:
import akka.actor._ object Calculator { 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 } class Calcultor extends Actor { import Calculator._ 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) => result = result / d case Clear => result = 0.0
case GetResult => sender() ! s"Result of calculation is: $result" } }
就是一个简单的Actor实现,跟Remoting没什么关系。
下面我们会在一个远程机上部署这个Calculator Actor。 先看看这个示范的项目结构:remoteLookup/build.sbt
lazy val commonSettings = seq ( name := "RemoteLookupDemo", 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 := "localSystem" ).aggregate(messages,remote).dependsOn(messages) lazy val messages = (project in file("messages")) .settings(commonSettings) .settings( name := "commands" ) lazy val remote = (project in file("remote")) .settings(commonSettings) .settings( name := "remoteSystem" ).aggregate(messages).dependsOn(messages)
在这里我们分了三个项目:local是主项目,messages和remote是分项目(subprojects)。messages里只有OpsMessages.scala一个源文件:
package remoteLookup.messages object Messages { 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 }
我们看到:这个文件是把上面的Calculator支持的消息拆了出来。这是因为Calculator Actor会在另一个JVM remote上部署,而我们会从local JVM里向Calculator发送操作消息,所以Messages必须是local和remote共享的。这个要求我们通过dependOn(messages)实现了。现在Calculator是在remote项目里定义的:remote/Calculator.scala
package remoteLookup.remote import akka.actor._ import remoteLookup.messages.Messages._ object CalcProps { def props = Props(new Calcultor) } class Calcultor extends Actor with ActorLogging { var