Scala-Akka System

Akka System

架构图

在这里插入图片描述
主节点功能

  1. 维护一个Worker列表
  2. 接收心跳信号,更新Worker列表
  3. 接收注册信号
  4. 回复注册信号
从节点功能
  1. 发送注册信号
  2. 对自身发送心跳信号

代码实现

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")
}
发布了131 篇原创文章 · 获赞 12 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/JavaDestiny/article/details/94203637