1.RPC:简单点说,就是多线程之间的通信,我们今天用了scala以及akka

   来简单的实现了

   rpc框架的一些简单的内容,一脸包括了,心跳,间隔时间,

   注册以及一些问题,

   模式匹配的一些东西,虽然比较简单,但是属于麻雀虽小,五脏俱全

   这个里面一共有有四个文件:

   Master.scala

   RemoteMessage.scala

   Worker.scala

   WorkerInfo

  

   Master.scala

package cn.wj.rpc

import akka.actor.{Actor, ActorSystem}
import akka.actor.Actor.Receive
import com.typesafe.config.ConfigFactory
import akka.actor.Props
import scala.concurrent.duration._ import scala.collection.mutable /**
* Created by WJ on 2016/12/23.
*/
class Master(val host:String,val port:Int ) extends Actor { // workerId -> WorkerInfo
val idToWorker = new mutable.HashMap[String,WorkerInfo]()
val workers = new mutable.HashSet[WorkerInfo]() //时间间隔时间,超时检测的间隔
val CHECK_INTERVAL = 15000
//用于接收消息
override def receive: Receive = {
case RegisterWorker(id,memory,cores) => {
// println("a client connected")
// sender ! "reply" //往发送给他消息的人回复一个消息
//判断一下是不是已经注册过了
if(!(idToWorker.contains(id))){
//把Worker的信息封装以前,保存到内存当中
val workerInfo = new WorkerInfo(id,memory,cores)
idToWorker(id) = workerInfo //这个应该是scala的特定版本
workers += workerInfo
sender ! RegisteredWorker(s"akka.tcp://MasterSystem@$host:$port/user/Master")
} }
case Heartbeat(id) =>{
if(idToWorker.contains(id)) {
val workerInfo = idToWorker(id)
//报活
//得到系统当前时间
val currentTime = System.currentTimeMillis()
workerInfo.lastHeartbeatTime = currentTime
}
} case CheckTimeOutWorker => {
val currentTime = System.currentTimeMillis()
val toRemove = workers.filter(x => currentTime - x.lastHeartbeatTime > CHECK_INTERVAL)
for(w <- toRemove){
workers -= w
idToWorker -= w.id
}
println(workers.size)
}
} override def preStart(): Unit = {
println("prestart invoked")
//导入隐式转换的功能
import context.dispatcher
context.system.scheduler.schedule(0 millis,CHECK_INTERVAL millis,self,CheckTimeOutWorker)
}
} object Master{
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 = ConfigFactory.parseString(configStr)
//ActorSystem老大,辅助创建和监控下面的Actor,他是单例的
val actorSystem = ActorSystem("MasterSystem",config )
//创建Actor
val master = actorSystem.actorOf(Props(new Master(host,port)),"Master")
actorSystem.awaitTermination()
}
}

  Worker.scala

package cn.wj.rpc

import java.util.UUID

import akka.actor.{Actor, ActorSelection, ActorSystem, Props}
import com.typesafe.config.ConfigFactory
import scala.concurrent.duration._
/**
* Created by WJ on 2016/12/23.
*/
class Worker(val masterHost:String,val masterPort:Int,val memory:Int,val cores:Int) extends Actor { var master : ActorSelection = _
val workerId = UUID.randomUUID().toString
val HEART_INTERVAL = 10000
//preStart执行方法的时机:构造器之后,receive之前
//与Master(Actor)建立连接
override def preStart(): Unit = {
//master已经是别的Master的引用了 ,这是跟master建立连接
master = context.actorSelection(s"akka.tcp://MasterSystem@$masterHost:$masterPort/user/Master")
//向Master发送注册消息
master ! RegisterWorker(workerId,memory,cores)
} override def receive: Receive = { case RegisteredWorker(masterUrl) => {
println(masterUrl)
//启动定时器发送心跳
import context.dispatcher
context.system.scheduler.schedule(0 millis,HEART_INTERVAL millis,self,SendHeartbeat)
} case SendHeartbeat =>{
println("send heartbeat to master")
master ! Heartbeat(workerId)
} }
} object 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 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老大,辅助创建和监控下面的Actor,他是单例的
val actorSystem = ActorSystem("WorkerSystem",config )
//创建Actor,此时调用该(Actor)的prestart以及receive方法
actorSystem.actorOf(Props(new Worker(masterHost,masterPort,memory,cores)),"Worker")
actorSystem.awaitTermination()
}
}

  RemoteMessage.scala

