Akka System
架构图
主节点功能
- 维护一个Worker列表
- 接收心跳信号,更新Worker列表
- 接收注册信号
- 回复注册信号
- 发送注册信号
- 对自身发送心跳信号
代码实现
WorkerInfo类/*
* @author Jabin
* @version 1.0 2019/06/29
* Woker的信息
* */
class WorkerInfo(val id : String,val host : String,val memory : String,val core : String) {
//Worker的心跳消息
var heartBeat : Long = System.currentTimeMillis()
override def toString: String = s"WorkerInfo($id,$host,$memory,$core)"
}
ActorMessage类
/*
* @author Jabin
* @version 1.0 2019/06/29
* 消息的发送
* */
//Worker向Master请求注册节点信息
case class RegisterWorker(val id : String,val host : String,val memory : String,val core : String)
//Worker向Master发送心跳消息
case class HeartBeat(val id : String)
//Master向Worker响应注册完成
case class RegisteredWorker(val host : String)
//Master向自己发送心跳消息,检查Worker是否超时
case class CheckWorker()
//Worker向自己发送心跳消息
case class SelfHeartBeat()
Worker类
/*
* @author Jabin
* @version 1.0 2019/06/29
* Worker类
* */
import java.util.UUID
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import akka.actor.{Actor, ActorSelection, ActorSystem, Props}
import com.typesafe.config.ConfigFactory
class Worker extends Actor{
//实例化Master对象
var master : ActorSelection = null
//为每个Worker创建唯一的id
var id = UUID.randomUUID().toString
override def preStart(): Unit = {
//向系统建立连接请求
master = context.system.actorSelection("akka.tcp://MasterActorSystem@localhost:8888/user/Master")
//向Master发送注册节点信息
master ! RegisterWorker(id,"localhost","10240","8")
}
override def receive: Receive = {
//接收注册完成信息
case RegisteredWorker(masterURL) =>
context.system.scheduler.schedule(0 millis,5000 millis,self,SelfHeartBeat)
//Worker向自己发送心跳消息
case SelfHeartBeat() =>
println("Worker send heart beat")
master ! HeartBeat(id)
}
}
object Worker extends App{
//客户端端口
val PORT = 8891
//创建ActorSystem的配置
val systemConfig =
s"""
|akka.actor.provider = "akka.remote.RemoteActorRefProvider"
|akka.remote.netty.tcp.port = "$PORT"
""".stripMargin
//加载配置
val conf = ConfigFactory.parseString(systemConfig)
//创建ActorSystem
val actorSystem = ActorSystem.create("WorkerActorSystem",conf)
//启动Actor
actorSystem.actorOf(Props[Worker],"Worker")
}
Master类
/*
* @author Jabin
* @version 1.0 2019/06/29
* Master类
* */
import akka.actor.{Actor, ActorSystem, Props}
import com.typesafe.config.ConfigFactory
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.collection.mutable
class Master extends Actor{
//创建一个Map存储id和Worker的信息
val worderMap = new mutable.HashMap[String,WorkerInfo]()
//创建一个Set存储所有不重复的Worker信息
val workerSet = new mutable.HashSet[WorkerInfo]()
//定义超时的时间
val WORKER_TIMEOUT = 10 * 1000
override def preStart(): Unit = {
context.system.scheduler.schedule(0 millis,5000 millis,self,CheckWorker)
}
override def receive: Receive = {
//注册节点消息
case RegisterWorker(id,host,memory,core) =>
if (!worderMap.contains(id)) {
//实例化WorkerInfo对象
val worker = new WorkerInfo(id,host,memory,core)
//存储Worker和id
worderMap(id) = worker
workerSet.add(worker)
println("Register new Worker: "+worker)
sender() ! RegisteredWorker(worker.id)
}
//接收Worker发送的心跳消息
case HeartBeat(id) =>
//获取Worker信息
val workerInfo = worderMap(id)
println("Get heart beam from "+workerInfo)
//获取此时Worker的心跳消息
workerInfo.heartBeat = System.currentTimeMillis()
//检查Worker是否超时
case CheckWorker =>
//获取当前的时间
val currentTime = System.currentTimeMillis()
val toRemove = workerSet.filter(worker => currentTime - worker.heartBeat > WORKER_TIMEOUT).toArray
//遍历超时的Worker
for (worker <- toRemove){
//移除超时的Worker
workerSet -= worker
worderMap.remove(worker.id)
}
println("The number of surviving Worker is "+workerSet.size)
}
}
object Master extends App{
//创建端口和主机名
val PORT = 8888
val HOST = "localhost"
//创建ActorSystem的配置
val systemConfig =
s"""
|akka.actor.provider = "akka.remote.RemoteActorRefProvider"
|akka.remote.netty.tcp.hostname = "$HOST"
|akka.remote.netty.tcp.port = "$PORT"
""".stripMargin
//加载配置
val conf = ConfigFactory.parseString(systemConfig)
//创建ActorSystem
val actorSystem = ActorSystem.create("MasterActorSystem",conf)
//启动Master,生命周期的方法会被调用
actorSystem.actorOf(Props[Master],"Master")
}