LoginSignup
13
7

More than 5 years have passed since last update.

Akka-Remote使ってみた

Posted at

Akka-Remoteを使ってみた

なにができるものなの?

  • Actorがサーバをまたいで作成、コミュニケーションできるようになるもの

Actorってそもそもなに?

  • Actor Modelで登場するActor
  • Actor同士は非同期なメッセージでやりとりが行われる
  • 位置透過性を実現することができる <- ここが重要

位置透過性って?

  • Actorが同じマシン上にいても、リモート上にいても同じように扱えること

改めて、なにができるもの?

  • Actorの特徴の位置透過性を実現するためにAkka-Remoteが使えるよ。
  • Akka-Remoteを使えばとっても簡単に特定のActorを別のサーバで動かすことができる

使って見た

まずはローカルで動くActorを作ってみる

  • src/main/resource/application.confを作っておこう

akka {
  actor {
    provider = "local"
  }
}

  • ActorSystemの生成、Actorの生成
Main.scala
object Court {
  def main(args: Array[String]): Unit = {
    val config = ConfigFactory.load("application.conf")
    implicit val timeout: Timeout = Timeout(5000.milliseconds)
    implicit val system: ActorSystem = ActorSystem("Tennis", config)
    val playerA = system.actorOf(Props(classOf[TennisPlayer], "A", "a-!!"), "playerA")
    val playerB = system.actorOf(Props(classOf[TennisPlayer], "B", "un~~!"), "playerB")

    playerA ! GameStart(playerB)

    Thread.sleep(1000)
    system.terminate()
    sys.exit()
  }
}

case class TennisPlayer(name: String, howling: String) extends Actor {
  override def receive: Receive = {
    case Ball(vsPlayer) =>
      stroke(vsPlayer)
    case GameStart(vsPlayer) =>
      serve(vsPlayer)
  }

  def stroke(vsPlayer: ActorRef): Unit = {
    println(s"${name} < ${howling}!")
    vsPlayer ! Ball(self)
  }

  def serve(vsPlayer: ActorRef): Unit = {
    println(s"${name} < serve!!!")
    vsPlayer ! Ball(self)
  }
}

case class Ball(player: ActorRef)

case class GameStart(vsPlayer: ActorRef)


Court.mainを実行するとコンソールにプレイヤーA, Bが交互に叫びます。

A < serve!!!
B < un~~!!
A < a-!!!
B < un~~!!
A < a-!!!
B < un~~!!

別のサーバにActorを移してみた

application.confを修正する

  • providerをremoteに変更しする
  • /playerBのパスに生成されるActorを"akka.tcp://bCourt@127.0.0.1:2553"が指すサーバ上にあるActorSystemで動かすために、 "/playerB"の"remote"に"akka.tcp://bCourt@127.0.0.1:2553"を渡してる
  • この設定をconfに書いておいて、providerremoteであれば
system.actorOf(Props(classOf[TennisPlayer], "B", "un~~!"), "playerB")

system.actorOfで第二引数でpathを指定するときにplayerBにした場合、application.confから勝手に設定を読み込んでActorを生成してくれる

application.conf

akka {
  actor {
    provider = "remote"
    deployment {
      "/playerB" {
        # playerB Actorを動かすパスとポートを指定する
        # この先ではAkka Remoteによってactorのデプロイを受け付けるサーバになっている
        remote = "akka.tcp://bCourt@127.0.0.1:2553" 
      }
    }
  }
}

playerBが動くActorSystemの用意

  • playerAが動くActorSystemがいるサーバとは別のサーバにする
  • bCourtという名でActorSystemを作る
object PlayerBCourt {
  def main(args: Array[String]): Unit = {
    implicit val timeout: Timeout = Timeout(5000.milliseconds)
    val config = ConfigFactory.load("bCourt-application.conf")
    ActorSystem("bCourt", config)
  }
}
  • bCourtのためのbCourt-application.confを作る
akka {
  actor {
    provider = "remote"
  }

  remote {
    enabled-transports = ["akka.remote.netty.tcp"]
    netty.tcp {
      hostname = "127.0.0.1"
      port = 2553
    }
  }
}

Actor同士でやりとりをしてみる

  • 二つのターミナルウィンドウを用意してそれぞれBCourt, Courtmainを実行する
  • BCourtではBさんが吠えながらボールを返し、もう一方ではAさんがボールを返します

スクリーンショット 2017-11-28 11.31.48.png

できたね!

  • application.confの akka.actor.providerを localにすれば1つのサーバ上でコンソール出力がされ、remoteにすれば二つのコンソール上から出力がされる
  • ↑の切り替えはapplication.confのakka.actor.providerを localremoteにするだけでできて、ソースコードには変更はなしでできるね
  • ソースコード上ではメッセージを送る相手が、どこにいるのか意識しなくて良いね
13
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
7