package cn.wj.rpc

/**
* Created by WJ on 2016/12/25.
*/
trait RemoteMessage extends Serializable //Worker->Master(这个表明当master接受这个worker时的信息,是receive)
case class RegisterWorker (id:String, memory:Int, cores:Int) extends RemoteMessage //Master -> Worker(这个是master收到workerd的注册信息,表明已经注册过这条信息,是sender ! xxx时候出现的)
case class RegisteredWorker(masterUrl:String) extends RemoteMessage //这是进程之间自己给自己发送消息,所以采用case object,并且不需要实现Serializable
//Worker -> Worker(self)
case object SendHeartbeat //这个是work向master发送定时器,其中的id是work的id,因为要向master说明,是哪一个work给他发送的心跳
//Worker -> Master
case class Heartbeat(id:String) extends RemoteMessage //Master -> self
case object CheckTimeOutWorker

  WorkerInfo.scala

package cn.wj.rpc

/**
* Created by WJ on 2016/12/25.
*/
class WorkerInfo(val id:String ,val memory :Int,val cores:Int) {
//TODO 上一次心跳
var lastHeartbeatTime:Long = _
}

  这个上面的四个就是简单的实现了RPC框架,其实就是一个Master监控多个Worker,

  当一个Worker创建了,他就是需要在Master注册信息,其实这个Master个人感觉就像

  是个Zookeeper,掌管Worker的信息,为其Worker分配一些资源,当Master接到Worker

  的注册信息的时候,他就在自己的注册表添加上这个Worker,然后向Worker发送一个注册

  成功的信息,此时这个Worker的收到这个注册信息,然后他就给Master发送心跳,这个的

  作用是在告诉Master,我这个Worker是存活的(报活),当一个Worke发送心跳的时间间隔

  过长,长过我们规定的时间,那么此时我们就需要主动杀死这个Worker,感觉hadoop的一些

  分布式和这个原理差不多。

  下面奉上原理图一张:

  

  其中的receive是用于接受信息,因为继承Actor,

  prestart这个方法是执行实在类实例之后,receive的方法之后

2.RPC的大概流程

  首先定义了一个worker,一个master,master首先启动了,

  然后它在prestart()的方法里面
  检测超时的worker,那么在这个里面启动了一个定时器,

  那么我们自己是不是自己可以手写一个定时器,
  比如我们可以用线程来搞定时器,但是我们的akka

  里面提供了一个超级简单的定时器,
  context.system.schedular.schedule

  (0 millis,CHECK_INTERVAL millis,self,CheckTimeOutWorker)
  其中第一个参数:延迟多少秒
  第二个参数:时间间隔
  第三个参数:把这个消息发给谁
  第四个参数:发送什么消息
  虽然它起了消息,但是他不能一下子就把消息发送出去
  ,它只能把消息先发送给自己的receive接收到这个消息,
  然后在发送给我们master,这个里面有一个检测,
  检测worker有多长时间没有向我发送心跳了,
  如果这个时间大过了我规定的范围,
  这样,Master启动完成检测心跳,worker启动完成后
  ,首先向master建立连接,然后发送注册消息
  ,master接受到这个注册消息,
  把worker的信息保存到内存当中,然后向worker反馈一个消息,
  说你注册成功了,然后worker启动一个定时器,
  定时的向master发送心跳,就是这样的流程

  

