架构图
具体代码
Master类
import akka.actor.{Actor, ActorSystem, Props}
import com.typesafe.config.ConfigFactory
import com.zhe.rpc.{HeartBeat, RegisteredMessage, WorkerInfo}
import scala.concurrent.duration._
import scala.collection.mutable
import scala.collection.mutable.L
class Master extends Actor {
//定义一个map集合用于存储worker的注册信息 key;workerId value:workerInfo
private val id2WorkerInfoMap = new mutable.HashMap[String, WorkerInfo]()
//定义一个lst集合用于存储workerinfo信息,主要方便与后期按照worker的资源大小排序
private val workerInfoList = new ListBuffer[WorkerInfo]
//定义master定时检查的时间间隔
val checkOutTimeInterval = 15000 //15s
override def preStart(): Unit = {
//master定时检查超时worker
//手动导入隐式转换
import context.dispatcher
context.system.scheduler.schedule(0 millis, checkOutTimeInterval millis,self,CheckOutTime)
}
override def receive: Receive = {
//master接受worker的注册信息
case registMessage(workerId, memory, cores) => {
println("成功一个worker")
//判断当前worker是否注册,master只接受没有注册的worker信息
if (!id2WorkerInfoMap.contains(workerId)) {
//构建workerinfo对象
val workerInfo = new WorkerInfo(workerId, memory, cores)
//保存到map集合中
id2WorkerInfoMap.put(workerId, workerInfo)
//保存到list集合中
workerInfoList += workerInfo
//master反馈注册成功信息给worker
sender ! RegisteredMessage(s"workerId:$workerId 注册成功")
}
}
//master接收worker的心跳信息
case HeartBeat(workerId) => {
//判断当前worker是否注册,master只接受已注册过的worker的心跳信息
if (id2WorkerInfoMap.contains(workerId)) {
//获取workerId对应的WorkerInfo
val workerInfo: WorkerInfo = id2WorkerInfoMap(workerId);
//获取当前系统时间
val lastTime: Long = System.currentTimeMillis()
//吧当前系统时间赋值给worker上一次心跳时间
workerInfo.lastHeartBeatTime = lastTime
}
}
//master接受master信息
case CheckOutTime => {
//判断worker超时逻辑:当前时间 - worker上一次心跳时间 > master定时检查的时间间隔
//获取当前时间
val now: Long = System.currentTimeMillis()
val outTimeWorkerInfoes: ListBuffer[WorkerInfo] = workerInfoList.filter(x => now - x.lastHeartBeatTime > checkOutTimeInterval)
//遍历
for (c <- outTimeWorkerInfoes) {
//获取超时的workerinfo对应的workerId
val workerId: String = c.workerId
//从map集合移除掉超时的worker信息
id2WorkerInfoMap.remove(workerId)
//从list集合移除掉超时的worker信息
workerInfoList -= c
println(s"workerId:$workerId 已经超时")
}
println("活着的worker总数:" + workerInfoList.size)
// 按照worker内存大小降序排列
println(workerInfoList.sortBy(x => x.memory).reverse)
}
}
}
object Master {
def main(args: Array[String]): Unit = {
val host = args(0)
val port = args(1)
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)
val masterActorSystem = ActorSystem.apply("masterActorSystem", config)
masterActorSystem.actorOf(Props(new Master), "masterActor")
}
}
Worker类
import java.util.UUID
import akka.actor.{Actor, ActorSelection, ActorSystem, Props}
import com.typesafe.config.{Config, ConfigFactory}
import scala.concurrent.duration._
class Worker(memory:Int,cores:Int,masterHost:String,val masterPost:Int) extends Actor{
//定义workId
private val workerId=UUID.randomUUID().toString
//定义worker定时发送心跳的时间间隔
val sendHeartBeatInterval=10000//10秒
var master: ActorSelection=_
override def preStart(): Unit = {
//获取master引用
master=context.actorSelection(s"akka.tcp://masterActorSystem@$masterHost:$masterPost/user/masterActor")
//向master发送注册信息,通过样例类封装注册信息(workId,memory,cores)
master ! registMessage(workerId,memory,cores)
}
override def receive: Receive = {
case RegisteredMessage(message)=>{
println(message)
//向master定时发送心跳 由于master的引用类型跟所需要的参数不一致,这里不可以直接向master发送信息,使用self(表示worker自己本身)
//手动导入隐式转换
import context.dispatcher
context.system.scheduler.schedule(0 millis, sendHeartBeatInterval millis, self, SendHeartBeat)
}
//worker接受worker的发送信息
case SendHeartBeat =>{
//worker真正向master发送心跳
master ! HeartBeat(workerId)
}
}
}
object Worker{
def main(args: Array[String]): Unit = {
val host=args(0)
val port=args(1)
val memory=args(2).toInt
val cores=args(3).toInt
val masterHost=args(4)
val masterPost=args(5).toInt
val configStr=
s"""
|akka.actor.provider = "akka.remote.RemoteActorRefProvider"
|akka.remote.netty.tcp.hostname = "$host"
|akka.remote.netty.tcp.port = "$port"
""".stripMargin
val config: Config = ConfigFactory.parseString(configStr)
val workerActorSystem = ActorSystem.apply("WorkerActorSystem",config)
workerActorSystem.actorOf(Props(new Worker(memory,cores,masterHost,masterPost)),"workerActor")
}
}
样例类
class Messages extends Serializable{
}
//worker向master发送注册信息
case class registMessage(workerId:String,memory:Int,cores:Int) extends Messages
//master向worker返回注册成功信息
case class RegisteredMessage(massage:String)extends Messages
//worker向自己发送信息
case object SendHeartBeat
//worker向master发送心跳
case class HeartBeat(workerId:String) extends Messages
//master向naster自己发送消息 ,由于在同一进程中,不需要实现序列化
case object CheckOutTime
WorkerInfo类
class WorkerInfo(val workerId:String,val memory:Int,val cores:Int) {
//用于存储worker的上次心跳时间
var lastHeartBeatTime:Long=_
override def toString: String = {
"workerId:"+workerId+" memory"+memory+" cores"+cores
}
}