Scala编程实战 RPC

1.  熟练使用Scala编写程序

2. 项目概述 

2.1 需求 

目前大多数的分布式架构层通信都是通过RPC实现的,RPC架构非常多,比如Hadoop项目的RPC通信框架,但是Hadoo在设计之初就是为了运行长达数小时的批量而设计的,在某些极端的情况下,任务提交的延迟很高,所有Hadoop的RPC显得有些笨重  Spark的RPC是通过AKKa类库实现的,Akka用Scala语言开发,基于Actor并发模型实现,Akka具有高可靠、高性能、可扩展等特点,使用Akka可以轻松实现分布式RPC功能。   

2.2 Akka简介 Akka基于Actor模型,提供了一个用于构建可扩展(Scalable),弹性的(Resilient),快速响应的(Responsive)应用程序的平台。  Actor模型:在计算机科学领域,Actor模型是一个并行计算(ConCurrent Computation)模型,它把actor做出一些决策,如创建更多的actor,或发送更多的actor,或发送更多的消息,或者确定如何去响应接收到的下一个消息。

Actor是一个Akka中最核心的概念,它是一个封装了状态和行为的对象,Actor之间可以通过交换消息的方式进行通信,每一个Actor都有自己的收件箱(MailBox)。通过Actor能够简化锁及线程还礼,可以非常的开发出正确并发程序和并行系统,Actor具有如下特性:

1.提供了一种高级抽象,能够简化在并发(Concurrency)/并行(parallelism)应用场景下的编程开发

 2. 提供了异步非阻塞的,高性能的时间驱动编程模型

3.超级了轻量级事件处理(每GB堆内存几百万Actor)   

3. 项目实现

3.1 架构图

3.2  重要类介绍   

3.2.1 ActorSystem

在Akka中,ActorSystem是一个重要级的结构,需要分配多个线程,所以在实际应用中,ActorSystem通常是一个单例对象,可以使用这个ActorSystem创建很多Actor.

3.2.2 Actor 

在Akka中,Actor负责通信,在Actor中有一些重要的生命周期方法 

1.preStart()方法:该方法Actor对象构造方法执行后执行,整个Actor生命周期中仅执行一次。

2.receive()方法:该方法在Actor的preStart方法执行完成后执行,用于接收消息,会被返回执行。

1.WorkInfo类

package com.zhiyou100.ScalaActor_akka.Worker
/*用来封装master接受的worker的信息
   @param id
   @param mem
   @param  cores
 */
class WorkInfo(val id:String,val mem:Int,val cores:Int) {
    var LastBeat :Long = _
}

2.IntervalMeaage类

package com.zhiyou100.ScalaActor_akka.Worker
/*交互消息:用来封装Master与Worker进行交互的消息
  1.注册  2.Master的反馈 3.心跳 4.检查信息(时间超时)
  这里面都是样例类,因为在网络传输所以必须实现序列化
 */
trait IntervalMeaage extends Serializable     //抽象类
  //注册样例类,封装了从Worker到Master的注册消息

  case class  RegisterWorker(id:String,mem:Int,cores:Int) extends IntervalMeaage  //mem  内存   core核数
 //注册成功确认消息
  case class RegisterFinish(masterURL:String) extends  IntervalMeaage
  //发送心跳   worker -->worker
  case object SendHeartBeat
//发送心跳 worker -> master
   case class  HeartBeat (id:String) extends IntervalMeaage
//超时检查  master -->master
case object CheckTimeOut

 

3.Master类

package com.zhiyou100.ScalaActor_akka.Worker

import akka.actor.{Actor, ActorSystem, Props}
import com.typesafe.config.ConfigFactory
import scala.collection.mutable
import  scala.concurrent.duration._

class Master extends Actor{
  //用来保存worker传输过来的信息,value最好一个实体类,以后方便使用其中属性
  val ids=new mutable.HashMap[String,WorkInfo]()
  //保存map中的workInfo的集合,方便以后属性的排序
  val workers=new mutable.HashSet[WorkInfo]()
  val CHECK_BEAT=2500
  // 生命周期之启动Actor     contrl+o
  override def preStart():Unit ={
  println("Actor is preStart")
    //启动定时器,检查worker心跳是否正常
    import context.dispatcher

    context.system.scheduler.schedule(0.millis,CHECK_BEAT.millis,self,CheckTimeOut)
  }

