akka构建简单分布式应用

当程序的要求达到一台计算机的极限时,我们便需要将程序分布式化,让程序运行在多台计算机上。akka提供了remote actor用来构建分布式应用。

一、remote actor

1.Actor path

  actor的路径设计采用了类似URL的形式,即scheme://domain:port/path。scheme代表协议(http或者ftp),domain代表域名或者ip地址,port代表端口,path代表路径。所以表示一个actor的路径是akka://ServerSys@10.102.141.77:2552/user/SomeActor。路径表示远程actor的主机ip是10.102.141.77,端口是2552,actorsystem是ServerSys,Actor的名字是SomeActor。通过Actor path,我们就可以远程访问一个actor,进而进行消息的传递。

2.Actor引用

当知道远程actor的url后,我们便可以远程访问一个actor。访问通过引用远程actor来实现。

val actor = context.actorFor("akka://actorSystemName@10.0.0.1:2552/user/actorName")

一旦得到了actor的引用,你就可以象与本地actor通讯一样与它进行通迅了

actor ! "Pretty awesome feature"

二、一个简单例子

有一个本地actor:LocalActor,一个远程actor:RemoteActor。我们要实现相互之间的通信。LocalActor向RemoteActor发送一个消息"Hi there",RemoteActor返回"Hi there got something"。

1.remote端。

remote端的目录结构如下

 包含四个文件:application.conf,build.sbt,RemoteNodeApplication.scala,RemoteActor.scala

application.conf:

RemoteSys {
    akka {
          actor {
            provider = "akka.remote.RemoteActorRefProvider"
          }
       remote {
        transport = "akka.remote.netty.NettyRemoteTransport"
        netty {
          hostname = "192.168.178.192"
          port = 2552
        }
      }
    }
}
View Code

build.sbt

name := "RemotingExampleRemoteNode"

version := "1.0"

scalaVersion := "2.9.1"

resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"

libraryDependencies ++= Seq(
"com.typesafe.akka" % "akka-actor" % "2.0.2",
"com.typesafe.akka" % "akka-remote" % "2.0.2",
"com.typesafe.akka" % "akka-kernel" % "2.0.2"
)
View Code

RemoteActor.scala

package org.akka.essentials.remotenode
import akka.actor.Actor

class RemoteActor extends Actor {
  def receive: Receive = {
    case message: String =>
      // Get reference to the message sender and reply back
      sender.tell(message + " 192.168.178.192 got something")
  }
}
View Code

RemoteNodeApplication.scala

package org.akka.essentials.remotenode
import akka.kernel.Bootable
import akka.actor.ActorSystem
import akka.actor.Props
import com.typesafe.config.ConfigFactory

object RemoteActorSystem{
  def main(args: Array[String]):Unit = {
    val system = ActorSystem("RemoteNodeApp", ConfigFactory.load().getConfig("RemoteSys"))
    val remoteActor = system.actorOf(Props[RemoteActor], name = "remoteActor")
  }
}
View Code

sbt package进行编译,然后sbt run运行程序。

Remote端如果要以独立微内核的形式使用,RemoteNodeApplication.scala如下

RemoteNodeApplication.scala

package org.akka.essentials.remotenode
import akka.kernel.Bootable
import akka.actor.ActorSystem
import akka.actor.Props
import com.typesafe.config.ConfigFactory

class RemoteNodeApplication extends Bootable {
  val system = ActorSystem("RemoteNodeApp", ConfigFactory
    .load().getConfig("RemoteSys"))

  def startup = {
    system.actorOf(Props[RemoteActor], name = "remoteActor")
  }

  def shutdown = {
    system.shutdown()
  }
}
View Code

微内核的使用参考参考文献4.

2.Local端程序

目录结构同Remote端。也是包含四个文件:application.conf,build.sbt,LocalActor.scala,LocalNodeApplication.scala。

application.conf

LocalSys {
    akka {
          actor {
            provider = "akka.remote.RemoteActorRefProvider"
          }
    }
}
View Code

build.sbt

name := "RemotingExampleLocalNode"

version := "1.0"

scalaVersion := "2.9.1"

resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"

libraryDependencies ++= Seq(
"com.typesafe.akka" % "akka-actor" % "2.0.2",
"com.typesafe.akka" % "akka-remote" % "2.0.2",
"com.typesafe.akka" % "akka-kernel" % "2.0.2"
)
View Code

LocalActor.scala

package org.akka.essentials.localnode
import akka.actor.Actor
import akka.actor.ActorLogging
import akka.actor.Address
import akka.actor.Deploy
import akka.actor.Props
import akka.dispatch.Await
import akka.pattern.ask
import akka.remote.RemoteScope
import akka.util.duration.intToDurationInt
import akka.util.Timeout

class LocalActor extends Actor with ActorLogging {

  //Get a reference to the remote actor
  val remoteActor = context.actorFor("akka://RemoteNodeApp@192.168.178.192:2552/user/remoteActor")
  implicit val timeout = Timeout(5 seconds)
  def receive: Receive = {
    case message: String =>
      val future = (remoteActor ? message).mapTo[String]
      val result = Await.result(future, timeout.duration)
      log.info("Message received from Server -> {}", result)
  }
}
View Code

LocalNodeApplication.scala

package org.akka.essentials.localnode
import com.typesafe.config.ConfigFactory
import akka.actor.ActorSystem
import akka.actor.Props

object LocalNodeApplication {

  def main(args: Array[String]): Unit = {
    // load the configuration
    val config = ConfigFactory.load().getConfig("LocalSys")
    val system = ActorSystem("LocalNodeApp", config)
    val clientActor = system.actorOf(Props[LocalActor])
    clientActor ! "Hello"
    Thread.sleep(4000)
    system.shutdown()
  }
}
View Code

运行结果如下(拖动图片或者另存为可以看大图)

 local端和Remote端的代码见:https://github.com/hequn8128/akka/tree/master/AkkaRemotingExample

参考文献:

1.akka官方文档中文版:http://www.gtan.com/akka_doc/index.html

2.akka essential by Munish K.G

3.akka essential code:https://github.com/write2munish/Akka-Essentials/tree/master/AkkaRemotingExample

4.akka微内核:http://www.gtan.com/akka_doc/modules/microkernel.html#microkernel

posted on 2014-06-02 20:30  hequn8128  阅读(3992)  评论(1编辑  收藏  举报

导航