1. 消息的传递,从一个Actor到另一个Actor或者从自己到自己。
//网络通信需要序列化反序列化
trait RemoteMessage extends Serializable
//Woker-->Master
case class RegisterWoker(wokerId:String , momery:Int, cores:Int) extends RemoteMessage
//Master-->Woker
case class RegisteredWoker(masterURL:String) extends RemoteMessage
//Woker-->Woker
case object SendHeartbeat
//Woker-->Master
case class Heartbeat(wokerId:String) extends RemoteMessage
//Master-->Master
case object CheckTimeOutWoker
2. WokeInfo
class WokerInfo(val wokerId:String,val memory:Int, val cores:Int){
//上次一心跳的时间
var lastHeartbeatTime:Long = _
}
3.Woker类
import java.util.UUID
import scala.concurrent.duration._
import akka.actor.{Actor, ActorSelection, ActorSystem, Props}
import com.typesafe.config.ConfigFactory
class Woker(val host:String, val port:Int, val momery:Int, val cores:Int) extends Actor{
val wokerId:String = UUID.randomUUID().toString
var master:ActorSelection = _
var Time = 10000
override def preStart(): Unit = {
import context.dispatcher
master = context.actorSelection(s"akka.tcp://MasterSystem@$host:$port/user/Master")
master ! RegisterWoker(wokerId,momery,cores)
}
override def receive: Receive = {
case RegisteredWoker(masterURL) =>{
println("注册成功! 地址"+masterURL)
import context.dispatcher
context.system.scheduler.schedule(0 millis,Time millis,self,SendHeartbeat)
}
case SendHeartbeat => {
//发送心跳
println("发送心跳")
master ! Heartbeat(wokerId)
}
}
}
object Woker {
def main(args: Array[String]): Unit = {
val host: String = args( 0 )
val port: Int = args( 1 ).toInt
val configString: String =
s"""
|akka.actor.provider = "akka.remote.RemoteActorRefProvider"
|akka.remote.netty.tcp.hostname = "$host"
|akka.remote.netty.tcp.port = "$port"
""".stripMargin
val config = ConfigFactory.parseString( configString )
val actorSystem = ActorSystem( "WokerSystem", config )
actorSystem.actorOf( Props( new Woker( args( 2 ), args( 3 ).toInt, args( 4 ).toInt, args( 5 ).toInt ) ), "Woker" )
actorSystem.awaitTermination()
}
}
4. Master类
import java.util.UUID
import akka.actor
import scala.concurrent.duration._
import akka.actor.{Actor, ActorSelection, ActorSystem, Props}
import com.typesafe.config.ConfigFactory
import scala.collection.mutable
class Master(val host:String, val port:Int) extends Actor{
val idToWoker = new mutable.HashMap[String,WokerInfo]()
val wokers = new mutable.HashSet[WokerInfo]()
val Time = 15000
override def preStart(): Unit = {
import context.dispatcher
context.system.scheduler.schedule(0 millis,Time millis,self,CheckTimeOutWoker)
}
override def receive: Receive = {
case RegisterWoker(wokerId,momery,cores) =>{
if(!idToWoker.contains(wokerId)){
val wokerInfo = new WokerInfo(wokerId,momery,cores)
idToWoker(wokerId) = wokerInfo
wokers+=wokerInfo
}
println("一个Woker注册了")
sender ! RegisteredWoker(s"akka.tcp://MasterSystem@$host:$port/user/Master")
}
case Heartbeat(wokerId) =>{
val currentTime = System.currentTimeMillis()
if(idToWoker.contains(wokerId)){
val wokerInfo = idToWoker(wokerId)
wokerInfo.lastHeartbeatTime = currentTime
}
}
case CheckTimeOutWoker =>{
val currentTime = System.currentTimeMillis()
val remote = wokers.filter(t=>currentTime-t.lastHeartbeatTime>=15000)
for(r<-remote){
wokers-=r
idToWoker-=r.wokerId
println("一个Woker断开了")
}
println("现有Woker:"+wokers.size)
}
}
}
object Master{
def main(args: Array[String]): Unit = {
val host:String = args(0)
val port:Int = args(1).toInt
val configString:String = s"""
|akka.actor.provider = "akka.remote.RemoteActorRefProvider"
|akka.remote.netty.tcp.hostname = "$host"
|akka.remote.netty.tcp.port = "$port"
""".stripMargin
val config = ConfigFactory.parseString(configString)
val actorSystem = ActorSystem("MasterSystem",config)
actorSystem.actorOf(Props(new Master(host,port)),"Master")
actorSystem.awaitTermination()
}
}
//s"akka.tcp://MasterSystem@$host:$port/user/Master"