Akka通信Demo

一个Master
一个Worker

还有一个WorkerInfo类 封装Worker信息
一个RemoteMsg 放样例类
在这里插入图片描述

Master

package Akka.RpcTest

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

import scala.collection.mutable
import scala.concurrent.duration._
//在Akka中负责监控和创建Actor的老大叫ActorSystem
//负责正在通信的叫Actor
class Master(val masterHost : String, val masterPort : Int)extends  Actor{

  //用来存储Worker的注册信息
  val idToWorker = new mutable.HashMap[String, WorkerInfo]()

  //用来存储Worker的信息
  val workers = new mutable.HashSet[WorkerInfo]()
  val CHECK_INTERVAL = 15000

  //preStart会被调用一次,在构造方法之后,receive方法之前
  override def preStart(): Unit = {
    //在preStart启动一个定时器 用于周期检查超时的Worker
    import  context.dispatcher
    context.system.scheduler.schedule(0 millis, CHECK_INTERVAL millis,
      self, CheckTimeOutWorker)
  }
  override def receive: Receive = {
    // Worker -> Master
    case RegisterWorker(id, host, port, memory, cores) => {
      if(!idToWorker.contains(id)){
        val workerInfo = new WorkerInfo(id, host, port, memory, cores)
        idToWorker += (id -> workerInfo)
        workers += workerInfo
        println("a worker registered")
        sender ! RegisteredWorker(s"akka.tcp://${Master.MASTER_SYSTEM}" +
          s"@$masterHost:$masterPort/user/${Master.MASTER_ACTOR}")
      }
    }
    case Heartbeat(workerId) => {
      val workerInfo = idToWorker(workerId)
      val current_time = System.currentTimeMillis()
      //更新最后一次心跳时间
      workerInfo.lastHeartbearTime = current_time
    }

    case CheckTimeOutWorker => {
      val currentTime = System.currentTimeMillis()
      val toRemove : mutable.HashSet[WorkerInfo] = workers
        .filter(w => currentTime - w.lastHeartbearTime > CHECK_INTERVAL)
      toRemove.foreach(deadWorker => {
        //将超时的worker从内存中移除掉
        idToWorker -= deadWorker.id
        workers -= deadWorker
      })
      println("num of workers " + workers.size)
    }
  }
}


object Master {
  val MASTER_SYSTEM = "MasterSystem"
  val MASTER_ACTOR = "Master"

  def main(args: Array[String]): Unit = {
    //如果想创建Actor 必须先创建它的老大 ActorSystem(单例的)

//    val host = args(0)
//    val port = args(1).toInt
    val host = "127.0.0.1"
    val port = 9999
    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)

    //先创建一个ActorSystem, 单例
    val actorSystem: ActorSystem = ActorSystem(MASTER_SYSTEM, config)
    actorSystem.actorOf(Props(new Master(host, port)), MASTER_ACTOR)
    actorSystem.awaitTermination()
  }
}

Woker

package Akka.RpcTest

import java.util.UUID

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

import scala.concurrent.duration._
class Worker(val host : String , val port : Int, val masterHost : String,
             val masterPort : Int, val memory : Int,  val cores : Int) extends Actor {
  val worker_id = UUID.randomUUID().toString
  var masterUrl: String = _
  val HEARTBEAT_INTERVAL = 10000
  var master : ActorSelection = _

  override def preStart(): Unit = {
    master = context.actorSelection(s"akka.tcp://${Master.MASTER_SYSTEM}" +
      s"@$masterHost:$masterPort/user/${Master.MASTER_ACTOR}")
    master ! RegisterWorker(worker_id, host, port, memory, cores)
  }
  override def receive: Receive = {
    //Worker接收到Master注册成功的反馈信息
    case RegisteredWorker(masterUrl) => {
      this.masterUrl = masterUrl
      //定时发送心跳, 心跳是一个case class
      //导入一个隐式转换, 才能启动定时器
      import context.dispatcher
      context.system.scheduler.schedule(0 millis, HEARTBEAT_INTERVAL millis,
        self, SendHeartbeat)
    }
    case SendHeartbeat => {
      //发送心跳之前要进行一些检查
      master ! Heartbeat(worker_id)
    }
  }
}

object Worker {
  val WORKER_SYSTEM = "WorkerSystem"
  val WORKER_ACTOR = "Worker"

  def main(args: Array[String]): Unit = {
//    val host = args(0)
//    val port = args(1).toInt
//    val masterHost = args(2)
//    val masterPort = args(3).toInt
//    val memory = args(4).toInt
//    val cores = args(5).toInt
    val host = "127.0.0.1"
    val port = 8888
    val masterHost = "127.0.0.1"
    val masterPort = 9999

    val memory = 512
    val cores = 2

    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)
    //先创建一个ActorSystem, 单例
    val actorSystem: ActorSystem = ActorSystem(WORKER_SYSTEM, config)
    actorSystem.actorOf(Props(new Worker(host, port,
      masterHost,masterPort, memory, cores)), WORKER_ACTOR)
    actorSystem.awaitTermination()
  }
}

WorkerInfo

package Akka.RpcTest

/**
 * 用于封装Worker的信息
 * @param id
 * @param host
 * @param port
 * @param memory
 * @param cores
 */
class WorkerInfo(val id : String, val host : String,
                 val port : Int, val memory : Int, val cores : Int) {
    var lastHeartbearTime : Long = _
}

RemoteMsg

package Akka.RpcTest

trait RemoteMsg extends Serializable
// Worker -> Master
case class RegisterWorker(id : String, host : String,
                            port : Int, memory : Int, cores : Int) extends  RemoteMsg

case class Heartbeat(workerId : String) extends  RemoteMsg

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

//Worker -> self
case object SendHeartbeat

//Master -> self
case object CheckTimeOutWorker



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值