Akka 实践之(三) 远程部署

来源:互联网 发布:通达信的软件 编辑:程序博客网 时间:2024/06/06 20:11

Akka 可以支持客户端和服务端远程部署,这点对与高并发分布式调用非常有利。 在上篇的代码基础上,新增2个类,LookupActor和LookupApplication.Java

1、首先看一下类图


2、 源码

在本例中,将远程创建CalculatorActor 对象,然后通过指定path的方式创建这个对象的远程Actor(其实我认为是这个对象的代理)

[java] view plain copy
  1. <span style="font-family:Microsoft YaHei;font-size:14px;">    final String path = "akka.tcp://CalculatorSystem@127.0.0.1:8552/user/calculator";  
  2.     final ActorRef actor = system.actorOf( Props.create(LookupActor.class, path), "lookupActor");</span>  

LookupActor和 LookupApplication的源码如下,重点关注是如何创建远程对象,以及如何获取对远程对象的使用。

[java] view plain copy
  1. <span style="font-family:Microsoft YaHei;font-size:14px;">package com.cwqsolo.study.akka.demo;  
  2.   
  3. import static java.util.concurrent.TimeUnit.SECONDS;  
  4. import scala.concurrent.duration.Duration;  
  5. import akka.actor.ActorRef;  
  6. import akka.actor.ActorIdentity;  
  7. import akka.actor.Identify;  
  8. import akka.actor.Terminated;  
  9. import akka.actor.UntypedActor;  
  10. import akka.actor.ReceiveTimeout;  
  11. import akka.japi.Procedure;  
  12.   
  13. public class LookupActor extends UntypedActor {  
  14.   
  15.   private final String path;  
  16.   private ActorRef calculator = null;  
  17.   
  18.   public LookupActor(String path) {  
  19.     this.path = path;  
  20.     sendIdentifyRequest();  
  21.   }  
  22.   
  23.   private void sendIdentifyRequest() {  
  24.     getContext().actorSelection(path).tell(new Identify(path), getSelf());  
  25.     getContext()  
  26.         .system()  
  27.         .scheduler()  
  28.         .scheduleOnce(Duration.create(3, SECONDS), getSelf(),  
  29.             ReceiveTimeout.getInstance(), getContext().dispatcher(), getSelf());  
  30.   }  
  31.   
  32.   @Override  
  33.   public void onReceive(Object message) throws Exception {  
  34.     if (message instanceof ActorIdentity) {  
  35.       calculator = ((ActorIdentity) message).getRef();  
  36.       if (calculator == null) {  
  37.         System.out.println("Remote actor not available: " + path);  
  38.       } else {  
  39.         getContext().watch(calculator);  
  40.         getContext().become(active, true);  
  41.       }  
  42.   
  43.     } else if (message instanceof ReceiveTimeout) {  
  44.       sendIdentifyRequest();  
  45.   
  46.     } else {  
  47.       System.out.println("Not ready yet");  
  48.   
  49.     }  
  50.   }  
  51.   
  52.   Procedure<Object> active = new Procedure<Object>() {  
  53.     @Override  
  54.     public void apply(Object message) {  
  55.       if (message instanceof Op.MathOp) {  
  56.         // send message to server actor  
  57.         calculator.tell(message, getSelf());  
  58.   
  59.       } else if (message instanceof Op.AddResult) {  
  60.         Op.AddResult result = (Op.AddResult) message;  
  61.         System.out.printf("Add result: %d + %d = %d\n", result.getN1(),  
  62.             result.getN2(), result.getResult());  
  63.   
  64.       } else if (message instanceof Op.SubtractResult) {  
  65.         Op.SubtractResult result = (Op.SubtractResult) message;  
  66.         System.out.printf("Sub result: %d - %d = %d\n", result.getN1(),  
  67.             result.getN2(), result.getResult());  
  68.   
  69.       } else if (message instanceof Terminated) {  
  70.         System.out.println("Calculator terminated");  
  71.         sendIdentifyRequest();  
  72.         getContext().unbecome();  
  73.           
  74.           
  75.   
  76.       } else if (message instanceof ReceiveTimeout) {  
  77.         // ignore  
  78.   
  79.       } else {  
  80.         unhandled(message);  
  81.       }  
  82.   
  83.     }  
  84.   };  
  85. }  
  86. </span>  

