基于akka与scala实现一个简单rpc框架
来源:互联网 发布:windows清理助手在哪儿 编辑:程序博客网 时间:2024/06/16 14:19
一、RPC简介
RPC,即 Remote Procedure Call(远程过程调用),说得通俗一点就是:调用远程计算机上的服务,就像调用本地服务一样。
RPC 可基于 HTTP 或 TCP 协议,Web Service 就是基于 HTTP 协议的 RPC,它具有良好的跨平台性,但其性能却不如基于 TCP 协议的 RPC。会两方面会直接影响 RPC 的性能,一是传输方式,二是序列化。
众所周知,TCP 是传输层协议,HTTP 是应用层协议,而传输层较应用层更加底层,在数据传输方面,越底层越快,因此,在一般情况下,TCP 一定比 HTTP 快。就序列化而言,Java 提供了默认的序列化方式,但在高并发的情况下,这种方式将会带来一些性能上的瓶颈,于是市面上出现了一系列优秀的序列化框架从而提供更高效的性能。
我们需要将服务部署在分布式环境下的不同节点上,通过服务注册的方式,让客户端来自动发现当前可用的服务,并调用这些服务。这需要一种服务注册表(Service Registry)的组件,让它来注册分布式环境下所有的服务地址(包括:主机名与端口号)。
二、代码框架
三、代码实现
该小项目包含四个文件:
1.WorkerInfo,用于保存Worker的信息,此次保存Worker的上一次心跳时间
package com.zxl.rpcclass WorkerInfo(val id: String, val memory: Int, val cores: Int) { // TODO 上一次心跳 var lastHeartbeatTime: Long = _}2.RemoteMessage,实现序列化并定义Master与Worker之间传送信息的类型
package com.zxl.rpc/** * 用于实现序列化 网络传输 */trait RemoteMessage extends Serializable// Worker -> Mastercase class RegisterWorker(id: String, memory: Int, cores: Int) extends RemoteMessagecase class Heartbeat(id: String) extends RemoteMessage// Master -> Workercase class RegisteredWorker(masterUrl: String) extends RemoteMessage// Worker -> selfcase object SendHeartbeat// Master -> selfcase object CheckTimeOutWorker3.Worker,与Master进行消息交互
package com.zxl.rpcimport java.util.UUIDimport akka.actor.{Props, ActorSystem, Actor, ActorSelection}import com.typesafe.config.ConfigFactoryimport scala.concurrent.duration._class Worker(val masterHost: String, val masterPort: Int, val memory: Int, val cores: Int) extends Actor { // 与master连接的对象 var master : ActorSelection = _ // 每个worker的id val workerId = UUID.randomUUID().toString // 发送心跳的时间间隔 val HEART_INTERVAL = 10000 override def preStart(): Unit = { // 建立连接 // 在Master启动时会打印下面的那个协议, 可以先用这个做一个标志, 连接哪个master // 继承actor后会有一个context, 可以通过它来连接 // 需要有/user, 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 // 多长时间后执行 单位,多长时间执行一次 单位, 消息的接受者(直接给master发不好, 先给自己发送消息, 以后可以做下判断, 什么情况下再发送消息), 信息 context.system.scheduler.schedule(0 millis, HEART_INTERVAL millis, self, SendHeartbeat) } case SendHeartbeat => { println("send heartbeat to master") // 对master发送心跳信息,发送当前worker的id master ! Heartbeat(workerId) } }}object Worker { def main(args: Array[String]) { 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) actorSystem.actorOf(Props(new Worker(masterHost, masterPort, memory, cores)), "Worker") actorSystem.awaitTermination() }}4.Master,接收Worker的消息并做回应
package com.zxl.rpcimport akka.actor.{Props, ActorSystem, Actor}import com.typesafe.config.ConfigFactoryimport scala.collection.mutableimport scala.concurrent.duration._class Master(val host: String, val port: Int) extends Actor { // 保存(workerId,WorkerInfo) val idToWorker = new mutable.HashMap[String, WorkerInfo]() // 保存wokerInfo // 使用set删除快, 也可用linkList val workers = new mutable.HashSet[WorkerInfo]() // 超时检查的间隔 val CHECK_INTERVAL = 15000 override def preStart(): Unit = { println("preStart invoked") // 导入隐式转换 import context.dispatcher // 使用timer太low了, 可以使用akka的, 使用定时器, 要导入这个包 // 定时检查worker的心跳时间是否超时 context.system.scheduler.schedule(0 millis, CHECK_INTERVAL millis, self, CheckTimeOutWorker) } // 用于接收消息 override def receive: Receive = { case RegisterWorker(id, memory, cores) => { // 判断一下,是不是已经注册过 if(!idToWorker.contains(id)) { // 把Worker的信息封装起来保存到内存当中 val workerInfo = new WorkerInfo(id, memory, cores) idToWorker(id) = workerInfo workers += workerInfo // 通知worker注册 并将master的地址返回给worker 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() // 更新已收到id的worker的上一次心跳时间 workerInfo.lastHeartbeatTime = currentTime } } case CheckTimeOutWorker => { val currentTime = System.currentTimeMillis() // 获取过时的worker val toRemove = workers.filter(x => currentTime - x.lastHeartbeatTime > CHECK_INTERVAL) // 将超时的worker从两个集合中去掉 for(w <- toRemove) { workers -= w idToWorker -= w.id } println(workers.size) } }}object Master { def main(args: Array[String]) { 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") master ! "hello" actorSystem.awaitTermination() }}
四、效果显示
Master运行效果:
Worker运行效果:
阅读全文
0 0
- 基于akka与scala实现一个简单rpc框架
- Scala基于Akka的Remote Actor实现的简单RPC
- 使用Akka实现一个简单的RPC框架(一)
- 使用Akka实现一个简单的RPC框架(二)
- 简单实现一个rpc框架
- Spark:Akka实现简单RPC通信
- 一个简单的rpc框架的实现
- 一个简单的rpc框架的实现
- 自己实现一个简单的RPC框架
- 如何实现一个简单的rpc框架
- Java实现一个简单的RPC框架(五) 基于Socket的传输层实现
- 使用scala实现Akka底层的rpc通信
- 【远程调用框架】如何实现一个简单的RPC框架(一)想法与设计
- 基于Netty的RPC简单框架实现(五):功能测试与性能测试
- scala分布式框架-akka
- Gatling-基于Scala,Akka&Netty的性能测试框架
- 简单RPC框架-基于Consul的服务注册与发现
- 用AKKA实现简单的RPC通信模型2
- 音视频开发的技术要点 音视频SDK的应用
- 关于Python第三方库安装失败问题的解决方案
- 【LeetCode】C# 24、Swap Nodes in Pairs
- 权限管理系统 ThreadLocal的使用:在同一线程中获取用户信息
- C++学习之对string流的初步认识
- 基于akka与scala实现一个简单rpc框架
- HTML5
- Linux学习之用户,组的基本操作
- Leetcode-Set Matrix Zeroes
- alloy-ui 2.0.0 图片轮播
- angularjs的二种数据绑定
- 使用URL Rewrite 实现网站伪静态
- 模仿QQ左划显示置顶, 标记, 删除
- HTML CSS总结