package com.skey.litespark.common
// 用於worker向master發送註冊的消息
case class RegisterWorkerInfo(id: String, cores: Int, mem: Int)
// 用於master向worker發送註冊成功的消息
case object RegisteredWorkerInfo
// 用於worker向master發送心跳
case class HeartBeat(id: String)
// 用於worker內部觸發發送心跳的動作
case object SendHeartBeat
// 用於master內部啓動worker心跳檢測
case object StartTimeOutWorker
// 用於master內部移除超時的worker
case object RemoveTimeOutWorker
// master內部維護的worker信息
class WorkerInfo(val id: String, cores: Int, mem: Int) {
var lastHeartBeat: Long = System.currentTimeMillis()
}
Master
import akka.actor.{Actor, ActorRef, ActorSystem, Props}
import com.skey.litespark.common._
import com.typesafe.config.ConfigFactory
import scala.collection.mutable
import scala.concurrent.duration._
/**
* Master
*
* @author ALion
* @version 2019/4/21 11:43
*/
class LiteMaster extends Actor {
/**
* 存儲worker的信息
*/
val workerMap = mutable.HashMap[String, WorkerInfo]()
private val MAX_DELAY = 60 * 1000
/**
* 收到消息後會調用receive,然後匹配對應的消息,做出不同的響應
* @return
*/
override def receive: Receive = {
case "start" =>
// 啓動
println("Master 啓動成功!")
self ! StartTimeOutWorker
case StartTimeOutWorker =>
// 定時檢測worker心跳
println("啓動定時檢測Worker心跳任務")
import context.dispatcher
context.system.scheduler.schedule(0 millis, 30000 millis, self, RemoveTimeOutWorker)
case RemoveTimeOutWorker =>
// 移除心跳超時的worker
val nowTime = System.currentTimeMillis()
workerMap.values
.filter(nowTime - _.lastHeartBeat > MAX_DELAY)
.foreach { worker =>
workerMap.remove(worker.id)
println(s"移除了worker(id=${worker.id}), 因爲心跳超時!")
}
case RegisterWorkerInfo(id, cores, mem) =>
// 註冊worker到master
if (!workerMap.contains(id)) {
workerMap.put(id, new WorkerInfo(id, cores, mem))
// 註冊成功後,向發送消息的worker返回消息
sender() ! RegisteredWorkerInfo
println(s"worker(id=$id) 註冊成功!")
}
case HeartBeat(id) =>
// 收到worker的心跳後,更新本地維護的worker心跳時間
workerMap.get(id) match {
case Some(workerInfo) =>
workerInfo.lastHeartBeat = System.currentTimeMillis()
println(s"更新 worker(id=$id) 心跳時間=${workerInfo.lastHeartBeat}")
case None => println(s"worker(id=$id) 不存在!")
}
}
}
object LiteMaster {
def main(args: Array[String]): Unit = {
// 加載master配置
val config = ConfigFactory.load("master.conf")
// 創建Actor系統
val actorSystem = ActorSystem("Master", config)
// 註冊LiteMaster,並獲取master引用
val masterRef: ActorRef = actorSystem.actorOf(Props[LiteMaster], "LiteMaster")
// 向master自己發送一個啓動消息
masterRef ! "start"
}
}