Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Akka Cluster in Java - JCConf 2015

3,692 views

Published on

This slide shows you how to use Akka cluster in Java.

Source Code: https://github.com/jiayun/akka_samples

If you want to use the links in slide, please download the pdf file.

Published in: Technology

Akka Cluster in Java - JCConf 2015

  1. 1. #JCConf Akka Cluster in Java Jiayun Zhou jiayun@gmail.com
  2. 2. Introduction
  3. 3. Akka
  4. 4. Concurrent & Distributed
  5. 5. Actor Model
  6. 6. http://blog.shiftehfar.org/?p=431
  7. 7. Scala
  8. 8. Java?
  9. 9. Scala is better
  10. 10. Java
  11. 11. Maven
  12. 12. Basic
  13. 13. pom.xml <dependencies> <dependency> <groupId>com.typesafe.akka</groupId> <artifactId>akka-actor_2.11</artifactId> <version>2.4.1</version> </dependency> </dependencies> <repositories> <repository> <id>typesafe</id> <name>Typesafe Repository</name> <url>http://repo.typesafe.com/typesafe/releases/</url> </repository> </repositories>
  14. 14. Main.java public static void main(String[] args) { // akka.Main.main(new String[]{HelloWorld.class.getName()}); ActorSystem system = ActorSystem.create("Hello"); ActorRef a = system.actorOf(Props.create(HelloWorld.class), "helloWorld"); }
  15. 15. HelloWorld Actor public class HelloWorld extends UntypedActor { @Override public void preStart() { final ActorRef greeter = getContext().actorOf(Props.create(Greeter.class), "greeter"); greeter.tell(Greeter.Msg.GREET, getSelf()); } @Override public void onReceive(Object msg) { if (msg == Greeter.Msg.DONE) { getContext().stop(getSelf()); } else unhandled(msg); } }
  16. 16. Greeter Actor public class Greeter extends UntypedActor { public static enum Msg { GREET, DONE; } @Override public void onReceive(Object msg) { if (msg == Msg.GREET) { System.out.println("Hello World!"); getSender().tell(Msg.DONE, getSelf()); } else unhandled(msg); } }
  17. 17. Sending message • tell() – Fire and forget • ask() – Send and receive
  18. 18. Avoid Ask • https://www.safaribooksonline.com/library/view/effective- akka/9781449360061/ch02.html#_avoiding_ask • https://www.safaribooksonline.com/library/view/effective- akka/9781449360061/ch03.html#_tell_don_8217_t_ask
  19. 19. Remoting
  20. 20. pom.xml <dependency> <groupId>com.typesafe.akka</groupId> <artifactId>akka-remote_2.11</artifactId> <version>2.4.1</version> </dependency>
  21. 21. Local application.conf LocalSys { akka { actor { provider = "akka.remote.RemoteActorRefProvider" } remote { enabled-transports = ["akka.remote.netty.tcp"] netty.tcp { hostname = "127.0.0.1" port = 2551 } } } }
  22. 22. Remote application.conf RemoteSys { akka { actor { provider = "akka.remote.RemoteActorRefProvider" } remote { enabled-transports = ["akka.remote.netty.tcp"] netty.tcp { hostname = "127.0.0.1" port = 2552 } } } }
  23. 23. Local Main public static void main(String[] args) throws Exception { ActorSystem _system = ActorSystem.create("LocalNodeApp",ConfigFactory .load().getConfig("LocalSys")); ActorRef localActor = _system.actorOf(Props.create(LocalActor.class)); localActor.tell("Hello", null); Thread.sleep(5000); _system.shutdown(); }
  24. 24. Local Actor ActorRef remoteActor; @Override public void preStart() { //Get a reference to the remote actor remoteActor = getContext().actorFor( "akka.tcp://RemoteNodeApp@127.0.0.1:2552/user/remoteActor" ); } @Override public void onReceive(Object message) throws Exception { Future<Object> future = Patterns.ask(remoteActor, message.toString(), timeout); String result = (String) Await.result(future, timeout.duration()); log.info("Message received from Server -> {}", result); }
  25. 25. Actor Path akka.<protocol>://<actorsystemname>@<hos tname>:<port>/<actor path> • http://doc.akka.io/docs/akka/2.4.1/general/addressing.html
  26. 26. Remote Main public static void main(String[] args) { final ActorSystem system = ActorSystem.create("RemoteNodeApp", ConfigFactory .load().getConfig("RemoteSys")); system.actorOf(Props.create(RemoteActor.class), "remoteActor"); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { system.shutdown(); } }); }
  27. 27. Remote Actor @Override public void onReceive(Object message) throws Exception { if (message instanceof String) { // Get reference to the message sender and reply back log.info("Message received -> {}", message); getSender().tell(message + " got something", null); } }
  28. 28. Router
  29. 29. Router Main public static void main(String[] args) throws InterruptedException { ActorSystem _system = ActorSystem.create("RemoteRouteeRouterExample", ConfigFactory.load().getConfig("MyRouterExample")); Address[] addresses = new Address[]{ new Address("akka.tcp", "RemoteNodeApp", "10.211.55.6", 2552), new Address("akka.tcp", "RemoteNodeApp", "10.211.55.5", 2552) }; ActorRef router = _system.actorOf(new RemoteRouterConfig(new RoundRobinPool(5), addresses).props( Props.create(RemoteActor.class))); for (int i = 1; i <= 10; i++) { // sends randomly to actors router.tell("Hello " + Integer.toString(i), null); } _system.shutdown(); }
  30. 30. Cluster
  31. 31. pom.xml <dependency> <groupId>com.typesafe.akka</groupId> <artifactId>akka-cluster_2.11</artifactId> <version>2.4.1</version> </dependency>
  32. 32. application.conf akka { actor { provider = "akka.cluster.ClusterActorRefProvider" } remote { log-remote-lifecycle-events = off netty.tcp { hostname = "127.0.0.1" port = 0 } } cluster { seed-nodes = [ "akka.tcp://ClusterSystem@10.211.55.5:2552", "akka.tcp://ClusterSystem@10.211.55.6:2552"] auto-down-unreachable-after = 10s } }
  33. 33. Seed Nodes
  34. 34. Member States
  35. 35. Backend Main public static void main(String[] args) { // Override the configuration of the port when specified as program argument final String hostname = args.length > 0 ? args[0] : "127.0.0.1"; final String port = args.length > 1 ? args[1] : "0"; final Config config = ConfigFactory.parseString("akka.remote.netty.tcp.hostname=" + hostname). withFallback(ConfigFactory.parseString("akka.remote.netty.tcp.port=" + port)). withFallback(ConfigFactory.parseString("akka.cluster.roles = [backend]")). withFallback(ConfigFactory.load()); ActorSystem system = ActorSystem.create("ClusterSystem", config); system.actorOf(Props.create(TransformationBackend.class), "backend"); }
  36. 36. Backend Actor - 1 Cluster cluster = Cluster.get(getContext().system()); //subscribe to cluster changes, MemberUp @Override public void preStart() { cluster.subscribe(getSelf(), MemberUp.class); } //re-subscribe when restart @Override public void postStop() { cluster.unsubscribe(getSelf()); } void register(Member member) { if (member.hasRole("frontend")) getContext().actorSelection(member.address() + "/user/frontend").tell( BACKEND_REGISTRATION, getSelf()); }
  37. 37. Backend Actor - 2 @Override public void onReceive(Object message) { if (message instanceof TransformationJob) { TransformationJob job = (TransformationJob) message; getSender().tell(new TransformationResult(job.getText().toUpperCase()), getSelf()); } else if (message instanceof CurrentClusterState) { CurrentClusterState state = (CurrentClusterState) message; for (Member member : state.getMembers()) { if (member.status().equals(MemberStatus.up())) { register(member); } } } else if (message instanceof MemberUp) { MemberUp mUp = (MemberUp) message; register(mUp.member()); } else { unhandled(message); } }
  38. 38. Frontend Main - 1 final String hostname = args.length > 0 ? args[0] : "127.0.0.1"; final String port = args.length > 1 ? args[1] : "0"; final Config config = ConfigFactory.parseString("akka.remote.netty.tcp.host name=" + hostname). withFallback(ConfigFactory.parseString("akka.remote.n etty.tcp.port=" + port)). withFallback(ConfigFactory.parseString("akka.cluster. roles = [frontend]")). withFallback(ConfigFactory.load()); ActorSystem system = ActorSystem.create("ClusterSystem", config);
  39. 39. Frontend Main - 2 final ActorRef frontend = system.actorOf( Props.create(TransformationFrontend.class), "frontend"); … system.scheduler().schedule(interval, interval, new Runnable() { public void run() { Patterns.ask(frontend, new TransformationJob("hello-" + counter.incrementAndGet()), timeout).onSuccess(new OnSuccess<Object>() { public void onSuccess(Object result) { System.out.println(result); } }, ec); } }, ec);
  40. 40. Frontend Actor - 1 List<ActorRef> backends = new ArrayList<ActorRef>(); int jobCounter = 0; @Override public void onReceive(Object message) { if ((message instanceof TransformationJob) && backends.isEmpty()) { TransformationJob job = (TransformationJob) message; getSender().tell( new JobFailed("Service unavailable, try again later", job), getSender());
  41. 41. Frontend Actor - 2 } else if (message instanceof TransformationJob) { TransformationJob job = (TransformationJob) message; jobCounter++; backends.get(jobCounter % backends.size()) .forward(job, getContext()); } else if (message.equals(BACKEND_REGISTRATION)) { getContext().watch(getSender()); backends.add(getSender()); } else if (message instanceof Terminated) { Terminated terminated = (Terminated) message; backends.remove(terminated.getActor()); } else { unhandled(message); } }
  42. 42. Run java -cp .:./* sample.cluster.transformation.TransformationBackendMa in 10.211.55.5 2552 java -cp .:./* sample.cluster.transformation.TransformationBackendMa in 10.211.55.6 2552 java -cp .:./* sample.cluster.transformation.TransformationFrontendM ain 10.211.55.2 2552
  43. 43. Best Practices • At least two seed nodes • Use fixed port if possible
  44. 44. Something not mentioned • Supervision • Persistence • …
  45. 45. ZooKeeper
  46. 46. 3 ZooKeeper Servers
  47. 47. pom.xml <dependency> <groupId>com.sclasen</groupId> <artifactId>akka-zk-cluster-seed_2.11</artifactId> <version>0.1.2</version> </dependency>
  48. 48. application.conf akka { loglevel = "DEBUG" stdout-loglevel = "DEBUG" actor { provider = "akka.cluster.ClusterActorRefProvider" } remote { log-remote-lifecycle-events = off netty.tcp { hostname = "127.0.0.1" port = 0 } } cluster { // seed-nodes = [ // "akka.tcp://ClusterSystem@10.211.55.5:2552", // "akka.tcp://ClusterSystem@10.211.55.6:2552"] auto-down-unreachable-after = 10s } }
  49. 49. reference.conf akka.cluster.seed.zookeeper { url = "10.211.55.2:2181,10.211.55.5:2181,10.211.55.6:2181" path = "/akka/cluster/seed" }
  50. 50. Join Cluster ActorSystem system = ActorSystem.create("ClusterSystem", config); new ZookeeperClusterSeed((ExtendedActorSystem)system).join();
  51. 51. Cluster & Router
  52. 52. factorial.conf - 1 include "application" # //#min-nr-of-members akka.cluster.min-nr-of-members = 3 # //#min-nr-of-members # //#role-min-nr-of-members akka.cluster.role { frontend.min-nr-of-members = 1 backend.min-nr-of-members = 2 } # //#role-min-nr-of-members
  53. 53. factorial.conf - 2 # //#adaptive-router akka.actor.deployment { /factorialFrontend/factorialBackendRouter = { router = adaptive-group # metrics-selector = heap # metrics-selector = load # metrics-selector = cpu metrics-selector = mix nr-of-instances = 100 routees.paths = ["/user/factorialBackend"] cluster { enabled = on use-role = backend allow-local-routees = off } } } # //#adaptive-router
  54. 54. Backend Main final String port = args.length > 0 ? args[0] : "0"; final Config config = ConfigFactory.parseString("akka.remote.netty.tcp.port=" + port). withFallback(ConfigFactory.parseString("akka.cluster.roles = [backend]")). withFallback(ConfigFactory.load("factorial")); ActorSystem system = ActorSystem.create("ClusterSystem", config); new ZookeeperClusterSeed((ExtendedActorSystem)system).join(); system.actorOf(Props.create(FactorialBackend.class), "factorialBackend"); system.actorOf(Props.create(MetricsListener.class), "metricsListener");
  55. 55. Backend Actor
  56. 56. Frontend Main final int upToN = 200; final Config config = ConfigFactory.parseString( "akka.cluster.roles = [frontend]").withFallback( ConfigFactory.load("factorial")); final ActorSystem system = ActorSystem.create("ClusterSystem", config); new ZookeeperClusterSeed((ExtendedActorSystem)system).join(); Cluster.get(system).registerOnMemberUp(new Runnable() { @Override public void run() { system.actorOf(Props.create(FactorialFrontend.class, upToN, true), "factorialFrontend"); } });
  57. 57. Frontend Actor ActorRef backend = getContext().actorOf(FromConfig.getInstance().props(), "factorialBackendRouter"); … void sendJobs() { log.info("Starting batch of factorials up to [{}]", upToN); for (int n = 1; n <= upToN; n++) { backend.tell(n, getSelf()); } }
  58. 58. Resources
  59. 59. Java Sample Code
  60. 60. https://github.com/jiayun/ akka_samples
  61. 61. https://www.safaribooksonlin e.com/search/?query=Akka& highlight=true
  62. 62. Thanks

×