大数据学习——akka自定义RPC

 

 

实现

package cn.itcast.akka

import akka.actor.{Actor, ActorSystem, Props}
import akka.actor.Actor.Receive
import com.typesafe.config.ConfigFactory

import scala.collection.mutable

import scala.concurrent.duration._

class Master(val host: String, val port: Int) extends Actor {

  //保存WorkerID 到 WorkerInfo的映射
  val idToWorker = new mutable.HashMap[String, WorkerInfo]()
  //保存所的WorkerInfo信息
  val workers = new mutable.HashSet[WorkerInfo]()

  val CHECK_INTERVAL = 15000

  override def preStart(): Unit = {
    //导入隐式转换
    import context.dispatcher
    context.system.scheduler.schedule(0 millis, CHECK_INTERVAL millis, self, CheckTimeOutWorker)
  }

  override def receive: Receive = {
    //Worker发送个Mater的注册消息
    case RegisterWorker(workerId, cores, memory) => {
      if (!idToWorker.contains(workerId)) {
        //封装worker发送的信息
        val workerInfo = new WorkerInfo(workerId, cores, memory)
        //保存workerInfo
        idToWorker(workerId) = workerInfo
        workers += workerInfo
        //Master向Worker反馈注册成功的消息
        sender ! RegisteredWorker(s"akka.tcp://${Master.MASTER_SYSTEM}@$host:$port/user/${Master.MASTER_NAME}")
      }
    }

    //Worker发送给Master的心跳信息
    case Heartbeat(workerId) => {
      if (idToWorker.contains(workerId)) {
        val workerInfo = idToWorker(workerId)
        val currentTime = System.currentTimeMillis()
        //更新上一次心跳时间
        workerInfo.lastHeartbeatTime = currentTime
      }
    }

    //检测超时的Worker
    case CheckTimeOutWorker => {
      val currentTime = System.currentTimeMillis()
      val deadWorkers: mutable.HashSet[WorkerInfo] = workers.filter(w => currentTime - w.lastHeartbeatTime > CHECK_INTERVAL)
      //      for(w <- deadWorkers) {
      //        idToWorker -= w.id
      //        workers -= w
      //      }
      deadWorkers.foreach(w => {
        idToWorker -= w.id
        workers -= w
      })
      println("alive worker size : " + workers.size)
    }
  }
}

object Master {

  val MASTER_SYSTEM = "MaterActorSystem"
  val MASTER_NAME = "Master"

  def main(args: Array[String]) {

    //    val host = args(0)
    //    val port = args(1).toInt
    val host = "127.0.0.1"
    val port = 8888
    val confStr =
      s"""
         |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
         |akka.remote.netty.tcp.hostname = "$host"
         |akka.remote.netty.tcp.port = "$port"
       """.stripMargin
    val conf = ConfigFactory.parseString(confStr)
    //ActorSystem是单例的,用于创建Acotor并监控actor
    val actorSystem = ActorSystem(MASTER_SYSTEM, conf)
    //通过ActorSystem创建Actor
    actorSystem.actorOf(Props(new Master(host, port)), MASTER_NAME)
    actorSystem.awaitTermination()

  }
}
package cn.itcast.akka

trait Message extends Serializable

//Worker -> Master
case class RegisterWorker(id: String, cores: Int, memory: Int) extends Message

//Master -> Worker
case class RegisteredWorker(masterUrl: String) extends Message

//Worker -> Master
case class Heartbeat(id: String) extends Message

//Worker internal message
case object SendHeartbeat

//Master internal message
case object CheckTimeOutWorker
package cn.itcast.akka

import java.util.UUID
import akka.actor.{Actor, ActorSelection, ActorSystem, Props}
import com.typesafe.config.ConfigFactory

import scala.concurrent.duration._

class Worker(val cores: Int, val memory: Int, val masterHost: String, val masterPort: Int) extends Actor {

  //Master的引用
  var master: ActorSelection = _
  //Worker的ID
  val workerId = UUID.randomUUID().toString
  //masterUrl
  var masterUrl: String = _

  val HEARTBEAT_INTERVAL = 10000

  //preStart在构造器之后receive之前执行
  override def preStart(): Unit = {
    //首先跟Master建立连接
    master = context.actorSelection(s"akka.tcp://${Master.MASTER_SYSTEM}@$masterHost:$masterPort/user/${Master.MASTER_NAME}")
    //通过master的引用向Master发送注册消息
    master ! RegisterWorker(workerId, cores, memory)
  }

  override def receive: Receive = {
    //Master发送给Worker注册成功的消息
    case RegisteredWorker(masterUrl) => {
      this.masterUrl = masterUrl
      //启动定时任务,向Master发送心跳
      //导入隐式转换
      import context.dispatcher
      context.system.scheduler.schedule(0 millis, HEARTBEAT_INTERVAL millis, self, SendHeartbeat)
    }

    case SendHeartbeat => {
      //向Master发送心跳
      master ! Heartbeat(workerId)
    }
  }
}

object Worker {
  def main(args: Array[String]) {

    //Worker的地址和端口
    //    val host = args(0)
    //    val port = args(1).toInt
    //    val cores = args(2).toInt
    //    val memory = args(3).toInt
    val host = "127.0.0.1"
    val port = 9999
    val cores = 8
    val memory = 1024

    //Master的地址和端口
    //    val masterHost = args(4)
    //    val masterPort = args(5).toInt
    val masterHost = "127.0.0.1"
    val masterPort = 8888

    val confStr =
      s"""
         |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
         |akka.remote.netty.tcp.hostname = "$host"
         |akka.remote.netty.tcp.port = "$port"
       """.stripMargin
    val conf = ConfigFactory.parseString(confStr)
    //单例的ActorSystem
    val actorSystem = ActorSystem("WorkerActorSystem", conf)
    //通过actorSystem来创建Actor
    val worker = actorSystem.actorOf(Props(new Worker(cores, memory, masterHost, masterPort)), "Worker")
    actorSystem.awaitTermination()
  }
}
package cn.itcast.akka


class WorkerInfo(val id: String, val cores: Int, val memory: Int) {

  //TODO
  var lastHeartbeatTime: Long = _

}

 

 

posted on 2019-06-10 09:39  o_0的园子  阅读(345)  评论(0编辑  收藏  举报