  //用于接收消息
  override def receive:Receive = {
    case "connect" =>{
      println("success")
      sender ! "reply"
    }
    case "hello" =>{
      println("1111" )
    }
    case RegisterWorker(id,mem,cores) =>{
      //判断一下worker是否注册过
      if (!ids.contains(id)){
        //将封装实例化
       val workInfo = new WorkInfo(id,mem,cores)
        //保存数据策略: 1.保存内存 2.持久化到磁盘 3. 保存到zookeeper
      //map的put的操作
        ids (id) =workInfo
        //set的追加操作
        workers += workInfo
        //创建样例类发送注册成功确认消息
        sender ! RegisterFinish("akka.tcp://MasterSystem@$host:$port/user/Master")
      }
    }
    case HeartBeat(id) =>{
      if (ids.contains(id)){
        val workInfo =ids(id)
        val currentTime=System.currentTimeMillis()
        //把心跳时间用当前的时间置换
        workInfo.LastBeat =currentTime
      }
    }
    case CheckTimeOut =>{
   val concurrentTime=System.currentTimeMillis()
    val toClean =  workers.filter(x=> concurrentTime -x.LastBeat >CHECK_BEAT)
      for (w<- toClean){
         workers -=w
        ids -=w.id
      }
      println("活着的wpoker数量:"+workers.size)
    }
  }
}
//老大
object  Master {
  def main(args: Array[String]): Unit = {
    val host=args(0)
    val port=args(1).toInt
    //准备配置文件
    val config =
      s"""
         |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
         |akka.remote.netty.tcp.hostname = "$host"
         |akka.remote.netty.tcp.port = "$port"
     """.stripMargin
    val cfg =  ConfigFactory.parseString(config)   //解析配置文件
   //actorSystem :Actor的领导,监控所有的actor,singletong
    val actorSystem =ActorSystem("MasterSystem",cfg)
    //创建actor
   val master = actorSystem.actorOf(Props[Master],name="Master")
    master ! "success"
    actorSystem.awaitTermination()  //让进程等待,不结束

  }
}

4. Worker类

package com.zhiyou100.ScalaActor_akka.Worker

import java.util.UUID
import  scala.concurrent.duration._
import akka.actor.{Actor, ActorSelection, ActorSystem, Props}
import com.typesafe.config.ConfigFactory
class Worker (val masterHost:String,val masterPort: Int,val mem:Int,val cores:Int)
                                            extends Actor{
  var master:ActorSelection=_
  val workerID=UUID.randomUUID().toString
  val HEART_BEAT=2000
  //建立连接
  override def preStart(): Unit = {
    //参数需要有/user/Master
   master= context.actorSelection(s"akka.tcp://MasterSystem@$masterHost:$masterPort/user/Master")
  // master ! "connect"
    //向Master发送注册消息,Master的receive方法中的case class去接受
    master ! RegisterWorker(workerID,mem,cores)
  }

  override def receive : Receive ={
    //worker收到master返回的确认消息
    case RegisterFinish (masterURL) =>{
      println(masterURL)
      //定时发送心跳
      //导入影视转换
       import context.dispatcher
      context.system.scheduler.schedule(0.millis,HEART_BEAT.millis,self,SendHeartBeat)

      //schedule(0.millis ,HEART_BEAT.millis,self,SendHeartBeat)
    }
 //接收自己发送给自己的心跳,然后在发送给Master

    case SendHeartBeat=>{
      println("发送心跳的Master")
      master ! HeartBeat(workerID)
    }
    case "reply" =>{
      println("haode")
    }
  }
}
  object Worker{
    def main(args: Array[String]): Unit = {
      val host=args(0)
      val port=args(1)
      val masterHost=args(2)
      val masterPort=args(3).toInt
      val mem =args(4).toInt
      val cores=args(5).toInt
      //准备配置
      val config=
        s"""
          |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
          |akka.remote.netty.tcp.hostname = "$host"
          |akka.remote.netty.tcp.port = "$port"
        """.stripMargin
      val cfg =  ConfigFactory.parseString(config)
      val actorSystem =  ActorSystem("WorkerSystem",cfg)
      //创建worker
      actorSystem.actorOf(Props(new Worker(masterHost,masterPort,mem,cores)),name = "Worker")
      actorSystem.awaitTermination()
    }
  }

猜你喜欢

转载自blog.csdn.net/abcdefghwelcome/article/details/86097436
RPC