AKKA底层实现原理
代码实现
import akka.actor.{Actor, ActorSystem, Props}
import com.typesafe.config.ConfigFactory
import scala.collection.mutable
import scala.concurrent.duration._
class Master extends Actor{
//将Worker信息存到map集合中
val map = new mutable.HashMap[String, WorkerInfo]()
override def preStart(): Unit = {
import context.dispatcher
context.system.scheduler.schedule(0.millisecond,15000.millisecond,self,CheckTimeOutWorker)
}
//消息的接受 此函数为偏函数 不需要写match
override def receive: Receive = {
//做模式匹配
case "hello" =>{
println("hello")
}
case CheckTimeOutWorker =>{
val deadWorker: Iterable[WorkerInfo] = map.values.filter(x => System.currentTimeMillis() - x.lastHeartbeatTime > 15000)
deadWorker.foreach(m =>{
map -= m.workerId
})
println(s"current alive worker size: ${map.size}")
}
//匹配worker发送来的注册信息
case Conf(workerId, memory, cores) => {
// println(s"workerId:$workerId,memory:$memory,cores:$cores")
//将Worker的数据存到内存中
val workInfo = new WorkerInfo(workerId, memory, cores)
map(workerId) = workInfo
//返回一个注册成功的响应
sender() ! Confed
}
//接受Worker的心跳 并更新心跳时间
case HeartBeat(workerId) => {
//根据workerId查找对应的Worker信息
if (map.contains(workerId)){
val workerInfo: WorkerInfo = map(workerId)
//更新Worker心跳的时间 更新到当前时间
workerInfo.lastHeartbeatTime = System.currentTimeMillis()
}
}
}
}
object Master{
def main(args: Array[String]): Unit = {
val host = "localhost"
val port = 8888
val configstr =
s"""
|akka.actor.provider = "akka.remote.RemoteActorRefProvider"
|akka.remote.netty.tcp.hostname = $host
|akka.remote.netty.tcp.port = $port
|""".stripMargin
val config = ConfigFactory.parseString(configstr)
//创建MasterActorSystem(单例)
val masterActorSystem = ActorSystem("MasterActorSystem", config)
//通过Master创建Actor
val masterActor = masterActorSystem.actorOf(Props[Master], "MasterActor")
//自己给自己发消息
masterActor ! "hello"
}
}
import java.util.UUID
import akka.actor.{Actor, ActorSelection, ActorSystem, Props}
import com.typesafe.config.ConfigFactory
import scala.concurrent.duration._
class Worker extends Actor{
var workerId = UUID.randomUUID().toString
var selection: ActorSelection = _
//是在构造方法之后,receive方法之前一定会调用一次
override def preStart(): Unit = {
//与master建立连接
selection = context.actorSelection("akka.tcp://MasterActorSystem@localhost:8888/user/MasterActor")
//向master注册信息
selection ! Conf(workerId, 2040, 4)
}
//消息的接受 此函数为偏函数 不需要写match
override def receive: Receive = {
//做模式匹配
case "hello" =>{
println("hello")
}
//向Master发送一个心跳
case SendHeartBeat =>{
selection ! HeartBeat(workerId)
}
//启动定时器
case Confed =>{
//导包 隐式转换
import context.dispatcher
context.system.scheduler.schedule(0.millisecond,10000.millisecond,self,SendHeartBeat)
}
}
}
object Worker{
def main(args: Array[String]): Unit = {
val host = "localhost"
val port = 9999
val configStr =
s"""
|akka.actor.provider = "akka.remote.RemoteActorRefProvider"
|akka.remote.netty.tcp.hostname = $host
|akka.remote.netty.tcp.port = $port
|""".stripMargin
val config = ConfigFactory.parseString(configStr)
//创建WorkerActorSystem
val workerActorSystem = ActorSystem("WorkerActorSysytem", config)
//通过WorkActorSystem创建WorkerActor
workerActorSystem.actorOf(Props[Worker], "WorkerActor")
}
}
case class Conf(workerId: String, memory: Int, cores: Int)
case object Confed
case class WorkerInfo(workerId: String, memory: Int, cores: Int){
var lastHeartbeatTime:Long = _
}
case object SendHeartBeat
case class HeartBeat(workerId: String)
case object CheckTimeOutWorker