初见akka-02:rpc框架的更多相关文章

  1. Spark RPC框架源码分析(一)简述

    Spark RPC系列: Spark RPC框架源码分析(一)运行时序 Spark RPC框架源码分析(二)运行时序 Spark RPC框架源码分析(三)运行时序 一. Spark rpc框架概述 S ...

  2. 一个入门rpc框架的学习

    一个入门rpc框架的学习 参考 huangyong-rpc 轻量级分布式RPC框架 该程序是一个短连接的rpc实现 简介 RPC,即 Remote Procedure Call(远程过程调用),说得通 ...

  3. 服务化实战之 dubbo、dubbox、motan、thrift、grpc等RPC框架比较及选型

    转自: http://blog.csdn.net/liubenlong007/article/details/54692241 概述 前段时间项目要做服务化,所以我比较了现在流行的几大RPC框架的优缺 ...

  4. Spark2.1.0——内置RPC框架详解

    Spark2.1.0——内置RPC框架详解 在Spark中很多地方都涉及网络通信,比如Spark各个组件间的消息互通.用户文件与Jar包的上传.节点间的Shuffle过程.Block数据的复制与备份等 ...

  5. 分布式远程服务调用(RPC)框架

    分布式远程服务调用(RPC)框架 finagle:一个支持容错,协议无关的RPC系统 热门度(没变化) 10.0 活跃度(没变化) 10.0  Watchers:581 Star:6174 Fork: ...

  6. dubbo、dubbox、motan、thrift、grpc等RPC框架比较及选型

    概述 前段时间项目要做服务化,所以我比较了现在流行的几大RPC框架的优缺点以及使用场景,最终结合本身项目的实际情况选择了使用dubbox作为rpc基础服务框架.下面就简单介绍一下RPC框架技术选型的过 ...

  7. 【Flink】Flink 底层RPC框架分析

    1. 前言 对于Flink中各个组件(JobMaster.TaskManager.Dispatcher等),其底层RPC框架基于Akka实现,本文着重分析Flink中的Rpc框架实现机制及梳理其通信流 ...

  8. 程序员修神之路--设计一套RPC框架并非易事

    菜菜哥,我最近终于把Socket通信调通了 这么底层的东西你现在都会了,恭喜你离涨薪又进一步呀 http协议不也是利用的Socket吗 可以这么说,http协议是基于TCP协议的,底层的数据传输可以说 ...

  9. 从 BIO、NIO 聊到 Netty,最后还要实现个 RPC 框架!

    大家好,我是 「后端技术进阶」 作者,一个热爱技术的少年. 觉得不错的话,欢迎 star!ღ( ´・ᴗ・` )比心 Netty 从入门到实战系列文章地址:https://github.com/Snai ...

随机推荐

  1. 【起航计划 016】2015 起航计划 Android APIDemo的魔鬼步伐 15 App->Activity->Wallpaper 系统壁纸作为当前Activity的背景

    Wallpaper介绍一个Activity如何通过Style把系统Wallpaper作为当前Activity的背景. 这是WallpaperActivity在AndroidManifest.xml中的 ...

  2. QtWebkits如何向QtWebEngine过渡

    QtWebkits如何向QtWebEngine过渡 1. 前言 很遗憾,QtWebkits在Qt5.6以上版本被淘汰了,对于这个接口良且和其他类例如QWebFrame完美结合的组件就这么没了,我只能表 ...

  3. Java—多态

    多态——对象的多种形态(继承是多态实现的基础) 引用多态:父类的引用可以指向本类的对象:父类的引用可以指向子类的对象 方法多态:创建本类对象时,调用的方法为本类方法:创建子类对象时,调用的方法为子类重 ...

  4. Oracle数据库基本语句练习

    以ORACLE数据库为主提纲:第一部分.SQL语言基础 第一章:Oracle命令类别及sql简单语法介绍第二章:oracle的基本函数第三章:oracle的数据类型第四章:多表连接技术 第二部分.or ...

  5. Linux远程桌面管理

    一: (1)查看用户  Linux系统root用户可强制踢制其它登录用户,首先可用w命令查看登录用户信息 [root@ylLinux~]:# w (2)强制踢人 命令格式:pkill -kill -t ...

  6. myeclipse 10 创建webservice

    java 快捷创建webservice 收集一下,方便一下查阅 详情去看一下这个老哥,里面写得非常详细: http://hyan.iteye.com/ -- http://www.cnblogs.co ...

  7. AD的命名规则 AD常用产品型号命名规则

    AD的命名规则 AD常用产品型号命名规则 DSP信号处理器    放大器工业用器件通信    电源管理    移动通信 视频/图像处理器等 模拟A/D    D/A 转换器 传感器    模拟器件 A ...

  8. linux命令之awk命令

    awk是一种编程语言,用于在linux/unix下对文本和数据进行处理.数据可以来自标准输入(stdin).一个或多个文件,或其它命令的输出.它支持用户自定义函数和动态正则表达式等先进功能,是linu ...

  9. cgi程序报 Premature end of script headers:

    这段时间写了一个CGI,也是为了应付工作,挺简单的一个程序,总是在调用的时候报:Premature end of script headers: 很让人头疼!   在网上找了些资料,按资料 ---- ...

  10. AI-Info-Micron-Insight:5G、人工智能和即将到来的移动革命

    ylbtech-AI-Info-Micron-Insight:5G.人工智能和即将到来的移动革命 1.返回顶部 1. 5G.人工智能和即将到来的移动革命 人们都说自己的手机“智能”,但究竟有多智能?凡 ...