• scala学习之实现RPC通信


    最近学习scala,个人感觉非常灵活,实现rpc通信非常简单,函数式编程比较烧脑

    1.搭建工程 创建scala maven 工程  

    项目pom文件

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.xiaot</groupId>
      <artifactId>scala-demo</artifactId>
      <version>1.0-SNAPSHOT</version>
      <inceptionYear>2008</inceptionYear>
      <properties>
        <scala.version>2.10.6</scala.version>
      </properties>
    
      <repositories>
        <repository>
          <id>scala-tools.org</id>
          <name>Scala-Tools Maven2 Repository</name>
          <url>http://scala-tools.org/repo-releases</url>
        </repository>
      </repositories>
    
      <pluginRepositories>
        <pluginRepository>
          <id>scala-tools.org</id>
          <name>Scala-Tools Maven2 Repository</name>
          <url>http://scala-tools.org/repo-releases</url>
        </pluginRepository>
      </pluginRepositories>
    
      <dependencies>
        <dependency>
          <groupId>org.scala-lang</groupId>
          <artifactId>scala-library</artifactId>
          <version>${scala.version}</version>
        </dependency>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>org.specs</groupId>
          <artifactId>specs</artifactId>
          <version>1.2.5</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>org.scala-lang</groupId>
          <artifactId>scala-actors</artifactId>
          <version>2.10.6</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.typesafe.akka/akka-actor -->
        <dependency>
          <groupId>com.typesafe.akka</groupId>
          <artifactId>akka-actor_2.10</artifactId>
          <version>2.3.14</version>
        </dependency>
    
        <dependency>
          <groupId>com.typesafe.akka</groupId>
          <artifactId>akka-remote_2.10</artifactId>
          <version>2.3.14</version>
        </dependency>
      </dependencies>
    
      <build>
        <sourceDirectory>src/main/scala</sourceDirectory>
        <testSourceDirectory>src/test/scala</testSourceDirectory>
        <plugins>
          <plugin>
            <groupId>org.scala-tools</groupId>
            <artifactId>maven-scala-plugin</artifactId>
            <executions>
              <execution>
                <goals>
                  <goal>compile</goal>
                  <goal>testCompile</goal>
                </goals>
              </execution>
            </executions>
            <configuration>
              <scalaVersion>${scala.version}</scalaVersion>
              <args>
                <arg>-target:jvm-1.5</arg>
              </args>
            </configuration>
          </plugin>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-eclipse-plugin</artifactId>
            <configuration>
              <downloadSources>true</downloadSources>
              <buildcommands>
                <buildcommand>ch.epfl.lamp.sdt.core.scalabuilder</buildcommand>
              </buildcommands>
              <additionalProjectnatures>
                <projectnature>ch.epfl.lamp.sdt.core.scalanature</projectnature>
              </additionalProjectnatures>
              <classpathContainers>
                <classpathContainer>org.eclipse.jdt.launching.JRE_CONTAINER</classpathContainer>
                <classpathContainer>ch.epfl.lamp.sdt.launching.SCALA_CONTAINER</classpathContainer>
              </classpathContainers>
            </configuration>
          </plugin>
        </plugins>
      </build>
      <reporting>
        <plugins>
          <plugin>
            <groupId>org.scala-tools</groupId>
            <artifactId>maven-scala-plugin</artifactId>
            <configuration>
              <scalaVersion>${scala.version}</scalaVersion>
            </configuration>
          </plugin>
        </plugins>
      </reporting>
    </project>

    2. 创建Master.scala  作为主节点保持跟Worker进行通信  提供Worker注册信息存储和心跳检测

    package com.xiaot.master
    
    import akka.actor.{Actor, ActorRef, ActorSystem, Props}
    import com.typesafe.config.ConfigFactory
    import com.xiaot.worker.WorkerInfo
    import scala.concurrent.duration._
    import scala.collection.mutable
    
    
    /**
      * Created by xiaot on 2018/4/2.
      * scla 实现RPC
      */
    class Master(val host:String,val port :Int)  extends Actor{
    
      //存储worker注册信息
      val idToWork = new mutable.HashMap[String,WorkerInfo]()
      //用于心跳检测动态删除添加worker节点信息
      val workers = new mutable.HashSet[WorkerInfo]()
      //超时时间
      val CHECK_TIME_OUT = 15000
    
      override def preStart(): Unit = {
        println("master preStart ")
        //定时检查worker是否存活 实时删除不存活的worker
        import context.dispatcher
        context.system.scheduler.schedule(0 millis,CHECK_TIME_OUT millis,self,CheckTimeOutWorker)
    
      }
    
      override def receive: Receive = {
        case RegisterWorker(id,memory,cores) =>{
    
          if (!idToWork.contains(id)){
            val workerInfo = new WorkerInfo(id,memory,cores)
            idToWork(id) = workerInfo
            workers+=workerInfo
          }
         println("worker:"+id+" regist to master success")
          sender ! RegisteredWorker(s"akka.tcp://MasterSystem@$host:$port/user/master")
        }
        case HeartBeat(id) =>{
          if (idToWork.contains(id)){
            //获取对应的worker
            val workerInfo = idToWork(id)
            val currentTime = System.currentTimeMillis()
            //心跳检测更新时间
            workerInfo.lastHeartbeatTime = currentTime
          }
        }
        case CheckTimeOutWorker =>{
          val currentTime = System.currentTimeMillis()
          val preMovesWorkers = workers.filter(x => currentTime-x.lastHeartbeatTime>CHECK_TIME_OUT)
    
          for (w<-preMovesWorkers){
            idToWork -= w.id
            workers -=w
          }
          println(workers.size)
        }
      }
    }
    
    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)
        val actorSystem = ActorSystem("MasterSystem",config)
      // 创建actor
        val master = actorSystem.actorOf(Props(new Master(host,port)),"master")
    
        actorSystem.awaitTermination()
      }
    
    
    
    }

    Master运行参数:

    3.创建Worker.scala  作为工作节点 定期向master心跳检测和节点注册信息

    package com.xiaot.worker
    
    import java.util.UUID
    
    import akka.actor.{Actor, ActorSelection, ActorSystem, Props}
    import com.typesafe.config.ConfigFactory
    
    import scala.concurrent.duration._
    import com.xiaot.master.{HeartBeat, RegisterWorker, RegisteredWorker, SendHeartBeat}
    
    /**
      * Created by xiaot on 2018/4/3.
      */
    class Worker(val masterHost:String,val port:Int,val memory:Int,val cores:Int) extends Actor{
    
      var  master :ActorSelection = _
      val workerId = UUID.randomUUID().toString
      val  HEART_INTERAL=10000
    
      override def preStart(): Unit = {
        //与master创建连接
        master = context.actorSelection(s"akka.tcp://MasterSystem@$masterHost:$port/user/master")
        //向master注册
        master ! RegisterWorker(workerId,memory,cores)
      }
    
      override def receive: Receive = {
    
        case RegisteredWorker(masterUrl) =>{
    
          println("worker:"+workerId+" 已经成功注册到"+masterUrl)
          //心跳检测
          import context.dispatcher
          //自己调用自己通过case类进行实际心跳检测实现
          context.system.scheduler.schedule(0 millis,HEART_INTERAL 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
    
        var config = ConfigFactory.parseString(configStr)
        var  worder = ActorSystem("WorderSystem",config)
        worder.actorOf(Props(new Worker(masterHost,masterPort,memory,cores)))
        worder.awaitTermination()
      }
    }

    Worker运行参数:

    WorkerInfo.scala 用于保存工作节点的信息

    package com.xiaot.worker
    
    /**
      * Created by xiaot on 2018/4/4.
      */
    class WorkerInfo(val id:String,val memory:Int,val cores:Int){
    
      var lastHeartbeatTime :Long = _
    }

     RemoteMessage.scala 用于远程信息发送,其中包括心跳检测等样例类

    package com.xiaot.master
    
    /**
      * Created by xiaot on 2018/4/4.
      */
    trait RemoteMessage extends Serializable
    //worker -->master
    case class RegisterWorker(id:String,memory:Int,cores:Int) extends RemoteMessage
    //master--->worker
    case class RegisteredWorker(masterUrl:String) extends RemoteMessage
    //worker---master
    case  class HeartBeat(id:String) extends RemoteMessage
    //worker -->self
    case object SendHeartBeat
    //master -->self
    case object CheckTimeOutWorker

    4. 执行结果

  • 相关阅读:
    scroller,,list里面滚动到最后,,再添加10条数据
    Egret ,dataGroup,,,tabBar,,,List的区别
    自我回答,问题3:Scroller的属性 scrollPolicyV怎么无效呢,,也就是 scrollPolicyV设置为on,但是并没有显示滚动条
    自我回答,问题2:比如有个历史记录,,然后左边有个按钮btnleft,,右边有个按钮btnright,点击对应按钮,,就会有对应历史记录推进,或者后退
    自我回答,问题1:八个按钮(btn0-btn8),,下面有加分8个bitmap(bitmap0-8),,点击按钮对应有bitmap的值+=1
    js生成 1-100 不重复随机数
    laravel 的passport Oauth 认证登录请求 的 oauth_token 重置
    phpunit 测试指定目录下的测试类
    [SymfonyComponentDebugExceptionFatalThrowableError] Class 'Dingo' not found
    laravel 观察器 模型绑定 方法的关系
  • 原文地址:https://www.cnblogs.com/shoutn/p/8717750.html
Copyright © 2020-2023  润新知