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に書いておいて、
provider
がremote
であれば
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
,Court
のmain
を実行する - BCourtではBさんが吠えながらボールを返し、もう一方ではAさんがボールを返します
できたね!
- application.confの akka.actor.providerを
local
にすれば1つのサーバ上でコンソール出力がされ、remote
にすれば二つのコンソール上から出力がされる - ↑の切り替えはapplication.confのakka.actor.providerを
local
かremote
にするだけでできて、ソースコードには変更はなしでできるね - ソースコード上ではメッセージを送る相手が、どこにいるのか意識しなくて良いね