├── README.MD ├── pom.xml └── src └── main ├── java └── cn │ └── sunxiang0918 │ └── akka │ ├── demo1 │ ├── AkkaMain.java │ ├── actor │ │ ├── GreetPrinter.java │ │ └── Greeter.java │ └── model │ │ ├── Greet.java │ │ ├── Greeting.java │ │ └── WhoToGreet.java │ ├── demo1_5 │ ├── AkkaMain.java │ └── actor │ │ ├── Squarer.java │ │ └── SquarerImpl.java │ ├── demo2 │ ├── client │ │ ├── ClientMain.java │ │ └── actor │ │ │ ├── ClientActor.java │ │ │ └── FileReadActor.java │ └── server │ │ ├── MyPriorityMailBox.java │ │ ├── WCMapReduceServer.java │ │ ├── actor │ │ ├── AggregateActor.java │ │ ├── MapActor.java │ │ ├── ReduceActor.java │ │ └── WCMapReduceActor.java │ │ └── model │ │ └── Result.java │ ├── demo3 │ ├── AkkaMain3.java │ └── actor │ │ ├── JobControllerActor.java │ │ └── WorkerActor.java │ ├── demo4 │ ├── AkkaMain4.java │ ├── actor │ │ ├── ReceiveActor.java │ │ └── ResultActor.java │ └── model │ │ └── Result.java │ ├── demo5 │ ├── AkkaMain5.java │ ├── actor │ │ ├── ControlActor.java │ │ ├── VoteCountRouter.java │ │ └── WriterActor.java │ └── model │ │ ├── ControlCommand.java │ │ ├── ExecutionResult.java │ │ ├── InsertCommand.java │ │ └── StartCommand.java │ ├── demo6 │ ├── SimpleClusterApp.java │ ├── SimpleClusterListener.java │ └── SimpleClusterListener2.java │ ├── demo7 │ ├── FactorialApp.java │ ├── FactorialBackend.java │ ├── FactorialBackendMain.java │ ├── FactorialFrontend.java │ ├── FactorialFrontendMain.java │ ├── FactorialResult.java │ └── MetricsListener.java │ ├── demo8 │ ├── ClusterRoledWorker.java │ ├── Demo8App.java │ ├── EventClient.java │ ├── EventCollector.java │ ├── EventInterceptor.java │ ├── EventInterceptorMain.java │ ├── EventMessages.java │ ├── EventProcessor.java │ ├── EventProcessorMain.java │ └── kafka │ │ ├── KafkaTemplate.java │ │ ├── ObjectDecoder.java │ │ └── ObjectEncoder.java │ └── demo9 │ └── FutureTest.java ├── resources ├── Othello.txt ├── application.conf ├── client.conf ├── demo5.conf ├── demo6.conf ├── demo7.conf └── demo8.conf └── webapp ├── WEB-INF └── web.xml └── index.jsp /README.MD: -------------------------------------------------------------------------------- 1 | AKKA In JAVA 的DEMO 代码. 2 | 相关文章为: 3 | 4 | * [Akka in JAVA(一)](http://sunxiang0918.cn/2016/01/10/Akka-in-JAVA-1/) 5 | * [Akka in JAVA(二)](http://sunxiang0918.cn/2016/01/13/Akka-in-JAVA-2/) 6 | * [Akka in JAVA(三)](http://sunxiang0918.cn/2016/01/18/Akka-in-JAVA-3/) 7 | * [Akka in JAVA(四)](http://sunxiang0918.cn/2016/02/10/Akka-in-JAVA-4/) 8 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | cn.sunxiang0918 5 | akkatest 6 | war 7 | 1.0-SNAPSHOT 8 | akkatest Maven Webapp 9 | http://maven.apache.org 10 | 11 | 12 | junit 13 | junit 14 | 4.12 15 | test 16 | 17 | 18 | com.typesafe.akka 19 | akka-actor_2.11 20 | 2.4.1 21 | 22 | 23 | com.typesafe.akka 24 | akka-remote_2.11 25 | 2.4.1 26 | 27 | 28 | 29 | com.typesafe.akka 30 | akka-cluster_2.11 31 | 2.4.1 32 | 33 | 34 | 35 | org.apache.httpcomponents 36 | httpclient 37 | 4.4.1 38 | 39 | 40 | 41 | com.alibaba 42 | fastjson 43 | 1.2.6 44 | 45 | 46 | 47 | org.apache.kafka 48 | kafka_2.11 49 | 0.9.0.0 50 | 51 | 52 | org.apache.kafka 53 | kafka-clients 54 | 0.9.0.0 55 | 56 | 57 | 58 | 59 | akkatest 60 | 61 | 62 | org.apache.maven.plugins 63 | maven-compiler-plugin 64 | 65 | 1.8 66 | 1.8 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo1/AkkaMain.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo1; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import akka.actor.ActorRef; 6 | import akka.actor.ActorSelection; 7 | import akka.actor.ActorSystem; 8 | import akka.actor.Inbox; 9 | import akka.actor.Props; 10 | import cn.sunxiang0918.akka.demo1.actor.GreetPrinter; 11 | import cn.sunxiang0918.akka.demo1.actor.Greeter; 12 | import cn.sunxiang0918.akka.demo1.model.Greet; 13 | import cn.sunxiang0918.akka.demo1.model.Greeting; 14 | import cn.sunxiang0918.akka.demo1.model.WhoToGreet; 15 | import scala.concurrent.duration.Duration; 16 | 17 | /** 18 | * @author SUN 19 | * @version 1.0 20 | * @Date 16/1/6 21:39 21 | */ 22 | public class AkkaMain { 23 | 24 | public static void main(String[] args) throws Exception { 25 | final ActorSystem system = ActorSystem.create("helloakka"); 26 | 27 | // 创建一个到greeter Actor的管道 28 | final ActorRef greeter = system.actorOf(Props.create(Greeter.class), "greeter"); 29 | 30 | System.out.println(greeter.path()); 31 | 32 | final ActorSelection selection = system.actorSelection("akka://helloakka/user/greeter"); 33 | selection.tell(new WhoToGreet("akka"), ActorRef.noSender()); 34 | 35 | // 创建邮箱 36 | final Inbox inbox = Inbox.create(system); 37 | 38 | // 先发第一个消息,消息类型为WhoToGreet 39 | // greeter.tell(new WhoToGreet("akka"), ActorRef.noSender()); 40 | 41 | // 真正的发送消息,消息体为Greet 42 | inbox.send(greeter, new Greet()); 43 | 44 | // 等待5秒尝试接收Greeter返回的消息 45 | Greeting greeting1 = (Greeting) inbox.receive(Duration.create(5, TimeUnit.SECONDS)); 46 | System.out.println("Greeting: " + greeting1.message); 47 | 48 | // 发送第三个消息,修改名字 49 | greeter.tell(new WhoToGreet("typesafe"), ActorRef.noSender()); 50 | // 发送第四个消息 51 | inbox.send(greeter, new Greet()); 52 | 53 | // 等待5秒尝试接收Greeter返回的消息 54 | Greeting greeting2 = (Greeting) inbox.receive(Duration.create(5, TimeUnit.SECONDS)); 55 | System.out.println("Greeting: " + greeting2.message); 56 | 57 | // 新创建一个Actor的管道 58 | ActorRef greetPrinter = system.actorOf(Props.create(GreetPrinter.class)); 59 | 60 | //使用schedule 每一秒发送一个Greet消息给 greeterActor,然后把greeterActor的消息返回给greetPrinterActor 61 | system.scheduler().schedule(Duration.Zero(), Duration.create(1, TimeUnit.SECONDS), greeter, new Greet(), system.dispatcher(), greetPrinter); 62 | //system.shutdown(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo1/actor/GreetPrinter.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo1.actor; 2 | 3 | import akka.actor.UntypedActor; 4 | import cn.sunxiang0918.akka.demo1.model.Greeting; 5 | 6 | /** 7 | * 打印招呼 8 | * @author SUN 9 | * @version 1.0 10 | * @Date 16/1/6 21:45 11 | */ 12 | public class GreetPrinter extends UntypedActor{ 13 | 14 | @Override 15 | public void onReceive(Object message) throws Exception { 16 | if (message instanceof Greeting) 17 | System.out.println(((Greeting) message).message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo1/actor/Greeter.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo1.actor; 2 | 3 | import akka.actor.UntypedActor; 4 | import cn.sunxiang0918.akka.demo1.model.Greet; 5 | import cn.sunxiang0918.akka.demo1.model.Greeting; 6 | import cn.sunxiang0918.akka.demo1.model.WhoToGreet; 7 | 8 | /** 9 | * 打招呼的Actor 10 | * @author SUN 11 | * @version 1.0 12 | * @Date 16/1/6 21:40 13 | */ 14 | public class Greeter extends UntypedActor{ 15 | 16 | String greeting = ""; 17 | 18 | @Override 19 | public void onReceive(Object message) throws Exception { 20 | if (message instanceof WhoToGreet) 21 | greeting = "hello, " + ((WhoToGreet) message).who; 22 | else if (message instanceof Greet) 23 | // 发送招呼消息给发送消息给这个Actor的Actor 24 | getSender().tell(new Greeting(greeting), getSelf()); 25 | 26 | else unhandled(message); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo1/model/Greet.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo1.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * 用于表示执行打招呼这个操作的消息 7 | * @author SUN 8 | * @version 1.0 9 | * @Date 16/1/6 21:43 10 | */ 11 | public class Greet implements Serializable { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo1/model/Greeting.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo1.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * 招呼体,里面有打的什么招呼 7 | * @author SUN 8 | * @version 1.0 9 | * @Date 16/1/6 21:44 10 | */ 11 | public class Greeting implements Serializable { 12 | public final String message; 13 | public Greeting(String message) { 14 | this.message = message; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo1/model/WhoToGreet.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo1.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * 打招呼的人 7 | * @author SUN 8 | * @version 1.0 9 | * @Date 16/1/6 21:41 10 | */ 11 | public class WhoToGreet implements Serializable { 12 | public final String who; 13 | public WhoToGreet(String who) { 14 | this.who = who; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo1_5/AkkaMain.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo1_5; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import akka.actor.ActorSystem; 6 | import akka.actor.TypedActor; 7 | import akka.actor.TypedProps; 8 | import akka.japi.Creator; 9 | import akka.japi.Option; 10 | import cn.sunxiang0918.akka.demo1_5.actor.Squarer; 11 | import cn.sunxiang0918.akka.demo1_5.actor.SquarerImpl; 12 | import scala.concurrent.Await; 13 | import scala.concurrent.Future; 14 | import scala.concurrent.duration.Duration; 15 | 16 | /** 17 | * @author SUN 18 | * @version 1.0 19 | * @Date 16/1/24 13:57 20 | */ 21 | public class AkkaMain { 22 | 23 | public static void main(String[] args) throws Exception { 24 | final ActorSystem system = ActorSystem.create("helloakka"); 25 | 26 | /*默认构造方法的Actor*/ 27 | Squarer mySquarer = TypedActor.get(system).typedActorOf(new TypedProps<>(Squarer.class, SquarerImpl.class)); 28 | 29 | /*传参构造的Actor*/ 30 | Squarer otherSquarer = 31 | TypedActor.get(system).typedActorOf(new TypedProps<>(Squarer.class, 32 | new Creator() { 33 | public SquarerImpl create() { 34 | return new SquarerImpl("foo"); 35 | } 36 | }), 37 | "name"); 38 | 39 | 40 | Option oSquare = mySquarer.squareNowPlease(10); //Option[Int] 41 | System.out.println("阻塞异步调用执行外面"); 42 | //获取结果 43 | System.out.println(oSquare.get()); 44 | 45 | Future fSquare = mySquarer.square(10); //A Future[Int] 46 | System.out.println("非阻塞异步执行外面"); 47 | //等待5秒内返回结果 48 | System.out.println(Await.result(fSquare, Duration.apply(5, TimeUnit.SECONDS))); 49 | 50 | TypedActor.get(system).stop(mySquarer); 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo1_5/actor/Squarer.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo1_5.actor; 2 | 3 | import akka.japi.Option; 4 | import scala.concurrent.Future; 5 | 6 | /** 7 | * @author SUN 8 | * @version 1.0 9 | * @Date 16/1/24 13:53 10 | */ 11 | public interface Squarer { 12 | 13 | Future square(int i); //non-blocking send-request-reply 14 | 15 | Option squareNowPlease(int i);//blocking send-request-reply 16 | 17 | int squareNow(int i); //blocking send-request-reply 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo1_5/actor/SquarerImpl.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo1_5.actor; 2 | 3 | import akka.dispatch.Futures; 4 | import akka.japi.Option; 5 | import scala.concurrent.Future; 6 | 7 | /** 8 | * @author SUN 9 | * @version 1.0 10 | * @Date 16/1/24 13:55 11 | */ 12 | public class SquarerImpl implements Squarer { 13 | 14 | private String name; 15 | 16 | public SquarerImpl() { 17 | this.name = "default"; 18 | } 19 | 20 | public SquarerImpl(String name) { 21 | this.name = name; 22 | } 23 | 24 | public Future square(int i) { 25 | return Futures.successful(squareNow(i)); 26 | } 27 | 28 | public Option squareNowPlease(int i) { 29 | return Option.some(squareNow(i)); 30 | } 31 | 32 | public int squareNow(int i) { 33 | try { 34 | Thread.sleep(100); 35 | } catch (InterruptedException e) { 36 | e.printStackTrace(); 37 | } 38 | System.out.println("执行里面"); 39 | return i * i; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo2/client/ClientMain.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo2.client; 2 | 3 | import akka.actor.ActorRef; 4 | import akka.actor.ActorSystem; 5 | import akka.actor.Props; 6 | import cn.sunxiang0918.akka.demo2.client.actor.ClientActor; 7 | import cn.sunxiang0918.akka.demo2.client.actor.FileReadActor; 8 | import com.typesafe.config.ConfigFactory; 9 | 10 | /** 11 | * @author SUN 12 | * @version 1.0 13 | * @Date 16/1/7 10:19 14 | */ 15 | public class ClientMain { 16 | 17 | public static void main(String[] args) throws Exception { 18 | 19 | //文件名 20 | final String fileName = "Othello.txt"; 21 | 22 | /*根据配置,找到System*/ 23 | ActorSystem system = ActorSystem.create("ClientApplication", ConfigFactory.load("client").getConfig("WCMapReduceClientApp")); 24 | 25 | /*实例化远程Actor*/ 26 | final ActorRef remoteActor = system.actorFor("akka.tcp://WCMapReduceApp@127.0.0.1:2552/user/WCMapReduceActor"); 27 | 28 | /*实例化Actor的管道*/ 29 | final ActorRef fileReadActor = system.actorOf(Props.create(FileReadActor.class)); 30 | 31 | /*实例化Client的Actor管道*/ 32 | final ActorRef clientActor = system.actorOf(Props.create(ClientActor.class,remoteActor)); 33 | 34 | /*发送文件名给fileReadActor.设置sender或者说回调的Actor为clientActor*/ 35 | fileReadActor.tell(fileName,clientActor); 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo2/client/actor/ClientActor.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo2.client.actor; 2 | 3 | import akka.actor.ActorRef; 4 | import akka.actor.UntypedActor; 5 | 6 | /** 7 | * @author SUN 8 | * @version 1.0 9 | * @Date 16/1/7 10:20 10 | */ 11 | public class ClientActor extends UntypedActor { 12 | 13 | private ActorRef remoteServer = null; 14 | private long start; 15 | 16 | /** 17 | * @param inRemoteServer 18 | */ 19 | public ClientActor(ActorRef inRemoteServer) { 20 | remoteServer = inRemoteServer; 21 | } 22 | 23 | @Override 24 | public void onReceive(Object message) throws Exception { 25 | /*如果接收到的任务是String的,那么就直接发送给remoteServer这个Actor*/ 26 | if (message instanceof String) { 27 | String msg = (String) message; 28 | if (message.equals("EOF")){ 29 | //这个的Sender设置为自己是为了接收聚合完成的消息 30 | remoteServer.tell(msg, getSelf()); 31 | }else{ 32 | remoteServer.tell(msg, null); 33 | } 34 | }else if (message instanceof Boolean) { 35 | System.out.println("聚合完成"); 36 | //聚合完成后发送显示结果的消息 37 | remoteServer.tell("DISPLAY_LIST",null); 38 | 39 | //执行完毕,关机 40 | getContext().stop(self()); 41 | } 42 | } 43 | 44 | @Override 45 | public void preStart() { 46 | /*记录开始时间*/ 47 | start = System.currentTimeMillis(); 48 | } 49 | 50 | @Override 51 | public void postStop() { 52 | /*计算用时*/ 53 | // tell the world that the calculation is complete 54 | long timeSpent = (System.currentTimeMillis() - start); 55 | System.out 56 | .println(String 57 | .format("\n\tClientActor estimate: \t\t\n\tCalculation time: \t%s MS", 58 | timeSpent)); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo2/client/actor/FileReadActor.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo2.client.actor; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | 7 | import akka.actor.UntypedActor; 8 | 9 | /** 10 | * 从文件里面获取出行数 11 | * 12 | * @author SUN 13 | * @version 1.0 14 | * @Date 16/1/6 22:25 15 | */ 16 | public class FileReadActor extends UntypedActor { 17 | 18 | @Override 19 | public void onReceive(Object message) throws Exception { 20 | if (message instanceof String) { 21 | /*如果消息是String类型的*/ 22 | String fileName = (String) message; 23 | try { 24 | BufferedReader reader = new BufferedReader( 25 | new InputStreamReader(Thread.currentThread().getContextClassLoader().getResource(fileName).openStream())); 26 | String line; 27 | while ((line = reader.readLine()) != null) { 28 | /*遍历,一行一个消息反馈给消息发送方*/ 29 | getSender().tell(line,null); 30 | } 31 | System.out.println("All lines send !"); 32 | /*发送一个结束标识*/ 33 | getSender().tell(String.valueOf("EOF"),null); 34 | } catch (IOException x) { 35 | System.err.format("IOException: %s%n", x); 36 | } 37 | } else { 38 | throw new IllegalArgumentException("Unknown message [" + message + "]"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo2/server/MyPriorityMailBox.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo2.server; 2 | 3 | import akka.actor.ActorSystem; 4 | import akka.actor.PoisonPill; 5 | import akka.dispatch.PriorityGenerator; 6 | import akka.dispatch.UnboundedPriorityMailbox; 7 | import com.typesafe.config.Config; 8 | 9 | /** 10 | * @author SUN 11 | * @version 1.0 12 | * @Date 16/1/7 13:32 13 | */ 14 | public class MyPriorityMailBox extends UnboundedPriorityMailbox { 15 | 16 | /** 17 | * 创建一个自定义优先级的无边界的邮箱. 用来规定命令的优先级. 这个就保证了DISPLAY_LIST 这个事件是最后再来处理. 18 | */ 19 | public MyPriorityMailBox(ActorSystem.Settings settings, Config config) { 20 | 21 | // Creating a new PriorityGenerator, 22 | super(new PriorityGenerator() { 23 | @Override 24 | public int gen(Object message) { 25 | if (message.equals("DISPLAY_LIST")) 26 | return 2; // 'DisplayList messages should be treated 27 | // last if possible 28 | else if (message.equals(PoisonPill.getInstance())) 29 | return 3; // PoisonPill when no other left 30 | else 31 | return 0; // By default they go with high priority 32 | } 33 | }); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo2/server/WCMapReduceServer.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo2.server; 2 | 3 | import akka.actor.ActorRef; 4 | import akka.actor.ActorSystem; 5 | import akka.actor.Props; 6 | import akka.routing.RoundRobinPool; 7 | import cn.sunxiang0918.akka.demo2.server.actor.AggregateActor; 8 | import cn.sunxiang0918.akka.demo2.server.actor.MapActor; 9 | import cn.sunxiang0918.akka.demo2.server.actor.ReduceActor; 10 | import cn.sunxiang0918.akka.demo2.server.actor.WCMapReduceActor; 11 | import com.typesafe.config.ConfigFactory; 12 | 13 | /** 14 | * @author SUN 15 | * @version 1.0 16 | * @Date 16/1/7 10:43 17 | */ 18 | public class WCMapReduceServer{ 19 | 20 | private ActorRef mapRouter; 21 | private ActorRef reduceRouter; 22 | private ActorRef aggregateActor; 23 | private ActorRef wcMapReduceActor; 24 | 25 | public WCMapReduceServer(int no_of_reduce_workers, int no_of_map_workers) { 26 | /*创建了Actor系统*/ 27 | ActorSystem system = ActorSystem.create("WCMapReduceApp", ConfigFactory.load("application") 28 | .getConfig("WCMapReduceApp")); 29 | 30 | // 创建聚合Actor 31 | aggregateActor = system.actorOf(Props.create(AggregateActor.class)); 32 | 33 | // 创建多个聚合的Actor 34 | reduceRouter = system.actorOf(Props.create(ReduceActor.class,aggregateActor).withRouter(new RoundRobinPool(no_of_reduce_workers))); 35 | 36 | // 创建多个Map的Actor 37 | mapRouter = system.actorOf(Props.create(MapActor.class,reduceRouter).withRouter(new RoundRobinPool(no_of_map_workers))); 38 | 39 | // create the overall WCMapReduce Actor that acts as the remote actor 40 | // for clients 41 | Props props = Props.create(WCMapReduceActor.class,aggregateActor,mapRouter).withDispatcher("priorityMailBox-dispatcher"); 42 | wcMapReduceActor = system.actorOf(props, "WCMapReduceActor"); 43 | } 44 | 45 | /** 46 | * @param args 47 | */ 48 | public static void main(String[] args) { 49 | new WCMapReduceServer(50, 50); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo2/server/actor/AggregateActor.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo2.server.actor; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import akka.actor.UntypedActor; 7 | 8 | /** 9 | * @author SUN 10 | * @version 1.0 11 | * @Date 16/1/7 10:41 12 | */ 13 | public class AggregateActor extends UntypedActor { 14 | 15 | /*最终的结果*/ 16 | private Map finalReducedMap = new HashMap<>(); 17 | 18 | @Override 19 | public void preStart() throws Exception { 20 | System.out.println("启动AggregateActor:"+Thread.currentThread().getName()); 21 | } 22 | 23 | @Override 24 | public void onReceive(Object message) throws Exception { 25 | /*如果是Map,那么就进行reduce操作*/ 26 | if (message instanceof Map) { 27 | Map reducedList = (Map) message; 28 | aggregateInMemoryReduce(reducedList); 29 | } else if (message instanceof String) { 30 | /*如果是String,那么就是打印结果*/ 31 | if (((String) message).compareTo("DISPLAY_LIST") == 0) { 32 | //getSender().tell(finalReducedMap.toString()); 33 | System.out.println(finalReducedMap.toString()); 34 | 35 | } 36 | }else if (message instanceof Boolean) { 37 | /*向客户端发送已经reduce完成的信息*/ 38 | getSender().tell(true,null); 39 | } 40 | } 41 | 42 | private void aggregateInMemoryReduce(Map reducedList) { 43 | 44 | for (String key : reducedList.keySet()) { 45 | /*最终的数量的累加*/ 46 | if (finalReducedMap.containsKey(key)) { 47 | Integer count = reducedList.get(key) + finalReducedMap.get(key); 48 | finalReducedMap.put(key, count); 49 | } else { 50 | finalReducedMap.put(key, reducedList.get(key)); 51 | } 52 | 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo2/server/actor/MapActor.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo2.server.actor; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.StringTokenizer; 7 | 8 | import akka.actor.ActorRef; 9 | import akka.actor.UntypedActor; 10 | import cn.sunxiang0918.akka.demo2.server.model.Result; 11 | 12 | /** 13 | * @author SUN 14 | * @version 1.0 15 | * @Date 16/1/7 10:33 16 | */ 17 | public class MapActor extends UntypedActor { 18 | 19 | //停用词 20 | String[] STOP_WORDS = {"a", "about", "above", "above", "across", "after", 21 | "afterwards", "again", "against", "all", "almost", "alone", 22 | "along", "already", "also", "although", "always", "am", "among", 23 | "amongst", "amoungst", "amount", "an", "and", "another", "any", 24 | "anyhow", "anyone", "anything", "anyway", "anywhere", "are", 25 | "around", "as", "at", "back", "be", "became", "because", "become", 26 | "becomes", "becoming", "been", "before", "beforehand", "behind", 27 | "being", "below", "beside", "besides", "between", "beyond", "bill", 28 | "both", "bottom", "but", "by", "call", "can", "cannot", "cant", 29 | "co", "con", "could", "couldnt", "cry", "de", "describe", "detail", 30 | "do", "done", "down", "due", "during", "each", "eg", "eight", 31 | "either", "eleven", "else", "elsewhere", "empty", "enough", "etc", 32 | "even", "ever", "every", "everyone", "everything", "everywhere", 33 | "except", "few", "fifteen", "fify", "fill", "find", "fire", 34 | "first", "five", "for", "former", "formerly", "forty", "found", 35 | "four", "from", "front", "full", "further", "get", "give", "go", 36 | "had", "has", "hasnt", "have", "he", "hence", "her", "here", 37 | "hereafter", "hereby", "herein", "hereupon", "hers", "herself", 38 | "him", "himself", "his", "how", "however", "hundred", "ie", "if", 39 | "in", "inc", "indeed", "interest", "into", "is", "it", "its", 40 | "itself", "keep", "last", "latter", "latterly", "least", "less", 41 | "ltd", "made", "many", "may", "me", "meanwhile", "might", "mill", 42 | "mine", "more", "moreover", "most", "mostly", "move", "much", 43 | "must", "my", "myself", "name", "namely", "neither", "never", 44 | "nevertheless", "next", "nine", "no", "nobody", "none", "noone", 45 | "nor", "not", "nothing", "now", "nowhere", "of", "off", "often", 46 | "on", "once", "one", "only", "onto", "or", "other", "others", 47 | "otherwise", "our", "ours", "ourselves", "out", "over", "own", 48 | "part", "per", "perhaps", "please", "put", "rather", "re", "same", 49 | "see", "seem", "seemed", "seeming", "seems", "serious", "several", 50 | "she", "should", "show", "side", "since", "sincere", "six", 51 | "sixty", "so", "some", "somehow", "someone", "something", 52 | "sometime", "sometimes", "somewhere", "still", "such", "system", 53 | "take", "ten", "than", "that", "the", "their", "them", 54 | "themselves", "then", "thence", "there", "thereafter", "thereby", 55 | "therefore", "therein", "thereupon", "these", "they", "thickv", 56 | "thin", "third", "this", "those", "though", "three", "through", 57 | "throughout", "thru", "thus", "to", "together", "too", "top", 58 | "toward", "towards", "twelve", "twenty", "two", "un", "under", 59 | "until", "up", "upon", "us", "very", "via", "was", "we", "well", 60 | "were", "what", "whatever", "when", "whence", "whenever", "where", 61 | "whereafter", "whereas", "whereby", "wherein", "whereupon", 62 | "wherever", "whether", "which", "while", "whither", "who", 63 | "whoever", "whole", "whom", "whose", "why", "will", "with", 64 | "within", "without", "would", "yet", "you", "your", "yours", 65 | "yourself", "yourselves", "the"}; 66 | 67 | List STOP_WORDS_LIST = Arrays.asList(STOP_WORDS); 68 | 69 | /*reduce聚合的Actor*/ 70 | private ActorRef actor = null; 71 | 72 | public MapActor(ActorRef inReduceActor) { 73 | actor = inReduceActor; 74 | } 75 | 76 | @Override 77 | public void preStart() throws Exception { 78 | System.out.println("启动MapActor:"+Thread.currentThread().getName()); 79 | } 80 | 81 | /** 82 | * 用于分词 计算单词的数量的 83 | * @param line 84 | * @return 85 | */ 86 | private List evaluateExpression(String line) { 87 | List list = new ArrayList<>(); 88 | /*字符串分词器*/ 89 | StringTokenizer parser = new StringTokenizer(line); 90 | while (parser.hasMoreTokens()) { 91 | /*如果是,那么就判断是否是字母.然后把结果记录下来*/ 92 | String word = parser.nextToken().toLowerCase(); 93 | if (isAlpha(word) && !STOP_WORDS_LIST.contains(word)) { 94 | list.add(new Result(word, 1)); 95 | } 96 | } 97 | return list; 98 | } 99 | 100 | /** 101 | * 判断是否是字母 102 | * @param s 103 | * @return 104 | */ 105 | private boolean isAlpha(String s) { 106 | s = s.toUpperCase(); 107 | for (int i = 0; i < s.length(); i++) { 108 | int c = (int) s.charAt(i); 109 | if (c < 65 || c > 90) 110 | return false; 111 | } 112 | return true; 113 | } 114 | 115 | @Override 116 | public void onReceive(Object message) throws Exception { 117 | if (message instanceof String) { 118 | String work = (String) message; 119 | 120 | if (work.equals("EOF")){ 121 | /*表示已经结束了*/ 122 | actor.tell(true,null); 123 | return; 124 | } 125 | 126 | // 计算这一行的单词情况 127 | List list = evaluateExpression(work); 128 | 129 | // 把这一行的单词情况发送给汇总的ReduceActor 130 | actor.tell(list, null); 131 | } else 132 | throw new IllegalArgumentException("Unknown message [" + message + "]"); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo2/server/actor/ReduceActor.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo2.server.actor; 2 | 3 | import java.util.List; 4 | import java.util.NavigableMap; 5 | import java.util.concurrent.ConcurrentSkipListMap; 6 | 7 | import akka.actor.ActorRef; 8 | import akka.actor.UntypedActor; 9 | import cn.sunxiang0918.akka.demo2.server.model.Result; 10 | 11 | /** 12 | * @author SUN 13 | * @version 1.0 14 | * @Date 16/1/7 10:38 15 | */ 16 | public class ReduceActor extends UntypedActor { 17 | 18 | /*管道Actor*/ 19 | private ActorRef actor = null; 20 | 21 | public ReduceActor(ActorRef inAggregateActor) { 22 | actor = inAggregateActor; 23 | } 24 | 25 | @Override 26 | public void preStart() throws Exception { 27 | System.out.println("启动ReduceActor:"+Thread.currentThread().getName()); 28 | } 29 | 30 | @Override 31 | public void onReceive(Object message) throws Exception { 32 | if (message instanceof List) { 33 | 34 | /*强制转换结果*/ 35 | List work = (List) message; 36 | 37 | // 第一次汇总单词表结果. 38 | NavigableMap reducedList = reduce(work); 39 | 40 | // 把这次汇总的结果发送给最终的结果聚合Actor 41 | actor.tell(reducedList, null); 42 | 43 | }else if (message instanceof Boolean) { 44 | //表示已经计算结束了 45 | // 把这次汇总的结果发送给最终的结果聚合Actor 46 | actor.tell(message, null); 47 | } else 48 | throw new IllegalArgumentException("Unknown message [" + message + "]"); 49 | } 50 | 51 | /** 52 | * 聚合计算本次结果中各个单词的出现次数 53 | * @param list 54 | * @return 55 | */ 56 | private NavigableMap reduce(List list) { 57 | 58 | NavigableMap reducedMap = new ConcurrentSkipListMap<>(); 59 | 60 | for (Result result : list) { 61 | /*遍历结果,如果在这个小的结果中已经存在相同的单词了,那么数量+1,否则新建*/ 62 | if (reducedMap.containsKey(result.getWord())) { 63 | Integer value = reducedMap.get(result.getWord()); 64 | value++; 65 | reducedMap.put(result.getWord(), value); 66 | } else { 67 | reducedMap.put(result.getWord(), 1); 68 | } 69 | } 70 | return reducedMap; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo2/server/actor/WCMapReduceActor.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo2.server.actor; 2 | 3 | import akka.actor.ActorRef; 4 | import akka.actor.UntypedActor; 5 | 6 | /** 7 | * @author SUN 8 | * @version 1.0 9 | * @Date 16/1/7 10:30 10 | */ 11 | public class WCMapReduceActor extends UntypedActor{ 12 | 13 | private ActorRef mapRouter; 14 | private ActorRef aggregateActor; 15 | 16 | @Override 17 | public void preStart() throws Exception { 18 | System.out.println("启动WCMapReduceActor:"+Thread.currentThread().getName()); 19 | } 20 | 21 | @Override 22 | public void onReceive(Object message) throws Exception { 23 | if (message instanceof String) { 24 | /*如果接收到的是显示结果的请求,那么就调用reduce的Actor*/ 25 | if (((String) message).compareTo("DISPLAY_LIST") == 0) { 26 | System.out.println("Got Display Message"); 27 | aggregateActor.tell(message, getSender()); 28 | }if (message.equals("EOF")){ 29 | //表示发送完毕 30 | aggregateActor.tell(true, getSender()); 31 | }else { 32 | /*否则给map的Actor进行计算*/ 33 | mapRouter.tell(message,null); 34 | } 35 | } 36 | } 37 | 38 | public WCMapReduceActor(ActorRef inAggregateActor, ActorRef inMapRouter) { 39 | mapRouter = inMapRouter; 40 | aggregateActor = inAggregateActor; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo2/server/model/Result.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo2.server.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author SUN 7 | * @version 1.0 8 | * @Date 16/1/7 10:33 9 | */ 10 | public class Result implements Serializable { 11 | 12 | /** 13 | * 14 | */ 15 | private static final long serialVersionUID = 5727560172917790458L; 16 | private String word; //单词 17 | private int no_of_instances; //数量 18 | 19 | public Result(String word, int no_of_instances) { 20 | this.setWord(word); 21 | this.setNoOfInstances(no_of_instances); 22 | } 23 | 24 | public void setWord(String word) { 25 | this.word = word; 26 | } 27 | 28 | public String getWord() { 29 | return word; 30 | } 31 | 32 | public void setNoOfInstances(int no_of_instances) { 33 | this.no_of_instances = no_of_instances; 34 | } 35 | 36 | public int getNoOfInstances() { 37 | return no_of_instances; 38 | } 39 | 40 | public String toString() { 41 | return word + ":" + no_of_instances; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo3/AkkaMain3.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo3; 2 | 3 | import akka.actor.ActorRef; 4 | import akka.actor.ActorSystem; 5 | import akka.actor.Props; 6 | import akka.routing.RoundRobinPool; 7 | import cn.sunxiang0918.akka.demo3.actor.JobControllerActor; 8 | import cn.sunxiang0918.akka.demo3.actor.WorkerActor; 9 | 10 | /** 11 | * @author SUN 12 | * @version 1.0 13 | * @Date 16/1/6 22:37 14 | */ 15 | public class AkkaMain3 { 16 | 17 | static final int no_of_msgs = 10000; 18 | 19 | final int no_of_workers = 10; 20 | 21 | final ActorRef router; 22 | 23 | public AkkaMain3() { 24 | final int no_of_workers = 10000; 25 | 26 | ActorSystem system = ActorSystem.create("LoadGeneratorApp"); 27 | 28 | final ActorRef appManager = system.actorOf(Props.create(JobControllerActor.class, no_of_msgs), "jobController");//启动jobController 29 | 30 | router = system.actorOf(Props.create(WorkerActor.class, appManager).withRouter(new RoundRobinPool(no_of_workers))); //启动带RoundRobinRouter的workerActor 31 | 32 | } 33 | 34 | public static void main(String[] args) throws Exception { 35 | new AkkaMain3().generateLoad(); 36 | } 37 | 38 | private void generateLoad() {//开始产生1000万消息 39 | for (int i = no_of_msgs; i >= 0; i--) { 40 | router.tell("Job Id " + i + "# send", ActorRef.noSender()); 41 | } 42 | System.out.println("All jobs sent successfully"); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo3/actor/JobControllerActor.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo3.actor; 2 | 3 | import akka.actor.UntypedActor; 4 | 5 | /** 6 | * @author SUN 7 | * @version 1.0 8 | * @Date 16/1/6 22:33 9 | */ 10 | public class JobControllerActor extends UntypedActor{ 11 | 12 | int count = 0; 13 | long startedTime = System.currentTimeMillis(); 14 | int no_of_msgs = 0; 15 | 16 | public JobControllerActor(int no_of_msgs) { 17 | this.no_of_msgs = no_of_msgs; 18 | } 19 | 20 | @Override 21 | public void onReceive(Object message) throws Exception { 22 | if (message instanceof String){ 23 | if (message.equals("DONE")){ 24 | count++; 25 | if (count == no_of_msgs) {//计数到达1000万结束,统计时间 26 | long now = System.currentTimeMillis(); 27 | System.out.println("All messages processed in " 28 | + (now - startedTime)+" millionseconds"); 29 | 30 | System.out.println("Total Number of messages processed " 31 | + count); 32 | getContext().system().shutdown(); 33 | } 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo3/actor/WorkerActor.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo3.actor; 2 | 3 | import org.apache.http.HttpResponse; 4 | import org.apache.http.client.methods.HttpPost; 5 | import org.apache.http.impl.client.DefaultHttpClient; 6 | 7 | import akka.actor.ActorRef; 8 | import akka.actor.UntypedActor; 9 | 10 | /** 11 | * @author SUN 12 | * @version 1.0 13 | * @Date 16/1/6 22:35 14 | */ 15 | public class WorkerActor extends UntypedActor { 16 | 17 | private ActorRef jobController;//jobController是接受者 18 | 19 | @Override //接受到generateLoad的发送消息 20 | public void onReceive(Object message) throws Exception { 21 | // using scheduler to send the reply after 1000 milliseconds 22 | // getContext() 23 | // .system() 24 | // .scheduler() 25 | // .scheduleOnce(Duration.create(1000, TimeUnit.MILLISECONDS),jobController,"DONE",getContext() 26 | // .system().dispatcher(),ActorRef.noSender()); 27 | 28 | //http://172.16.131.36:8081/api/media/task/media/info 29 | 30 | // System.out.println(Thread.currentThread().getName()); 31 | 32 | DefaultHttpClient httpclient = new DefaultHttpClient(); 33 | 34 | // 目标地址 35 | HttpPost httppost = new HttpPost( 36 | "http://172.16.131.36:8081/api/media/task/media/info"); 37 | 38 | HttpResponse response = httpclient.execute(httppost); 39 | 40 | // System.out.println(response.getStatusLine().getStatusCode()); 41 | 42 | httpclient.close(); 43 | 44 | jobController.tell("DONE",ActorRef.noSender()); 45 | 46 | } 47 | 48 | public WorkerActor(ActorRef inJobController) { 49 | jobController = inJobController; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo4/AkkaMain4.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo4; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | import akka.actor.ActorSystem; 8 | import akka.actor.Props; 9 | import akka.dispatch.Futures; 10 | import akka.dispatch.Mapper; 11 | import akka.util.Timeout; 12 | import cn.sunxiang0918.akka.demo4.actor.ReceiveActor; 13 | import cn.sunxiang0918.akka.demo4.actor.ResultActor; 14 | import cn.sunxiang0918.akka.demo4.model.Result; 15 | import scala.concurrent.Future; 16 | import scala.concurrent.duration.Duration; 17 | 18 | import static akka.pattern.Patterns.ask; 19 | import static akka.pattern.Patterns.pipe; 20 | 21 | /** 22 | * @author SUN 23 | * @version 1.0 24 | * @Date 16/1/7 20:26 25 | */ 26 | public class AkkaMain4 { 27 | 28 | public static void main(String[] args) throws Exception { 29 | final ActorSystem system = ActorSystem.create("demo4"); 30 | 31 | //超时时间 32 | final Timeout t = new Timeout(Duration.create(5, TimeUnit.SECONDS)); 33 | 34 | //异步反馈futures 35 | final ArrayList> futures = new ArrayList<>(); 36 | 37 | futures.add(ask(system.actorOf(Props.create(ReceiveActor.class)), "request", 1000)); // using 1000ms timeout 38 | futures.add(ask(system.actorOf(Props.create(ReceiveActor.class)), "another request", t)); // using timeout from 39 | 40 | /*定义结果聚合管道*/ 41 | final Future> aggregate = Futures.sequence(futures, 42 | system.dispatcher()); 43 | 44 | /*对聚合的结果做map操作.*/ 45 | final Future transformed = aggregate.map( 46 | new Mapper, Result>() { 47 | public Result apply(Iterable coll) { 48 | /*这里面就是所有的ask的结果.这里明确的晓得是两次,所以就调用两次next*/ 49 | final Iterator it = coll.iterator(); 50 | final String x = (String) it.next(); 51 | final String s = (String) it.next(); 52 | return new Result(x, s); 53 | } 54 | }, system.dispatcher()); 55 | 56 | pipe(transformed, system.dispatcher()).to(system.actorOf(Props.create(ResultActor.class))); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo4/actor/ReceiveActor.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo4.actor; 2 | 3 | import java.util.UUID; 4 | 5 | import akka.actor.UntypedActor; 6 | 7 | /** 8 | * @author SUN 9 | * @version 1.0 10 | * @Date 16/1/7 20:27 11 | */ 12 | public class ReceiveActor extends UntypedActor { 13 | 14 | @Override 15 | public void onReceive(Object message) throws Exception { 16 | System.out.println("接收到消息:"+message); 17 | String content = Thread.currentThread().getName()+":"+ UUID.randomUUID().toString(); 18 | //返回结果 19 | getSender().tell(content,null); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo4/actor/ResultActor.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo4.actor; 2 | 3 | import akka.actor.UntypedActor; 4 | 5 | /** 6 | * @author SUN 7 | * @version 1.0 8 | * @Date 16/1/7 20:34 9 | */ 10 | public class ResultActor extends UntypedActor{ 11 | 12 | @Override 13 | public void onReceive(Object message) throws Exception { 14 | System.out.println("接收到消息:"+message); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo4/model/Result.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo4.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author SUN 7 | * @version 1.0 8 | * @Date 16/1/7 10:33 9 | */ 10 | public class Result implements Serializable { 11 | 12 | private String word; //单词 13 | private String name; //数量 14 | 15 | public Result(String word, String name) { 16 | this.name = name; 17 | this.word = word; 18 | } 19 | 20 | public String getWord() { 21 | return word; 22 | } 23 | 24 | public void setWord(String word) { 25 | this.word = word; 26 | } 27 | 28 | public String getName() { 29 | return name; 30 | } 31 | 32 | public void setName(String name) { 33 | this.name = name; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "Result{" + 39 | "word='" + word + '\'' + 40 | ", name='" + name + '\'' + 41 | '}'; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo5/AkkaMain5.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo5; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import akka.actor.ActorRef; 6 | import akka.actor.ActorSystem; 7 | import akka.actor.Props; 8 | import cn.sunxiang0918.akka.demo5.actor.WriterActor; 9 | import com.typesafe.config.ConfigFactory; 10 | import scala.concurrent.duration.Duration; 11 | 12 | /** 13 | * @author SUN 14 | * @version 1.0 15 | * @Date 16/1/6 21:39 16 | */ 17 | public class AkkaMain5 { 18 | 19 | public static void main(String[] args) throws Exception { 20 | 21 | final ActorSystem system = ActorSystem.create("demo5", ConfigFactory.load("demo5") 22 | .getConfig("demo5")); 23 | 24 | // // 创建一个到greeter Actor的管道 25 | // final ActorRef controlActor = system.actorOf(Props.create(ControlActor.class), "control"); 26 | // 27 | // controlActor.tell(new StartCommand(100),ActorRef.noSender()); 28 | 29 | ActorRef actorRef = system.actorOf(Props.create(WriterActor.class)); 30 | 31 | system.scheduler().scheduleOnce(Duration.create(5, TimeUnit.SECONDS),actorRef,"1111",system.dispatcher(),ActorRef.noSender()); 32 | 33 | // Cancellable cancellable = system.scheduler().schedule(Duration.Zero(),Duration.create(1, TimeUnit.SECONDS),actorRef,"1111",system.dispatcher(),ActorRef.noSender()); 34 | 35 | Thread.sleep(10000); 36 | // cancellable.cancel(); 37 | //system.shutdown(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo5/actor/ControlActor.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo5.actor; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import akka.actor.ActorRef; 7 | import akka.actor.Props; 8 | import akka.actor.UntypedActor; 9 | import akka.routing.RoundRobinPool; 10 | import cn.sunxiang0918.akka.demo5.model.StartCommand; 11 | 12 | /** 13 | * @author SUN 14 | * @version 1.0 15 | * @Date 16/1/26 14:31 16 | */ 17 | public class ControlActor extends UntypedActor { 18 | 19 | @Override 20 | public void onReceive(Object message) throws Exception { 21 | if (message instanceof StartCommand) { 22 | 23 | // List actors = createActors(((StartCommand) message).getActorCount()); 24 | // 25 | // Router router = new Router(new RoundRobinRoutingLogic()); 26 | // 27 | // for (ActorRef actor : actors) { 28 | // router = router.addRoutee(actor); 29 | // } 30 | // 31 | // router.route("Insert",ActorRef.noSender()); 32 | 33 | // 34 | // /*这里使用了JDK1.8中的StreamAPI*/ 35 | // actors.stream().parallel().forEach(actorRef -> actorRef.tell("Insert", ActorRef.noSender())); 36 | 37 | /*使用Router方式启动100个Actor*/ 38 | Props props = Props.create(WriterActor.class).withRouter(new RoundRobinPool(((StartCommand) message).getActorCount())).withDispatcher("writer-dispatcher"); 39 | ActorRef actorRef = getContext().actorOf(props); 40 | // for (int i = 0; i < 100; i++) { 41 | actorRef.tell("Insert",ActorRef.noSender()); 42 | // } 43 | } 44 | } 45 | 46 | private List createActors(int actorCount) { 47 | Props props = Props.create(WriterActor.class).withDispatcher("writer-dispatcher"); 48 | 49 | List actors = new ArrayList<>(actorCount); 50 | for (int i = 0; i < actorCount; i++) { 51 | actors.add(getContext().actorOf(props,"writer_"+ i)); 52 | } 53 | return actors; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo5/actor/VoteCountRouter.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo5.actor; 2 | 3 | import akka.actor.ActorSystem; 4 | import akka.routing.CustomRouterConfig; 5 | import akka.routing.Router; 6 | 7 | /** 8 | * @author SUN 9 | * @version 1.0 10 | * @Date 16/1/27 10:30 11 | */ 12 | public class VoteCountRouter extends CustomRouterConfig{ 13 | 14 | @Override 15 | public Router createRouter(ActorSystem system) { 16 | return null; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo5/actor/WriterActor.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo5.actor; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | import akka.actor.UntypedActor; 6 | 7 | /** 8 | * @author SUN 9 | * @version 1.0 10 | * @Date 16/1/26 14:30 11 | */ 12 | public class WriterActor extends UntypedActor { 13 | 14 | private static AtomicInteger a = new AtomicInteger(0); 15 | 16 | @Override 17 | public void preStart() throws Exception { 18 | System.out.println("启动一个新的Actor:"+a.getAndIncrement()); 19 | } 20 | 21 | @Override 22 | public void onReceive(Object message) throws Exception { 23 | System.out.println(getSelf().path()+" "+Thread.currentThread().getName()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo5/model/ControlCommand.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo5.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author SUN 7 | * @version 1.0 8 | * @Date 16/1/26 14:33 9 | */ 10 | public class ControlCommand implements Serializable { 11 | 12 | private String message; 13 | 14 | private Long startTime; 15 | 16 | public ControlCommand(String message, Long startTime) { 17 | this.message = message; 18 | this.startTime = startTime; 19 | } 20 | 21 | public ControlCommand() { 22 | } 23 | 24 | public String getMessage() { 25 | return message; 26 | } 27 | 28 | public void setMessage(String message) { 29 | this.message = message; 30 | } 31 | 32 | public Long getStartTime() { 33 | return startTime; 34 | } 35 | 36 | public void setStartTime(Long startTime) { 37 | this.startTime = startTime; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo5/model/ExecutionResult.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo5.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author SUN 7 | * @version 1.0 8 | * @Date 16/1/26 14:32 9 | */ 10 | public class ExecutionResult implements Serializable { 11 | 12 | private long costTime; 13 | 14 | public ExecutionResult() { 15 | } 16 | 17 | public ExecutionResult(long costTime) { 18 | this.costTime = costTime; 19 | } 20 | 21 | public long getCostTime() { 22 | return costTime; 23 | } 24 | 25 | public void setCostTime(long costTime) { 26 | this.costTime = costTime; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo5/model/InsertCommand.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo5.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author SUN 7 | * @version 1.0 8 | * @Date 16/1/26 14:34 9 | */ 10 | public class InsertCommand implements Serializable { 11 | 12 | private int recordCount; 13 | 14 | public InsertCommand() { 15 | } 16 | 17 | public InsertCommand(int recordCount) { 18 | this.recordCount = recordCount; 19 | } 20 | 21 | public int getRecordCount() { 22 | return recordCount; 23 | } 24 | 25 | public void setRecordCount(int recordCount) { 26 | this.recordCount = recordCount; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo5/model/StartCommand.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo5.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author SUN 7 | * @version 1.0 8 | * @Date 16/1/26 14:31 9 | */ 10 | public class StartCommand implements Serializable { 11 | 12 | private int actorCount =0; 13 | 14 | public StartCommand() { 15 | } 16 | 17 | public StartCommand(int actorCount) { 18 | this.actorCount = actorCount; 19 | } 20 | 21 | public int getActorCount() { 22 | return actorCount; 23 | } 24 | 25 | public void setActorCount(int actorCount) { 26 | this.actorCount = actorCount; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo6/SimpleClusterApp.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo6; 2 | 3 | import akka.actor.ActorSystem; 4 | import akka.actor.Props; 5 | import com.typesafe.config.Config; 6 | import com.typesafe.config.ConfigFactory; 7 | 8 | public class SimpleClusterApp { 9 | 10 | public static void main(String[] args) { 11 | if (args.length == 0) 12 | /*启动三个节点*/ 13 | startup(new String[]{"2551", "2552", "0"}); 14 | else 15 | startup(args); 16 | } 17 | 18 | public static void startup(String[] ports) { 19 | for (String port : ports) { 20 | // 重写配置中的远程端口 21 | Config config = ConfigFactory.parseString( 22 | "akka.remote.netty.tcp.port=" + port).withFallback( 23 | ConfigFactory.load("demo6")); 24 | 25 | // 创建ActorSystem,名称需要和conf配置文件中的相同 26 | ActorSystem system = ActorSystem.create("ClusterSystem", config); 27 | 28 | // 创建集群中的Actor,并监听事件 29 | system.actorOf(Props.create(SimpleClusterListener.class), 30 | "clusterListener"); 31 | 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo6/SimpleClusterListener.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo6; 2 | 3 | import akka.actor.UntypedActor; 4 | import akka.cluster.Cluster; 5 | import akka.cluster.ClusterEvent; 6 | import akka.cluster.ClusterEvent.MemberEvent; 7 | import akka.cluster.ClusterEvent.MemberRemoved; 8 | import akka.cluster.ClusterEvent.MemberUp; 9 | import akka.cluster.ClusterEvent.UnreachableMember; 10 | import akka.event.Logging; 11 | import akka.event.LoggingAdapter; 12 | 13 | public class SimpleClusterListener extends UntypedActor { 14 | /*记录日志*/ 15 | LoggingAdapter log = Logging.getLogger(getContext().system(), this); 16 | 17 | /*创建,获取集群*/ 18 | Cluster cluster = Cluster.get(getContext().system()); 19 | 20 | //订阅集群中的事件 21 | @Override 22 | public void preStart() { 23 | //region subscribe 24 | cluster.subscribe(getSelf(), ClusterEvent.initialStateAsEvents(), 25 | MemberEvent.class, UnreachableMember.class); 26 | //endregion 27 | } 28 | 29 | //re-subscribe when restart 30 | @Override 31 | public void postStop() { 32 | cluster.unsubscribe(getSelf()); 33 | } 34 | 35 | @Override 36 | public void onReceive(Object message) { 37 | /*当接收到不同的事件的时候,打印出不同的信息*/ 38 | if (message instanceof MemberUp) { 39 | MemberUp mUp = (MemberUp) message; 40 | log.info("Member is Up: {}", mUp.member()); 41 | 42 | } else if (message instanceof UnreachableMember) { 43 | UnreachableMember mUnreachable = (UnreachableMember) message; 44 | log.info("Member detected as unreachable: {}", mUnreachable.member()); 45 | 46 | } else if (message instanceof MemberRemoved) { 47 | MemberRemoved mRemoved = (MemberRemoved) message; 48 | log.info("Member is Removed: {}", mRemoved.member()); 49 | 50 | } else if (message instanceof MemberEvent) { 51 | // ignore 52 | log.info("Member Event: {}", ((MemberEvent) message).member()); 53 | } else { 54 | unhandled(message); 55 | } 56 | 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo6/SimpleClusterListener2.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo6; 2 | 3 | import akka.actor.UntypedActor; 4 | import akka.cluster.Cluster; 5 | import akka.cluster.ClusterEvent.CurrentClusterState; 6 | import akka.cluster.ClusterEvent.MemberEvent; 7 | import akka.cluster.ClusterEvent.MemberUp; 8 | import akka.cluster.ClusterEvent.MemberRemoved; 9 | import akka.cluster.ClusterEvent.UnreachableMember; 10 | import akka.event.Logging; 11 | import akka.event.LoggingAdapter; 12 | 13 | public class SimpleClusterListener2 extends UntypedActor { 14 | LoggingAdapter log = Logging.getLogger(getContext().system(), this); 15 | Cluster cluster = Cluster.get(getContext().system()); 16 | 17 | //subscribe to cluster changes 18 | @Override 19 | public void preStart() { 20 | //#subscribe 21 | cluster.subscribe(getSelf(), MemberEvent.class, UnreachableMember.class); 22 | //#subscribe 23 | } 24 | 25 | //re-subscribe when restart 26 | @Override 27 | public void postStop() { 28 | cluster.unsubscribe(getSelf()); 29 | } 30 | 31 | @Override 32 | public void onReceive(Object message) { 33 | if (message instanceof CurrentClusterState) { 34 | CurrentClusterState state = (CurrentClusterState) message; 35 | log.info("Current members: {}", state.members()); 36 | 37 | } else if (message instanceof MemberUp) { 38 | MemberUp mUp = (MemberUp) message; 39 | log.info("Member is Up: {}", mUp.member()); 40 | 41 | } else if (message instanceof UnreachableMember) { 42 | UnreachableMember mUnreachable = (UnreachableMember) message; 43 | log.info("Member detected as unreachable: {}", mUnreachable.member()); 44 | 45 | } else if (message instanceof MemberRemoved) { 46 | MemberRemoved mRemoved = (MemberRemoved) message; 47 | log.info("Member is Removed: {}", mRemoved.member()); 48 | 49 | } else if (message instanceof MemberEvent) { 50 | // ignore 51 | 52 | } else { 53 | unhandled(message); 54 | } 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo7/FactorialApp.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo7; 2 | 3 | public class FactorialApp { 4 | 5 | public static void main(String[] args) { 6 | // starting 3 backend nodes and 1 frontend node 7 | FactorialBackendMain.main(new String[] { "2551" }); 8 | FactorialBackendMain.main(new String[] { "2552" }); 9 | FactorialBackendMain.main(new String[0]); 10 | FactorialFrontendMain.main(new String[0]); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo7/FactorialBackend.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo7; 2 | 3 | import java.math.BigInteger; 4 | 5 | import akka.actor.UntypedActor; 6 | import akka.dispatch.Mapper; 7 | import scala.concurrent.Future; 8 | 9 | import static akka.dispatch.Futures.future; 10 | import static akka.pattern.Patterns.pipe; 11 | 12 | //#backend 13 | public class FactorialBackend extends UntypedActor { 14 | 15 | @Override 16 | public void onReceive(Object message) { 17 | //如果是数字 18 | if (message instanceof Integer) { 19 | final Integer n = (Integer) message; 20 | /*使用akka的future功能,异步的计算阶乘*/ 21 | Future f = future(() -> factorial(n), getContext().dispatcher()); 22 | 23 | /*合并计算的结果*/ 24 | Future result = f.map( 25 | new Mapper() { 26 | public FactorialResult apply(BigInteger factorial) { 27 | return new FactorialResult(n, factorial); 28 | } 29 | }, getContext().dispatcher()); 30 | 31 | /*把结果返回Sender*/ 32 | pipe(result, getContext().dispatcher()).to(getSender()); 33 | } else { 34 | unhandled(message); 35 | } 36 | } 37 | 38 | /** 39 | * 进行阶乘计算 40 | * @param n 41 | * @return 42 | */ 43 | BigInteger factorial(int n) { 44 | BigInteger acc = BigInteger.ONE; 45 | for (int i = 1; i <= n; ++i) { 46 | acc = acc.multiply(BigInteger.valueOf(i)); 47 | } 48 | return acc; 49 | } 50 | } 51 | //#backend 52 | 53 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo7/FactorialBackendMain.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo7; 2 | 3 | import com.typesafe.config.Config; 4 | import com.typesafe.config.ConfigFactory; 5 | import akka.actor.ActorSystem; 6 | import akka.actor.Props; 7 | 8 | public class FactorialBackendMain { 9 | 10 | public static void main(String[] args) { 11 | // 重写配置文件中的集群角色和端口 12 | final String port = args.length > 0 ? args[0] : "0"; 13 | final Config config = ConfigFactory.parseString("akka.remote.netty.tcp.port=" + port). 14 | withFallback(ConfigFactory.parseString("akka.cluster.roles = [backend]")). 15 | withFallback(ConfigFactory.load("demo7")); 16 | 17 | ActorSystem system = ActorSystem.create("ClusterSystem", config); 18 | 19 | system.actorOf(Props.create(FactorialBackend.class), "factorialBackend"); 20 | 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo7/FactorialFrontend.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo7; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import akka.actor.ActorRef; 6 | import akka.actor.ReceiveTimeout; 7 | import akka.actor.UntypedActor; 8 | import akka.event.Logging; 9 | import akka.event.LoggingAdapter; 10 | import akka.routing.FromConfig; 11 | import scala.concurrent.duration.Duration; 12 | 13 | //#frontend 14 | public class FactorialFrontend extends UntypedActor { 15 | final int upToN; //计算到多少 16 | final boolean repeat; //是否重复计算 17 | 18 | LoggingAdapter log = Logging.getLogger(getContext().system(), this); 19 | 20 | /*获取到Backend的Router*/ 21 | ActorRef backend = getContext().actorOf(FromConfig.getInstance().props(), 22 | "factorialBackendRouter"); 23 | 24 | public FactorialFrontend(int upToN, boolean repeat) { 25 | this.upToN = upToN; 26 | this.repeat = repeat; 27 | } 28 | 29 | @Override 30 | public void preStart() { 31 | //因为是在Start前就发送消息,所以必定超时. 32 | sendJobs(); 33 | getContext().setReceiveTimeout(Duration.create(10, TimeUnit.SECONDS)); 34 | } 35 | 36 | @Override 37 | public void onReceive(Object message) { 38 | if (message instanceof FactorialResult) { 39 | FactorialResult result = (FactorialResult) message; 40 | if (result.n == upToN) { 41 | System.out.println("计算的结果:" + result); 42 | if (repeat) 43 | sendJobs(); 44 | else 45 | getContext().stop(getSelf()); 46 | } 47 | 48 | } else if (message instanceof ReceiveTimeout) { 49 | log.info("Timeout"); 50 | sendJobs(); 51 | 52 | } else { 53 | unhandled(message); 54 | } 55 | } 56 | 57 | void sendJobs() { 58 | log.info("Starting batch of factorials up to [{}]", upToN); 59 | for (int n = 1; n <= upToN; n++) { 60 | backend.tell(n, getSelf()); 61 | } 62 | } 63 | 64 | } 65 | 66 | //#frontend 67 | 68 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo7/FactorialFrontendMain.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo7; 2 | 3 | import com.typesafe.config.Config; 4 | import com.typesafe.config.ConfigFactory; 5 | import akka.actor.ActorSystem; 6 | import akka.actor.Props; 7 | import akka.cluster.Cluster; 8 | 9 | public class FactorialFrontendMain { 10 | 11 | public static void main(String[] args) { 12 | final int upToN = 10; 13 | 14 | final Config config = ConfigFactory.parseString( 15 | "akka.cluster.roles = [frontend]").withFallback( 16 | ConfigFactory.load("demo7")); 17 | 18 | final ActorSystem system = ActorSystem.create("ClusterSystem", config); 19 | system.log().info( 20 | "Factorials will start when 2 backend members in the cluster."); 21 | //#registerOnUp 22 | Cluster.get(system).registerOnMemberUp((Runnable) () -> system.actorOf(Props.create(FactorialFrontend.class, upToN, false), 23 | "factorialFrontend")); 24 | //#registerOnUp 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo7/FactorialResult.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo7; 2 | 3 | import java.io.Serializable; 4 | import java.math.BigInteger; 5 | 6 | public class FactorialResult implements Serializable { 7 | public final int n; 8 | public final BigInteger factorial; 9 | 10 | FactorialResult(int n, BigInteger factorial) { 11 | this.n = n; 12 | this.factorial = factorial; 13 | } 14 | 15 | @Override 16 | public String toString() { 17 | return "FactorialResult{" + 18 | "n=" + n + 19 | ", factorial=" + factorial + 20 | '}'; 21 | } 22 | } -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo7/MetricsListener.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo7; 2 | 3 | //#metrics-listener 4 | import akka.actor.UntypedActor; 5 | import akka.cluster.Cluster; 6 | import akka.cluster.ClusterEvent.ClusterMetricsChanged; 7 | import akka.cluster.ClusterEvent.CurrentClusterState; 8 | import akka.cluster.NodeMetrics; 9 | import akka.cluster.StandardMetrics; 10 | import akka.cluster.StandardMetrics.HeapMemory; 11 | import akka.cluster.StandardMetrics.Cpu; 12 | import akka.event.Logging; 13 | import akka.event.LoggingAdapter; 14 | 15 | public class MetricsListener extends UntypedActor { 16 | LoggingAdapter log = Logging.getLogger(getContext().system(), this); 17 | 18 | Cluster cluster = Cluster.get(getContext().system()); 19 | 20 | //subscribe to ClusterMetricsChanged 21 | @Override 22 | public void preStart() { 23 | cluster.subscribe(getSelf(), ClusterMetricsChanged.class); 24 | } 25 | 26 | //re-subscribe when restart 27 | @Override 28 | public void postStop() { 29 | cluster.unsubscribe(getSelf()); 30 | } 31 | 32 | 33 | @Override 34 | public void onReceive(Object message) { 35 | if (message instanceof ClusterMetricsChanged) { 36 | ClusterMetricsChanged clusterMetrics = (ClusterMetricsChanged) message; 37 | for (NodeMetrics nodeMetrics : clusterMetrics.getNodeMetrics()) { 38 | if (nodeMetrics.address().equals(cluster.selfAddress())) { 39 | logHeap(nodeMetrics); 40 | logCpu(nodeMetrics); 41 | } 42 | } 43 | 44 | } else if (message instanceof CurrentClusterState) { 45 | // ignore 46 | 47 | } else { 48 | unhandled(message); 49 | } 50 | } 51 | 52 | void logHeap(NodeMetrics nodeMetrics) { 53 | HeapMemory heap = StandardMetrics.extractHeapMemory(nodeMetrics); 54 | if (heap != null) { 55 | log.info("Used heap: {} MB", ((double) heap.used()) / 1024 / 1024); 56 | } 57 | } 58 | 59 | void logCpu(NodeMetrics nodeMetrics) { 60 | Cpu cpu = StandardMetrics.extractCpu(nodeMetrics); 61 | if (cpu != null && cpu.systemLoadAverage().isDefined()) { 62 | log.info("Load: {} ({} processors)", cpu.systemLoadAverage().get(), 63 | cpu.processors()); 64 | } 65 | } 66 | 67 | } 68 | //#metrics-listener -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo8/ClusterRoledWorker.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo8; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import akka.actor.ActorRef; 7 | import akka.actor.ActorSelection; 8 | import akka.actor.UntypedActor; 9 | import akka.cluster.Cluster; 10 | import akka.cluster.ClusterEvent; 11 | import akka.cluster.Member; 12 | import akka.event.Logging; 13 | import akka.event.LoggingAdapter; 14 | 15 | public abstract class ClusterRoledWorker extends UntypedActor{ 16 | 17 | /*记录日志*/ 18 | protected LoggingAdapter log = Logging.getLogger(getContext().system(), this); 19 | 20 | /*集群系统*/ 21 | protected Cluster cluster = Cluster.get(getContext().system()); 22 | 23 | // 用来缓存下游注册过来的子系统ActorRef 24 | protected List workers = new ArrayList<>(); 25 | 26 | @Override 27 | public void preStart() throws Exception { 28 | // 订阅集群事件 29 | cluster.subscribe(getSelf(), ClusterEvent.initialStateAsEvents(), ClusterEvent.MemberUp.class,ClusterEvent.MemberEvent.class, ClusterEvent.UnreachableMember.class); 30 | } 31 | 32 | @Override 33 | public void postStop() throws Exception { 34 | // 取消事件监听 35 | cluster.unsubscribe(getSelf()); 36 | } 37 | 38 | /** 39 | * 下游子系统节点发送注册消息 40 | */ 41 | 42 | protected void register(Member member,String actorPath) { 43 | ActorSelection actorSelection = getContext().actorSelection(actorPath); 44 | 45 | /*发送注册消息*/ 46 | actorSelection.tell(new EventMessages.Registration(),getSelf()); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo8/Demo8App.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo8; 2 | 3 | public class Demo8App { 4 | 5 | public static void main(String[] args) throws Exception { 6 | 7 | // 启动一个Client 8 | EventClient.main(new String[0]); 9 | 10 | // 启动两个Interceptor 11 | EventInterceptorMain.main(new String[] { "2851" }); 12 | EventInterceptorMain.main(new String[] { "2852" }); 13 | 14 | // 启动两个Processor 15 | EventProcessorMain.main(new String[]{"2951"}); 16 | EventProcessorMain.main(new String[]{"2952"}); 17 | EventProcessorMain.main(new String[]{"2953"}); 18 | EventProcessorMain.main(new String[]{"2954"}); 19 | EventProcessorMain.main(new String[]{"2955"}); 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo8/EventClient.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo8; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.concurrent.Executors; 9 | import java.util.concurrent.ScheduledExecutorService; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | import akka.actor.ActorRef; 13 | import akka.actor.ActorSystem; 14 | import akka.actor.Props; 15 | import com.typesafe.config.Config; 16 | import com.typesafe.config.ConfigFactory; 17 | 18 | public class EventClient { 19 | 20 | /*假的Nginx的日志,Key是Nginx的端口,Value是日志内容,一行一个*/ 21 | private static Map> events=new HashMap<>(); 22 | 23 | static { 24 | /*构造假的日志内容*/ 25 | events.put(2751,new ArrayList<>()); 26 | events.put(2752,new ArrayList<>()); 27 | events.put(2753,new ArrayList<>()); 28 | 29 | events.get(2751).add("\"\"10.10.2.72 [21/Aug/2015:18:29:19 +0800] \"GET /t.gif?installid=0000lAOX&udid=25371384b2eb1a5dc5643e14626ecbd4&sessionid=25371384b2eb1a5dc5643e14626ecbd41440152875362&imsi=460002830862833&operator=1&network=1×tamp=1440152954&action=14&eventcode=300039&page=200002& HTTP/1.0\" \"-\" 204 0 \"-\" \"Dalvik/1.6.0 (Linux; U; Android 4.4.4; R8207 Build/KTU84P)\" \"121.25.190.146\"\"\""); 30 | events.get(2751).add("\"\"10.10.2.8 [21/Aug/2015:18:29:19 +0800] \"GET /t.gif?installid=0000VACO&udid=f6b0520cbc36fda6f63a72d91bf305c0&imsi=460012927613645&operator=2&network=1×tamp=1440152956&action=1840&eventcode=100003&type=1&result=0& HTTP/1.0\" \"-\" 204 0 \"-\" \"Dalvik/1.6.0 (Linux; U; Android 4.4.2; GT-I9500 Build/KOT49H)\" \"61.175.219.69\"\"\""); 31 | 32 | events.get(2752).add("\"\"10.10.2.72 [21/Aug/2015:18:29:19 +0800] \"GET /t.gif?installid=0000gCo4&udid=636d127f4936109a22347b239a0ce73f&sessionid=636d127f4936109a22347b239a0ce73f1440150695096&imsi=460036010038180&operator=3&network=4×tamp=1440152902&action=1566&eventcode=101010&playid=99d5a59f100cb778b64b5234a189e1f4&radioid=1100000048450&audioid=1000001535718&playtime=3& HTTP/1.0\" \"-\" 204 0 \"-\" \"Dalvik/1.6.0 (Linux; U; Android 4.4.4; R8205 Build/KTU84P)\" \"106.38.128.67\"\"\""); 33 | events.get(2752).add("\"\"10.10.2.72 [21/Aug/2015:18:29:19 +0800] \"GET /t.gif?installid=0000kPSC&udid=2ee585cde388ac57c0e81f9a76f5b797&operator=0&network=1×tamp=1440152968&action=6423&eventcode=100003&type=1&result=0& HTTP/1.0\" \"-\" 204 0 \"-\" \"Dalvik/v3.3.85 (Linux; U; Android L; P8 Build/KOT49H)\" \"202.103.133.112\"\"\""); 34 | events.get(2752).add("\"\"10.10.2.72 [21/Aug/2015:18:29:19 +0800] \"GET /t.gif?installid=0000lABW&udid=face1161d739abacca913dcb82576e9d&sessionid=face1161d739abacca913dcb82576e9d1440151582673&operator=0&network=1×tamp=1440152520&action=1911&eventcode=101010&playid=b07c241010f8691284c68186c42ab006&radioid=1100000000762&audioid=1000001751983&playtime=158& HTTP/1.0\" \"-\" 204 0 \"-\" \"Dalvik/1.6.0 (Linux; U; Android 4.1; H5 Build/JZO54K)\" \"221.232.36.250\"\"\""); 35 | 36 | 37 | events.get(2753).add("\"\"10.10.2.8 [21/Aug/2015:18:29:19 +0800] \"GET /t.gif?installid=0000krJw&udid=939488333889f18e2b406d2ece8f938a&sessionid=939488333889f18e2b406d2ece8f938a1440137301421&imsi=460028180045362&operator=1&network=1×tamp=1440152947&action=1431&eventcode=300030&playid=e1fd5467085475dc4483d2795f112717&radioid=1100000001123&audioid=1000000094911&playtime=951992& HTTP/1.0\" \"-\" 204 0 \"-\" \"Dalvik/1.6.0 (Linux; U; Android 4.0.4; R813T Build/IMM76D)\" \"5.45.64.205\"\"\""); 38 | events.get(2753).add("\"\"10.10.2.72 [21/Aug/2015:18:29:19 +0800] \"GET /t.gif?installid=0000kcpz&udid=cbc7bbb560914c374cb7a29eef8c2144&sessionid=cbc7bbb560914c374cb7a29eef8c21441440152816008&imsi=460008782944219&operator=1&network=1×tamp=1440152873&action=360&eventcode=200003&page=200003&radioid=1100000046018& HTTP/1.0\" \"-\" 204 0 \"-\" \"Dalvik/v3.3.85 (Linux; U; Android 4.4.2; MX4S Build/KOT49H)\" \"119.128.106.232\"\"\""); 39 | events.get(2753).add("\"\"10.10.2.8 [21/Aug/2015:18:29:19 +0800] \"GET /t.gif?installid=0000juRL&udid=3f9a5ffa69a5cd5f0754d2ba98c0aeb2&imsi=460023744091238&operator=1&network=1×tamp=1440152957&action=78&eventcode=100003&type=1&result=0& HTTP/1.0\" \"-\" 204 0 \"-\" \"Dalvik/v3.3.85 (Linux; U; Android 4.4.3; S?MSUNG. Build/KOT49H)\" \"223.153.72.78\"\"\""); 40 | } 41 | 42 | private static List ports = Arrays.asList(2751,2752, 2753); 43 | 44 | private static Map actors = new HashMap<>(); 45 | 46 | public static void main(String[] args) throws Exception { 47 | 48 | /*根据端口号的多少,启动多少个Collector在集群中*/ 49 | ports.forEach(port -> { 50 | final Config config = ConfigFactory.parseString("akka.remote.netty.tcp.port=" + port). 51 | withFallback(ConfigFactory.parseString("akka.cluster.roles = [collector]")). 52 | withFallback(ConfigFactory.load("demo8")); 53 | final ActorSystem system = ActorSystem.create("event-cluster-system", config); 54 | 55 | ActorRef collectingActor = system.actorOf(Props.create(EventCollector.class), "collectingActor"); 56 | 57 | actors.put(port,collectingActor); 58 | }); 59 | 60 | Thread.sleep(10000); 61 | 62 | /*使用JDK中的scheduleAtFixedRate,每5秒发送一次日志给Collector*/ 63 | ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(); 64 | 65 | service.scheduleAtFixedRate(() -> { 66 | ports.forEach(port -> { 67 | events.get(port).forEach(line ->{ 68 | System.out.println("RAW: port=" + port + ", line=" + line); 69 | actors.get(port).tell(new EventMessages.RawNginxRecord("host.me:" + port, line),ActorRef.noSender()); 70 | } ); 71 | } ); 72 | },0,5, TimeUnit.SECONDS); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo8/EventCollector.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo8; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | import java.util.regex.Matcher; 5 | import java.util.regex.Pattern; 6 | 7 | import akka.actor.Terminated; 8 | import akka.cluster.ClusterEvent; 9 | 10 | public class EventCollector extends ClusterRoledWorker { 11 | 12 | private AtomicInteger recordCounter = new AtomicInteger(0); 13 | 14 | 15 | @Override 16 | public void onReceive(Object message) throws Exception { 17 | if (message instanceof ClusterEvent.MemberUp) { 18 | ClusterEvent.MemberUp member = (ClusterEvent.MemberUp) message; 19 | log.info("Member is Up: {}", member.member().address()); 20 | } else if (message instanceof ClusterEvent.UnreachableMember) { 21 | ClusterEvent.UnreachableMember mUnreachable = (ClusterEvent.UnreachableMember) message; 22 | log.info("Member detected as unreachable: {}", mUnreachable.member()); 23 | } else if (message instanceof ClusterEvent.MemberRemoved) { 24 | ClusterEvent.MemberRemoved mRemoved = (ClusterEvent.MemberRemoved) message; 25 | log.info("Member is Removed: {}", mRemoved.member()); 26 | } else if (message instanceof ClusterEvent.MemberEvent) { 27 | // ignore 28 | log.info("Member Event: {}", ((ClusterEvent.MemberEvent) message).member()); 29 | } else if (message instanceof EventMessages.Registration) { 30 | // watch发送注册消息的interceptor,如果对应的Actor终止了,会发送一个Terminated消息 31 | getContext().watch(getSender()); 32 | workers.add(getSender()); 33 | log.info("Interceptor registered: " + getSender()); 34 | log.info("Registered interceptors: " + workers.size()); 35 | } else if (message instanceof Terminated) { 36 | // interceptor终止,更新缓存的ActorRef 37 | Terminated terminated = (Terminated) message; 38 | workers.remove(terminated.actor()); 39 | } else if (message instanceof EventMessages.RawNginxRecord) { 40 | EventMessages.RawNginxRecord rawNginxRecord = (EventMessages.RawNginxRecord) message; 41 | String line = rawNginxRecord.getLine(); 42 | String sourceHost = rawNginxRecord.getSourceHost(); 43 | String eventCode = findEventCode(line); 44 | 45 | // 构造NginxRecord消息,发送到下游interceptor 46 | log.info("Raw message: eventCode=" + eventCode + ", sourceHost=" + sourceHost + ", line=" + line); 47 | int counter = recordCounter.incrementAndGet(); 48 | if (workers.size() > 0) { 49 | // 模拟Roudrobin方式,将日志记录消息发送给下游一组interceptor中的一个 50 | int interceptorIndex = (counter < 0 ? 0 : counter) % workers.size(); 51 | workers.get(interceptorIndex).tell(new EventMessages.NginxRecord(sourceHost, line, eventCode), getSelf()); 52 | log.info("Details: interceptorIndex=" + interceptorIndex + ", interceptors=" + workers.size()); 53 | } 54 | } 55 | } 56 | 57 | private String findEventCode(String line) { 58 | Pattern pattern = Pattern.compile("eventcode=(\\d+)"); 59 | Matcher matcher = pattern.matcher(line); 60 | if (matcher.find()) { 61 | return matcher.group(1); 62 | } 63 | return null; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo8/EventInterceptor.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo8; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.concurrent.atomic.AtomicInteger; 8 | import java.util.regex.Matcher; 9 | import java.util.regex.Pattern; 10 | 11 | import akka.actor.Terminated; 12 | import akka.cluster.ClusterEvent; 13 | import akka.cluster.Member; 14 | import akka.cluster.MemberStatus; 15 | 16 | public class EventInterceptor extends ClusterRoledWorker { 17 | 18 | private AtomicInteger interceptedRecords = new AtomicInteger(0); 19 | 20 | /*IP地址的正则表达式*/ 21 | private Pattern IP_PATTERN = Pattern.compile("[^\\s]+\\s+\\[([^\\]]+)\\].+\"(\\d+\\.\\d+\\.\\d+\\.\\d+)"); 22 | 23 | /*黑名单*/ 24 | private List blackIpList = Arrays.asList("5.9.116.101", "103.42.176.138", "123.182.148.65", "5.45.64.205", 25 | "27.159.226.192", "76.164.228.218", "77.79.178.186", "104.200.31.117", 26 | "104.200.31.32", "104.200.31.238", "123.182.129.108", "220.161.98.39", 27 | "59.58.152.90", "117.26.221.236", "59.58.150.110", "123.180.229.156", 28 | "59.60.123.239", "117.26.222.6", "117.26.220.88", "59.60.124.227", 29 | "142.54.161.50", "59.58.148.52", "59.58.150.85", "202.105.90.142"); 30 | 31 | @Override 32 | public void onReceive(Object message) throws Exception { 33 | if (message instanceof ClusterEvent.MemberUp){ 34 | ClusterEvent.MemberUp member = (ClusterEvent.MemberUp) message; 35 | log.info("Member is Up: {}", member.member().address()); 36 | 37 | register(member.member(), getCollectorPath(member.member())); 38 | }else if (message instanceof ClusterEvent.CurrentClusterState) { 39 | 40 | ClusterEvent.CurrentClusterState state = (ClusterEvent.CurrentClusterState) message; 41 | Iterable members = state.getMembers(); 42 | 43 | // 如果加入Akka集群的成员节点是Up状态,并且是collector角色,则调用register向collector进行注册 44 | members.forEach(o -> { 45 | if (o.status() == MemberStatus.up()){ 46 | register(o,getCollectorPath(o)); 47 | } 48 | }); 49 | } else if (message instanceof ClusterEvent.UnreachableMember) { 50 | ClusterEvent.UnreachableMember mUnreachable = (ClusterEvent.UnreachableMember) message; 51 | log.info("Member detected as unreachable: {}", mUnreachable.member()); 52 | } else if (message instanceof ClusterEvent.MemberRemoved) { 53 | ClusterEvent.MemberRemoved mRemoved = (ClusterEvent.MemberRemoved) message; 54 | log.info("Member is Removed: {}", mRemoved.member()); 55 | } else if (message instanceof ClusterEvent.MemberEvent) { 56 | // ignore 57 | log.info("Member Event: {}", ((ClusterEvent.MemberEvent) message).member()); 58 | } else if (message instanceof EventMessages.Registration) { 59 | // watch发送注册消息的interceptor,如果对应的Actor终止了,会发送一个Terminated消息 60 | getContext().watch(getSender()); 61 | workers.add(getSender()); 62 | log.info("Interceptor registered: " + getSender()); 63 | log.info("Registered interceptors: " + workers.size()); 64 | } else if (message instanceof Terminated) { 65 | // interceptor终止,更新缓存的ActorRef 66 | Terminated terminated = (Terminated) message; 67 | workers.remove(terminated.actor()); 68 | }else if (message instanceof EventMessages.NginxRecord) { 69 | EventMessages.NginxRecord nginxRecord = (EventMessages.NginxRecord) message; 70 | 71 | CheckRecord checkRecord = checkRecord(nginxRecord.getEventCode(), nginxRecord.getLine()); 72 | 73 | if (!checkRecord.isIpInBlackList){ 74 | int records = interceptedRecords.incrementAndGet(); 75 | 76 | if (workers.size()>0){ 77 | int processorIndex = (records<0?0:records) % workers.size(); 78 | workers.get(processorIndex).tell(new EventMessages.FilteredRecord(nginxRecord.getSourceHost(),nginxRecord.getLine(), nginxRecord.getEventCode() , checkRecord.data.get("eventdate"), checkRecord.data.get("realip")),getSelf()); 79 | log.info("Details: processorIndex=" + processorIndex + ", processors=" + workers.size()); 80 | } 81 | log.info("Intercepted data: data=" + checkRecord.data); 82 | }else { 83 | log.info("Discarded: " + nginxRecord.getLine()); 84 | } 85 | } 86 | } 87 | 88 | /** 89 | * 检查和解析每一行日志的记录 90 | * @param eventCode 91 | * @param line 92 | * @return 93 | */ 94 | private CheckRecord checkRecord(String eventCode,String line){ 95 | 96 | Map data = new HashMap<>(); 97 | boolean isIpInBlackList = false; 98 | 99 | Matcher matcher = IP_PATTERN.matcher(line); 100 | 101 | while (matcher.find()) { 102 | String rawDt = matcher.group(1); 103 | String realIp = matcher.group(2); 104 | 105 | data.put("eventdate", rawDt); 106 | data.put("realip", realIp); 107 | data.put("eventcode", eventCode); 108 | 109 | isIpInBlackList = blackIpList.contains(realIp); 110 | } 111 | 112 | return new CheckRecord(isIpInBlackList,data); 113 | } 114 | 115 | /** 116 | * 获取Collector的路径 117 | * @param member 118 | * @return 119 | */ 120 | private String getCollectorPath(Member member){ 121 | return member.address()+"/user/collectingActor"; 122 | } 123 | 124 | private class CheckRecord { 125 | private boolean isIpInBlackList; 126 | 127 | private Map data; 128 | 129 | public CheckRecord(boolean isIpInBlackList, Map data) { 130 | this.isIpInBlackList = isIpInBlackList; 131 | this.data = data; 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo8/EventInterceptorMain.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo8; 2 | 3 | import akka.actor.ActorRef; 4 | import akka.actor.ActorSystem; 5 | import akka.actor.Props; 6 | import com.typesafe.config.Config; 7 | import com.typesafe.config.ConfigFactory; 8 | 9 | public class EventInterceptorMain { 10 | 11 | public static void main(String[] args) throws Exception { 12 | 13 | final String port = args.length > 0 ? args[0] : "0"; 14 | 15 | /*修改配置文件中的端口和角色*/ 16 | final Config config = ConfigFactory.parseString("akka.remote.netty.tcp.port=" + port). 17 | withFallback(ConfigFactory.parseString("akka.cluster.roles = [interceptor]")). 18 | withFallback(ConfigFactory.load("demo8")); 19 | 20 | final ActorSystem system = ActorSystem.create("event-cluster-system", config); 21 | 22 | /*实例化EventInterceptor Actor*/ 23 | ActorRef interceptingActor = system.actorOf(Props.create(EventInterceptor.class), "interceptingActor"); 24 | 25 | system.log().info("Processing Actor: " + interceptingActor); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo8/EventMessages.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo8; 2 | 3 | import java.io.Serializable; 4 | 5 | //#messages 6 | public interface EventMessages { 7 | 8 | public static class EventMessage implements Serializable { 9 | 10 | } 11 | 12 | /** 13 | * 内存中的Nginx的日志 14 | */ 15 | public static class RawNginxRecord extends EventMessage { 16 | 17 | private String sourceHost; 18 | 19 | private String line; 20 | 21 | public RawNginxRecord(String sourceHost, String line) { 22 | this.sourceHost = sourceHost; 23 | this.line = line; 24 | } 25 | 26 | public String getLine() { 27 | return line; 28 | } 29 | 30 | public String getSourceHost() { 31 | return sourceHost; 32 | } 33 | } 34 | 35 | /** 36 | * 解析出了事件内容的Nginx记录 37 | */ 38 | public static class NginxRecord extends EventMessage { 39 | 40 | private String sourceHost; 41 | 42 | private String line; 43 | 44 | private String eventCode; 45 | 46 | public NginxRecord(String sourceHost, String line, String eventCode) { 47 | this.sourceHost = sourceHost; 48 | this.line = line; 49 | this.eventCode = eventCode; 50 | } 51 | 52 | public String getSourceHost() { 53 | return sourceHost; 54 | } 55 | 56 | public String getLine() { 57 | return line; 58 | } 59 | 60 | public String getEventCode() { 61 | return eventCode; 62 | } 63 | } 64 | 65 | /** 66 | * 通过了拦截器的日志记录 67 | */ 68 | public static class FilteredRecord extends EventMessage { 69 | 70 | private String sourceHost; 71 | 72 | private String line; 73 | 74 | private String eventCode; 75 | 76 | private String logDate; 77 | 78 | private String realIp; 79 | 80 | public FilteredRecord(String sourceHost, String line, String eventCode, String logDate, String realIp) { 81 | this.sourceHost = sourceHost; 82 | this.line = line; 83 | this.eventCode = eventCode; 84 | this.logDate = logDate; 85 | this.realIp = realIp; 86 | } 87 | 88 | public String getSourceHost() { 89 | return sourceHost; 90 | } 91 | 92 | public String getLine() { 93 | return line; 94 | } 95 | 96 | public String getEventCode() { 97 | return eventCode; 98 | } 99 | 100 | public String getLogDate() { 101 | return logDate; 102 | } 103 | 104 | public String getRealIp() { 105 | return realIp; 106 | } 107 | } 108 | 109 | /** 110 | * 子系统注册的消息 111 | */ 112 | public static final class Registration implements Serializable { 113 | } 114 | 115 | } 116 | //#messages -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo8/EventProcessor.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo8; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.regex.Matcher; 6 | import java.util.regex.Pattern; 7 | 8 | import akka.cluster.ClusterEvent; 9 | import akka.cluster.Member; 10 | import akka.cluster.MemberStatus; 11 | import cn.sunxiang0918.akka.demo8.kafka.KafkaTemplate; 12 | import com.alibaba.fastjson.JSON; 13 | 14 | public class EventProcessor extends ClusterRoledWorker { 15 | 16 | /*内容的正则表达式*/ 17 | private Pattern PATTERN = Pattern.compile("[\\?|&]([^=]+)=([^&]+)&"); 18 | 19 | /*kafka的连接工具*/ 20 | private KafkaTemplate kafkaTemplate = new KafkaTemplate("127.0.0.1:8092"); 21 | 22 | @Override 23 | public void onReceive(Object message) throws Exception { 24 | if (message instanceof ClusterEvent.MemberUp) { 25 | ClusterEvent.MemberUp member = (ClusterEvent.MemberUp) message; 26 | log.info("Member is Up: {}", member.member().address()); 27 | 28 | register(member.member(), getProcessorPath(member.member())); 29 | } else if (message instanceof ClusterEvent.CurrentClusterState) { 30 | 31 | ClusterEvent.CurrentClusterState state = (ClusterEvent.CurrentClusterState) message; 32 | Iterable members = state.getMembers(); 33 | 34 | // 如果加入Akka集群的成员节点是Up状态,并且是collector角色,则调用register向collector进行注册 35 | members.forEach(o -> { 36 | if (o.status() == MemberStatus.up()) { 37 | register(o, getProcessorPath(o)); 38 | } 39 | }); 40 | } else if (message instanceof ClusterEvent.UnreachableMember) { 41 | ClusterEvent.UnreachableMember mUnreachable = (ClusterEvent.UnreachableMember) message; 42 | log.info("Member detected as unreachable: {}", mUnreachable.member()); 43 | } else if (message instanceof ClusterEvent.MemberRemoved) { 44 | ClusterEvent.MemberRemoved mRemoved = (ClusterEvent.MemberRemoved) message; 45 | log.info("Member is Removed: {}", mRemoved.member()); 46 | } else if (message instanceof ClusterEvent.MemberEvent) { 47 | // ignore 48 | log.info("Member Event: {}", ((ClusterEvent.MemberEvent) message).member()); 49 | } else if (message instanceof EventMessages.FilteredRecord) { 50 | EventMessages.FilteredRecord filteredRecord = (EventMessages.FilteredRecord) message; 51 | /*处理每一行日志内容,转换成Map模型*/ 52 | Map data = process(filteredRecord.getEventCode(), filteredRecord.getLine(), filteredRecord.getLogDate(), filteredRecord.getRealIp()); 53 | 54 | log.info("Processed: data=" + data); 55 | 56 | // 将解析后的消息一JSON字符串的格式,保存到Kafka中 57 | kafkaTemplate.convertAndSend("app_events", JSON.toJSONString(data)); 58 | } 59 | } 60 | 61 | private Map process(String eventCode, String line, String logDate, String realIp) { 62 | 63 | Map data = new HashMap<>(); 64 | 65 | Matcher matcher = PATTERN.matcher(line); 66 | 67 | while (matcher.find()) { 68 | String key = matcher.group(1); 69 | String value = matcher.group(2); 70 | data.put(key,value); 71 | } 72 | 73 | data.put("eventdate", logDate); 74 | data.put("realip", realIp); 75 | 76 | return data; 77 | } 78 | 79 | private String getProcessorPath(Member member) { 80 | return member.address()+"/user/interceptingActor"; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo8/EventProcessorMain.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo8; 2 | 3 | import akka.actor.ActorRef; 4 | import akka.actor.ActorSystem; 5 | import akka.actor.Props; 6 | import com.typesafe.config.Config; 7 | import com.typesafe.config.ConfigFactory; 8 | 9 | public class EventProcessorMain { 10 | 11 | public static void main(String[] args) throws Exception { 12 | final String port = args.length > 0 ? args[0] : "0"; 13 | 14 | final Config config = ConfigFactory.parseString("akka.remote.netty.tcp.port=" + port). 15 | withFallback(ConfigFactory.parseString("akka.cluster.roles = [processor]")). 16 | withFallback(ConfigFactory.load("demo8")); 17 | 18 | final ActorSystem system = ActorSystem.create("event-cluster-system", config); 19 | 20 | ActorRef processingActor = system.actorOf(Props.create(EventProcessor.class), "processingActor"); 21 | 22 | system.log().info("Processing Actor: " + processingActor); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo8/kafka/KafkaTemplate.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo8.kafka; 2 | 3 | import java.io.Serializable; 4 | import java.util.Properties; 5 | 6 | import kafka.javaapi.producer.Producer; 7 | import kafka.producer.KeyedMessage; 8 | import kafka.producer.ProducerConfig; 9 | 10 | public class KafkaTemplate { 11 | 12 | private Producer producer; 13 | 14 | public KafkaTemplate(String urls) { 15 | Properties props = new Properties(); 16 | props.put("metadata.broker.list", urls); 17 | props.put("serializer.class", "cn.sunxiang0918.akka.demo8.kafka.ObjectEncoder"); 18 | props.put("request.required.acks", "1"); 19 | 20 | ProducerConfig config = new ProducerConfig(props); 21 | 22 | producer = new Producer<>(config); 23 | } 24 | 25 | public void convertAndSend(String destinationName, Object message) { 26 | assert message instanceof Serializable; 27 | KeyedMessage data = new KeyedMessage<>(destinationName, destinationName, (Serializable) message); 28 | producer.send(data); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo8/kafka/ObjectDecoder.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo8.kafka; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.IOException; 5 | import java.io.ObjectInputStream; 6 | import java.io.Serializable; 7 | 8 | import kafka.serializer.Decoder; 9 | import kafka.utils.VerifiableProperties; 10 | 11 | public class ObjectDecoder implements Decoder { 12 | 13 | public ObjectDecoder(){} 14 | 15 | public ObjectDecoder(VerifiableProperties props) { 16 | // this.encoding = props == null?"UTF8":props.getString("serializer.encoding", "UTF8"); 17 | } 18 | 19 | public Serializable fromBytes(byte[] bytes) { 20 | 21 | // return (Serializable) SerializationUtils.deserialize(bytes); 22 | 23 | if (bytes == null) { 24 | return null; 25 | } 26 | try { 27 | ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes)); 28 | return (Serializable) ois.readObject(); 29 | } 30 | catch (IOException ex) { 31 | throw new IllegalArgumentException("Failed to deserialize object", ex); 32 | } 33 | catch (ClassNotFoundException ex) { 34 | throw new IllegalStateException("Failed to deserialize object type", ex); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo8/kafka/ObjectEncoder.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo8.kafka; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.ObjectOutputStream; 6 | import java.io.Serializable; 7 | 8 | import kafka.serializer.Encoder; 9 | import kafka.utils.VerifiableProperties; 10 | 11 | public class ObjectEncoder implements Encoder { 12 | 13 | public ObjectEncoder(){} 14 | 15 | public ObjectEncoder(VerifiableProperties props) { 16 | // this.encoding = props == null?"UTF8":props.getString("serializer.encoding", "UTF8"); 17 | } 18 | 19 | public byte[] toBytes(Serializable object) { 20 | if (object == null) { 21 | return null; 22 | } 23 | ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); 24 | try { 25 | ObjectOutputStream oos = new ObjectOutputStream(baos); 26 | oos.writeObject(object); 27 | oos.flush(); 28 | } 29 | catch (IOException ex) { 30 | throw new IllegalArgumentException("Failed to serialize object of type: " + object.getClass(), ex); 31 | } 32 | return baos.toByteArray(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/cn/sunxiang0918/akka/demo9/FutureTest.java: -------------------------------------------------------------------------------- 1 | package cn.sunxiang0918.akka.demo9; 2 | 3 | import java.util.Random; 4 | 5 | import akka.actor.ActorSystem; 6 | import akka.dispatch.Futures; 7 | import akka.dispatch.OnComplete; 8 | import akka.dispatch.OnFailure; 9 | import akka.dispatch.OnSuccess; 10 | import scala.concurrent.Future; 11 | 12 | public class FutureTest { 13 | 14 | public static void main(String[] args) throws Exception { 15 | 16 | final ActorSystem system = ActorSystem.create("helloakka"); 17 | 18 | /*通过Futures的静态方法future创建一个Future类.入参就是一个异步的计算*/ 19 | Future f = Futures.future(() -> { 20 | Thread.sleep(10); 21 | if (new Random(System.currentTimeMillis()).nextBoolean()){ 22 | return "Hello"+"World!"; 23 | }else { 24 | throw new IllegalArgumentException("参数错误"); 25 | } 26 | },system.dispatcher()); 27 | 28 | f.andThen(new OnComplete() { 29 | @Override 30 | public void onComplete(Throwable failure, String success) throws Throwable { 31 | System.out.println("这里是andThen"); 32 | } 33 | },system.dispatcher()).andThen(new OnComplete() { 34 | @Override 35 | public void onComplete(Throwable failure, String success) throws Throwable { 36 | System.out.println("这里是andThen2"); 37 | } 38 | },system.dispatcher()); 39 | 40 | f.onSuccess(new PrintResult(),system.dispatcher()); 41 | f.onFailure(new FailureResult(),system.dispatcher()); 42 | 43 | System.out.println("这个地方是外面"); 44 | } 45 | 46 | public final static class PrintResult extends OnSuccess { 47 | @Override public final void onSuccess(T t) { 48 | System.out.println(t); 49 | } 50 | } 51 | 52 | public final static class FailureResult extends OnFailure { 53 | @Override 54 | public void onFailure(Throwable failure) throws Throwable { 55 | System.out.println("进入错误的处理"); 56 | failure.printStackTrace(); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/resources/application.conf: -------------------------------------------------------------------------------- 1 | WCMapReduceApp { 2 | include "common" 3 | akka { 4 | actor { 5 | provider = "akka.remote.RemoteActorRefProvider" 6 | } 7 | remote { 8 | enabled-transports = ["akka.remote.netty.tcp"] 9 | netty.tcp { 10 | hostname = "127.0.0.1" 11 | port = 2552 12 | } 13 | } 14 | } 15 | 16 | priorityMailBox-dispatcher { 17 | mailbox-type = "cn.sunxiang0918.akka.demo2.server.MyPriorityMailBox" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/client.conf: -------------------------------------------------------------------------------- 1 | WCMapReduceClientApp { 2 | include "common" 3 | akka { 4 | actor { 5 | provider = "akka.remote.RemoteActorRefProvider" 6 | } 7 | remote { 8 | enabled-transports = ["akka.remote.netty.tcp"] 9 | netty.tcp { 10 | hostname = "127.0.0.1" 11 | port = 2553 //0表示自动选择一个可用的 12 | } 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/resources/demo5.conf: -------------------------------------------------------------------------------- 1 | demo5 { 2 | writer-dispatcher { 3 | type = Dispatcher //Dispatcher类型,Dispatcher PinnedDispatcher 4 | executor = "fork-join-executor" //底层实现方式 fork-join-executor thread-pool-executor 5 | //执行器方式的参数 6 | fork-join-executor { 7 | parallelism-min = 2 8 | parallelism-factor = 2.0 9 | parallelism-max = 10 10 | } 11 | 12 | thread-pool-executor { 13 | core-pool-size-min = 2 14 | core-pool-size-factor = 2.0 15 | core-pool-size-max = 10 16 | } 17 | throughput = 100 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/demo6.conf: -------------------------------------------------------------------------------- 1 | akka { 2 | actor { 3 | provider = "akka.cluster.ClusterActorRefProvider" 4 | } 5 | remote { 6 | log-remote-lifecycle-events = off 7 | netty.tcp { 8 | hostname = "127.0.0.1" 9 | port = 0 10 | } 11 | } 12 | 13 | cluster { 14 | seed-nodes = [ 15 | "akka.tcp://ClusterSystem@127.0.0.1:2551", 16 | "akka.tcp://ClusterSystem@127.0.0.1:2552"] 17 | 18 | auto-down-unreachable-after = 10s 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/demo7.conf: -------------------------------------------------------------------------------- 1 | include "demo6" 2 | 3 | # //#min-nr-of-members 4 | akka.cluster.min-nr-of-members = 3 5 | # //#min-nr-of-members 6 | 7 | # //#role-min-nr-of-members 8 | akka.cluster.role { 9 | frontend.min-nr-of-members = 1 10 | backend.min-nr-of-members = 2 11 | } 12 | # //#role-min-nr-of-members 13 | 14 | # //#adaptive-router 15 | akka.actor.deployment { 16 | /factorialFrontend/factorialBackendRouter = { 17 | router = adaptive-group 18 | # metrics-selector = heap 19 | # metrics-selector = load 20 | # metrics-selector = cpu 21 | metrics-selector = mix 22 | nr-of-instances = 100 23 | routees.paths = ["/user/factorialBackend"] 24 | cluster { 25 | enabled = on 26 | use-role = backend 27 | allow-local-routees = off 28 | } 29 | } 30 | } 31 | # //#adaptive-router 32 | -------------------------------------------------------------------------------- /src/main/resources/demo8.conf: -------------------------------------------------------------------------------- 1 | akka { 2 | actor { 3 | provider = "akka.cluster.ClusterActorRefProvider" 4 | } 5 | remote { 6 | log-remote-lifecycle-events = off 7 | netty.tcp { 8 | hostname = "127.0.0.1" 9 | port = 0 10 | } 11 | } 12 | 13 | cluster { 14 | seed-nodes = [ 15 | "akka.tcp://event-cluster-system@127.0.0.1:2751", 16 | "akka.tcp://event-cluster-system@127.0.0.1:2752", 17 | "akka.tcp://event-cluster-system@127.0.0.1:2753"] 18 | seed-node-timeout = 60s 19 | auto-down-unreachable-after = 10s 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | Archetype Created Web Application 7 | 8 | -------------------------------------------------------------------------------- /src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Hello World!

4 | 5 | 6 | --------------------------------------------------------------------------------