Akka-RPC通信案列流程

Akka是JAVA虚拟机JVM平台上构建高并发、分布式和容错应用的工具包。Akka用Scala语言写成,同时提供了Scala和JAVA的开发接口。
Akka处理并发的方法基于Actor模型。在Akka里,Actor之间通信的唯一机制就是消息传递

Spark的RPC是通过Akka类库实现的,Akka用Scala语言开发,基于Actor并发模型实现,Akka具有高可靠、高性能、可扩展等特点,使用Akka可以轻松实现分布式RPC功能。

负责管理的角色:ActorSystem(总监)单例的,在scala中就是一个object
负责通信的:Actor,多实例的(Student和School)
发送的消息:case class(参数)和case objce
发消息的方式:异步、同步
Akka-RPC通信案列思路:

  1. 第一步:在student和school类中,创建一个单列的ActorSystem,和一个实列的Actor.学生通过school的地址和端口号以及ActorSystem实现连接.
  2. 第二步:student向school发送注册信息(本文中,发送的是学生信息,这里需要创建一个case class StudentInformation(studentID: String, name: String, age: Int,gender: String)),school收到学生信息,保存,同时回复(case object StudentInformationed)用以表名收到信息,连接成功;
  3. 第三步:student和school内部都需要一个定时器,用于定时检测Actor心跳信息是否超时,超时一定时间,会自动剔除超时的Actor.
***

## 创建一个Scala代码如下

***
//学生发送给学校的学生信息
case class StudentInformation(studentID: String, name: String, age: Int, gender: String)

//学校收到学生信息,返回消息
case object StudentInformationed

//Student发送给School的心跳消息  因为需要识别是哪个Student需要有学生ID的参数,所以为case class
case class Heartbeat(studentID: String)

//-->第三步  Student 自己给自己发送的消息(内部消息)
case object SendHeartbeat

School发送给自己的消息,用于检查超时的student
case object CherkTimeOutStudent

***

## 创建一个Scala代码如下

***
class StudentInfor(val studentID: String, val name: String, var age: Int, val gender: String) {
  //可变的成员变量
  var LastUpdateTime: Long = _

  override def toString = s"StudentInfor($studentID, $name, $age,$gender)"
}
***

## Student学生代码如下

***
import akka.actor.{Actor, ActorRef, ActorSelection, ActorSystem, Props}
import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils.ConfigFile
import com.typesafe.config.{Config, ConfigFactory}

import scala.concurrent.duration._ //--->手动导包


class Student extends Actor {

  var selection: ActorSelection = _ //-->,把selection局部变量转成成员变量.由val改成var
  override def preStart(): Unit = {
    selection = context.actorSelection("akka.tcp://School_Actor_System@localhost:4444/user/School_Actor")
    //   第一步,学生给学校发送自己的注册信息(带有参数)
    selection ! StudentInformation("w001", "yangshuaishuai", 18, "nan")
  }

  override def receive: Receive = {
    //第三步  接受学校发的注册成功的消息,并启动定时器
    case StudentInformationed => {
      //导入隐式转换
      import context.dispatcher
      //启动一个定时器,定时向School发送心跳
      //将消息发送给自己[定期执行的]
      /**
        * scheduler:调度员
        * initialDelay: FiniteDuration,-->第一次延迟多长时间
        * interval:     FiniteDuration,-->多长时间执行一次
        * receiver:     ActorRef,-->发送给谁
        * message:      Any)(implicit-->发送的消息
        *
        *
        * self :先自己给自己发消息,然后再给School发心跳.
        */
      context.system.scheduler.schedule(0 millisecond, 5000 millisecond, self, SendHeartbeat)
    }
    //-->第四步  Student自己发送给自己的消息
    case SendHeartbeat => {
      //进行一些逻辑判断
      //Student将心跳消息发送个School[周期性的]
      selection ! Heartbeat("w001")
    }
  }
}

object Student {
  def main(args: Array[String]): Unit = {
    val host = args(0)
    val port = args(1).toInt
    val configStr =
      s"""
         |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
         |akka.remote.netty.tcp.hostname = "$host"
         |akka.remote.netty.tcp.port = "$port"
      """.stripMargin
    val config: Config = ConfigFactory.parseString(configStr)
    val student_Actor_Systrm: ActorSystem = ActorSystem("Student_Actor_Systrm", config)
    val ref: ActorRef = student_Actor_Systrm.actorOf(Props[Student])

  }
}
***

## School学校代码如下

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

class School extends Actor {
  val idTostudent: mutable.HashMap[String, StudentInfor] = new mutable.HashMap[String, StudentInfor]

  //--> 第六步   在preStart中启动定时器,定期检查超时的
  override def preStart(): Unit = {
    import context.dispatcher
    //自己给自己发送用于检测超时的Student,那肯定的自己接
    context.system.scheduler.schedule(0 millisecond, 10000 millisecond, self, CherkTimeOutStudent)
  }

  override def receive: Receive = {
    //第二步     接受学生信息
    case StudentInformation(studentID, name, age, gender) => {
      //数据保存
      val studentInfor = new StudentInfor(studentID, name, age, gender)
      //将数剧信息放入Map中
      idTostudent.put(studentID, studentInfor)

      //School向学生返回一个连接成功的消息
      sender() ! StudentInformationed
    }
    //--> 第五步    Student发送给School的心跳消息[周期性的]
    case Heartbeat(studentID) => {
      //根据StudentID到idTostudent中取查找对应的studentInfor
      if (idTostudent.contains((studentID))) {
        //根据ID取出studentInfor
        val studentInfor = idTostudent(studentID)

        //获取当前时间
        val currentTime: Long = System.currentTimeMillis()
        //更新最近一次心跳时间
        studentInfor.LastUpdateTime = currentTime
      }
    }
    //   第七步  自己接自己的消息
    case CherkTimeOutStudent => {
      //把超时的Student取出来
      //去除当前时间
      val currentTime = System.currentTimeMillis()

      //遍历超时的Student
      val students: Iterable[StudentInfor] = idTostudent.values
      val deadstudents: Iterable[StudentInfor] = students.filter(w => currentTime - w.LastUpdateTime > 10000)
      deadstudents.foreach(w => {
        //移除超时的Studeng
        idTostudent -= w.studentID
      })
      println(s"current alive student is:+${idTostudent.size}")
    }
  }
}

object School {
  def main(args: Array[String]): Unit = {
    val host = args(0)
    val port = args(1).toInt
    val configStr =
      s"""
         |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
         |akka.remote.netty.tcp.hostname = "$host"
         |akka.remote.netty.tcp.port = "$port"
      """.stripMargin
    val config: Config = ConfigFactory.parseString(configStr)
    val actorSystem: ActorSystem = ActorSystem("School_Actor_System", config)
    val school_Actor: ActorRef = actorSystem.actorOf(Props[School], "School_Actor")

  }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值