可以看到LookupActor 与上节中的CreationActor类没有什么区别,重点是LookupApplication类源码。

[java] view plain copy
  1. <span style="font-family:Microsoft YaHei;font-size:14px;">package com.cwqsolo.study.akka.demo;  
  2. import static java.util.concurrent.TimeUnit.SECONDS;  
  3.   
  4. import java.util.Random;  
  5.   
  6. //import scala.concurrent.duration.Duration;  
  7. //import akka.actor.ActorRef;  
  8. //import akka.actor.ActorSystem;  
  9. //import akka.actor.Props;  
  10. import com.typesafe.config.ConfigFactory;  
  11.   
  12. import java.util.Arrays;    
  13. import java.util.concurrent.Callable;      
  14. import scala.concurrent.*;  
  15. import scala.concurrent.duration.Duration;  
  16. import akka.actor.ActorRef;    
  17. import akka.actor.ActorSystem;    
  18. import akka.actor.Props;    
  19.   
  20. public class LookupApplication {  
  21.   public static void main(String[] args) {  
  22.     if (args.length == 0 || args[0].equals("Calculator"))  
  23.       startRemoteCalculatorSystem();  
  24.     if (args.length == 0 || args[0].equals("Lookup"))  
  25.       startRemoteLookupSystem();  
  26.       
  27.    }  
  28.   
  29.   public static void startRemoteCalculatorSystem() {  
  30. <span style="color:#ff0000;">    final ActorSystem system = ActorSystem.create("CalculatorSystem",  
  31.         ConfigFactory.load(("calculator")));</span>  
  32.     <span style="color:#ff0000;">final ActorRef calActor = system.actorOf(Props.create(CalculatorActor.class), "calculator");</span>  
  33.     //calActor.  
  34.     System.out.println("Started CalculatorSystem");  
  35.   }  
  36.   
  37.   public static void startRemoteLookupSystem() {  
  38.   
  39.     <span style="color:#ff0000;">final ActorSystem system = ActorSystem.create("LookupSystem",  
  40.         ConfigFactory.load("remotelookup"));</span>  
  41. <span style="color:#ff0000;">    final String path = "akka.tcp://CalculatorSystem@127.0.0.1:8552/user/calculator";  
  42.     final ActorRef actor = system.actorOf(  
  43.         Props.create(LookupActor.class, path), "lookupActor");</span>  
  44.   
  45.     System.out.println("Started LookupSystem");  
  46.     final Random r = new Random();  
  47.     system.scheduler().schedule(Duration.create(1, SECONDS),  
  48.         Duration.create(1, SECONDS), new Runnable() {  
  49.           @Override  
  50.           public void run() {  
  51.             if (r.nextInt(100) % 2 == 0) {  
  52.               actor.tell(new Op.Add(r.nextInt(100), r.nextInt(100)), null);  
  53.             } else {  
  54.               actor.tell(new Op.Subtract(r.nextInt(100), r.nextInt(100)), null);  
  55.             }  
  56.   
  57.           }  
  58.         }, system.dispatcher());  
  59.   
  60.   }  
  61. }</span>  
标红代码这里要注意,这里是关键,而且可以看到,这里用到了配置文件(一开始,这里没有搞懂,运行起来都是无法找到远程对象)

配置文件有3个

common.conf

[java] view plain copy
  1. <span style="font-family:Microsoft YaHei;font-size:14px;">[root@archive akka]# cat  common.conf  
  2. akka {    
  3.   actor {    
  4.     provider = "akka.remote.RemoteActorRefProvider"    
  5.   }    
  6.     
  7.   remote {    
  8.      enabled-transports = ["akka.remote.netty.tcp"]    
  9.     netty.tcp {    
  10.       hostname = "127.0.0.1"    
  11.     }    
  12.   }    
  13. }</span>  
