hangscer

Akka入门

2017/04/29

actor远程引用demo

actor远程创建与引用看书平时直接略过,五一节在家闲来无事决定亲自用两台电脑实践一次.

thinkpad配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
akka{
loggers= ["akka.event.Logging$DefaultLogger"]
loglevel="DEBUG"
stdout-loglevel="DEBUG"
actor{
provider="akka.remote.RemoteActorRefProvider"
deployment{
}
default-dispatcher{
throughput=1
}
}
remote{
enabled-transports=["akka.remote.netty.tcp"]
netty.tcp{
hostname ="192.168.1.103"
port=2552
}
}
}

mac配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
akka {
loggers= ["akka.event.Logging$DefaultLogger"]
loglevel = "DEBUG"
stdout-loglevel = "DEBUG"
actor{
provider = "akka.remote.RemoteActorRefProvider"
default-dispatcher{
throughput = 1
}
}
remote{
enabled-transports = ["akka.remote.netty.tcp"]
netty.tcp{
hostname = "192.168.1.106"
port= 2552
}
}
}

thinkpad测试代码如下:

1
2
3
4
5
6
7
8
9
object Main extends App{
val actorSystem=ActorSystem("thinkpad")
val actor=actorSystem.actorOf(Props[Myactor],"greets")
}
class Myactor extends Actor{
override def receive: Receive = {
case obj => println("haha:"+obj)
}
}

mac测试代码如下:

1
2
3
4
5
6
7
8
object Main extends App {
val actorSystem=ActorSystem("mac")
val remoteActor=actorSystem.actorSelection("akka.tcp://thinkpad@192.168.1.103:2552/user/greets")
1 to 100 foreach({
i=> remoteActor!"ha"+i
Thread.sleep(1000)
})
}

actor远程之间传递消息

可传递消息包括数字 Stringcase class等.
mac端代码为:

1
2
package hang
case class Message(str:String)
1
2
3
4
5
val actorSystem=ActorSystem("mac")
val remoteActor=actorSystem.actorSelection("akka.tcp://thinkpad@192.168.1.103:2552/user/greets")
remoteActor!hang.Haha
Thread.sleep(1000)
remoteActor!hang.Message("hang")

thinkpad端代码为:

1
2
package hang
case class Message(str:String)
1
2
3
4
5
6
class Myactor extends Actor{
override def receive: Receive = {
case hang.Message(str) => println(str)
case obj=>println(obj)
}
}

actor远程消息传递是通过反射机制实现的,两台电脑中必须保证case class相同,且package一致.

远程创建actor

比如thinkpad上的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
akka{
...
deployment{
/someRemoteActor{ //如果写/user/someRemoteActor 则并不会远程创建节点
//若是在已创建的节点之下远程部署节点,路径如 /LoanRateQuotes/riskManager1
// /user节点不需要也不能明确写出来 此时路径比如: akka://mac2/remote/akka.tcp/mac@localhost:2553/user/LoanRateQuotes/riskManager1
remote="akka.tcp://mac@192.168.1.106:2552"
}
}
}
remote{
enabled-transports=["akka.remote.netty.tcp"]
netty.tcp{
hostname ="192.168.1.103"
port=2552
}
}
}

当Akka系统被告知需要创建/someRemoteActor这个路径的actor时,系统会去在akka.tcp://mac@192.168.1.106:2552这个akka系统中去远程创建它,路径为akka.tcp://mac@192.168.1.106:2552/remote/akka.tcp/thinkpad@192.168.1.103:2552/user/someRemoteActor,在/remote路径后,反映了该actor的逻辑路径,也可以看出someRemoteActor挂载于远程节点的虚拟remote节点上.
远程创建对象仍然使用了反射机制.
thinkpad端的代码(MyActor这个类与mac端的MyActor并不一样):

1
2
3
4
5
6
7
package myactor
import akka.actor.Actor
class Myactor extends Actor{
override def receive: Receive = {
case obj => println("received on Thinkpad:"+obj)
}
}
1
2
3
4
5
6
7
8
9
object Main extends App{
val actorSystem=ActorSystem("thinkpad")
val actor=actorSystem.actorOf(Props[Myactor],"someRemoteActor")
actor!11
Thread.sleep(1000)
//实际路径为akka.tcp://mac@192.168.1.106:2552/remote/akka.tcp/thinkpad@192.168.1.103:2552/user/someRemoteActor
//虚拟路径为akka.tcp/thinkpad@192.168.1.103:2552/user/someRemoteActor 这里用虚拟路径也可成功
actorSystem.actorSelection("/user/someRemoteActor")!213123213 //
}

ActorRef并不如actorSelection可靠,ActorRef可能会指向已经停止的或者不存在的Actor对象,另一方面,ActorSelection选择路径是以ActorPath为基础的,通过路径发送消息使得akka框架内部通过路径查找Actor对象.原因在于:

当Actor对象重启后,它的ActorRef引用会改变,但是它的Actor系统路径不变.

mac端代码:

1
2
3
4
5
6
7
package myactor
import akka.actor.Actor
class Myactor extends Actor{
override def receive: Receive = {
case obj => println("received on Mac:"+obj)
}
}
1
2
3
object Main extends App {
val actorSystem=ActorSystem("mac")
}

由于someRemoteActor在mac端创建(反射),则实际打印的应该是received on Mac:xx而非received on Thinkpad:xx .