[java] view plain copy
  1. <span style="font-family:Microsoft YaHei;font-size:14px;">[root@archive akka]# cat  calculator.conf  
  2. include "common"    
  3.     
  4. akka {    
  5.   # LISTEN on tcp port 2552    
  6.   remote.netty.tcp.port = 8552    
  7. }  </span>  


[java] view plain copy
  1. <span style="font-family:Microsoft YaHei;font-size:14px;">[root@archive akka]# cat  remotelookup.conf   
  2. include "common"  
  3.   
  4. akka {  
  5.   remote.netty.tcp.port = 2553  
  6. }</span>  
从上面的配置文件可以看到, calculator对象在8552端口进行监听,  lookup对象通过remotelookup创建了 2553端口的监听,lookup对象通过path 获取

到calculator对象的引用(代理),然后就可以进行对象间的调用。

3、执行结果

[root@archive akka]# sh  ./start.sh
Java version "1.7.0_80"
Java(TM) SE Runtime Environment (build 1.7.0_80-b15)
java HotSpot(TM) 64-Bit Server VM (build 24.80-b11, mixed mode)
[INFO] [10/27/2016 16:48:26.956] [main] [Remoting] Starting remoting
[INFO] [10/27/2016 16:48:27.234] [main] [Remoting] Remoting started; listening on addresses :[akka.tcp://CalculatorSystem@127.0.0.1:8552]
[INFO] [10/27/2016 16:48:27.236] [main] [Remoting] Remoting now listens on addresses: [akka.tcp://CalculatorSystem@127.0.0.1:8552]
Started CalculatorSystem
[INFO] [10/27/2016 16:48:27.311] [main] [Remoting] Starting remoting
[INFO] [10/27/2016 16:48:27.339] [main] [Remoting] Remoting started; listening on addresses :[akka.tcp://LookupSystem@127.0.0.1:2553]
[INFO] [10/27/2016 16:48:27.339] [main] [Remoting] Remoting now listens on addresses: [akka.tcp://LookupSystem@127.0.0.1:2553]
Started LookupSystem
Calculating 9 - 61
Sub result: 9 - 61 = -52
Calculating 51 - 86
Sub result: 51 - 86 = -35
Calculating 64 - 30
Sub result: 64 - 30 = 34
Calculating 38 + 71
Add result: 38 + 71 = 109
Calculating 51 - 73
Sub result: 51 - 73 = -22
Calculating 29 + 12
Add result: 29 + 12 = 41


4、注意内容

4.1 因为引入了配置文件,需要使用google的配置文件类protobuf-java-2.5.0.jar

4.2 打包运行

      我是eclipse环境中调试后,放centos执行的,一开始把代码和依赖库打包在一起,执行会报错。最后是将依赖库单独在centos上建一个lib,只打包代码部分,这样执行才没有问题。

    

[java] view plain copy
  1. <span style="font-family:Microsoft YaHei;font-size:14px;">[root@archive akka]# Exception in thread "main" com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'akka.version'  
  2.         at com.typesafe.config.impl.SimpleConfig.findKey(SimpleConfig.java:124)  
  3.         at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:145)  
  4. </span>  
    或者是这样

   

[java] view plain copy
  1. <span style="font-family:Microsoft YaHei;font-size:14px;">Java HotSpot(TM) 64-Bit Server VM (build 24.80-b11, mixed mode)  
  2. [root@archive akka]# Exception in thread "main" java.lang.NoClassDefFoundError: scala/concurrent/ExecutionContext  
  3.         at java.lang.Class.getDeclaredMethods0(Native Method)  
  4.         at java.lang.Class.privateGetDeclaredMethods(Class.java:2625)  
  5.         at java.lang.Class.getMethod0(Class.java:2866)  
  6.         at java.lang.Class.getMethod(Class.java:1676)  
  7. </span>  
     最后通过只打包自己的代码, lib库单独放置的方式解决
 


原创粉丝点击