Akka 是一个用 Scala 编写的库,用于简化编写容错的、高可伸缩性的 Java 和 Scala 的 Actor 模型应用。Akka是一个开发库和运行环境,可以用于构建高并发、分布式、可容错、事件驱动的基于JVM的应用。使构建高并发的分布式应用更加容易。
Akka可以以两种不同的方式来使用
Akka平台竞争力
Akka提供可扩展的实时事务处理。
Akka是一个运行时与编程模型一致的系统,为以下目标设计:
2)可靠性(Resilient by Design)
系统具备自愈能力,在本地/远程都有监护。
3)高性能(High Performance)
在单机中每秒可发送50000000个消息。内存占用小,1GB内存中可保存2500000个actors。
4)弹性,无中心(Elastic — Decentralized)
5)可扩展(Extensible)
可以使用Akka 扩展包进行扩展。
在Akka的世界里,只有一个内容需要学习和管理,具有高内聚和高一致的语义。Akka是一种高度可扩展的软件,这不仅仅表现在性能方面,也表现在它所适用的应用的大小。Akka的核心,Akka-actor是非常小的,可以非常方便地放进你的应用中,提供你需要的异步无锁并行功能,不会有任何困扰。你可以任意选择Akka的某些部分集成到你的应用中,也可以使用完整的包——Akka 微内核,它是一个独立的容器,可以直接部署你的Akka应用。随着CPU核数越来越多,即使你只使用一台电脑,Akka也可作为一种提供卓越性能的选择。Akka还同时提供多种并发范型,允许用户选择正确的工具来完成工作。
Akka使用场景
我们看到Akka被成功运用在众多行业的众多大企业,从投资业到商业银行、从零售业到社会媒体、仿真、游戏和赌
博、汽车和交通系统、数据分析等等等等。任何需要高吞吐率和低延迟的系统都是使用Akka的候选。
Actor使你能够进行服务失败管理(监管者),负载管理(缓和策略、超时和隔离),水平和垂直方向上的可扩展性
(增加cpu核数和/或增加更多的机器)管理。
下面的链接中有一些Akka用户关于他们如何使用Akka的描述:
http://stackoverflow.com/questions/4493001/good-use-case-for-akka
所有以上这些都在这个Apache2许可的开源软件中。
Actors模型
<dependency> <groupId>com.typesafe.akka</groupId> <artifactId>akka-actor_2.11</artifactId> <version>2.3.11</version> </dependency>
import java.util.concurrent.TimeUnit; import scala.concurrent.duration.Duration; import akka.actor.ActorRef; import akka.actor.ActorSystem; import akka.actor.Props; public class Bootstrap { public static void main(String[] args) { ActorSystem actorSystem = ActorSystem.create("CaculateSystem"); final ActorRef master = actorSystem.actorOf(Props.create(Master.class), "Master"); actorSystem.scheduler().schedule( Duration.create(1, TimeUnit.SECONDS), Duration.create(1, TimeUnit.SECONDS), new Runnable() { @Override public void run() { master.tell(new Operation(1, 2, OperationSymbol.ADD), null); master.tell(new Operation(3, 2, OperationSymbol.SUB), null); master.tell(new Operation(2, 2, OperationSymbol.MUL), null); master.tell(new Operation(8, 2, OperationSymbol.DEV), null); } }, actorSystem.dispatcher()); } }
import akka.actor.ActorRef; import akka.actor.Props; import akka.actor.UntypedActor; public class Master extends UntypedActor { @Override public void onReceive(Object message) throws Exception { if (message instanceof Operation) { ActorRef worker = getContext().actorOf(Props.create(Worker.class)); worker.tell(message, getSelf()); } else if (message instanceof OperationResult) { OperationResult operationResult = (OperationResult) message; System.out.println(operationResult.toString()); getContext().stop(getSender()); } else { unhandled(message); } } }
import akka.actor.UntypedActor; public class Worker extends UntypedActor { @Override public void onReceive(Object message) throws Exception { if (message instanceof Operation) { Operation operation = (Operation) message; int result = operation.execute(); getSender().tell(new OperationResult(operation, result), getSelf()); } else { unhandled(message); } } }
public class Operation { private final int param1; private final int param2; private final OperationSymbol symbol; public Operation(int param1, int param2, OperationSymbol symbol) { this.param1 = param1; this.param2 = param2; this.symbol = symbol; } public int getParam1() { return param1; } public int getParam2() { return param2; } public OperationSymbol getOperationSymbol() { return symbol; } public int execute() { int result = 0; String name = symbol.getName(); if (name.equalsIgnoreCase(OperationSymbol.ADD.getName())) { result = this.param1 + this.param2; } else if (name.equalsIgnoreCase(OperationSymbol.SUB.getName())) { result = this.param1 - this.param2; } else if (name.equalsIgnoreCase(OperationSymbol.MUL.getName())) { result = this.param1 * this.param2; } else { result = this.param1 / this.param2; } return result; } }
public enum OperationSymbol { ADD("+"), SUB("-"), MUL("*"), DEV("/"); private String name = null; private OperationSymbol(String name) { this.name = name; } public String getName() { return name; } }
public class OperationResult { private final Operation operation; private final int result; public OperationResult(Operation operation, int result) { this.operation = operation; this.result = result; } @Override public String toString() { return operation.getParam1() + operation.getOperationSymbol().getName() + operation.getParam2() + "=" + result; } }
import java.util.concurrent.TimeUnit; import scala.concurrent.duration.Duration; import akka.actor.ActorRef; import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.UntypedActor; import akka.routing.RoundRobinRouter; public class Pi { public static void main(String[] args) { Pi pi = new Pi(); pi.calculate(4, 10000, 10000); } static class Calculate { } static class Work { private final int start; private final int nrOfElements; public Work(int start, int nrOfElements) { this.start = start; this.nrOfElements = nrOfElements; } public int getStart() { return start; } public int getNrOfElements() { return nrOfElements; } } static class Result { private final double value; public Result(double value) { this.value = value; } public double getValue() { return value; } } static class PiApproximation { private final double pi; private final Duration duration; public PiApproximation(double pi, Duration duration) { this.pi = pi; this.duration = duration; } public double getPi() { return pi; } public Duration getDuration() { return duration; } } public static class Worker extends UntypedActor { private double calculatePiFor(int start, int nrOfElements) { double acc = 0.0; for (int i = start * nrOfElements; i <= ((start + 1) * nrOfElements - 1); i++) { acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1); } return acc; } public void onReceive(Object message) { if (message instanceof Work) { Work work = (Work) message; double result = calculatePiFor(work.getStart(), work.getNrOfElements()); getSender().tell(new Result(result), getSelf()); } else { unhandled(message); } } } public static class Master extends UntypedActor { private final int nrOfMessages; private final int nrOfElements; private double pi; private int nrOfResults; private final long start = System.currentTimeMillis(); private final ActorRef listener; private final ActorRef workerRouter; public Master(final int nrOfWorkers, int nrOfMessages, int nrOfElements, ActorRef listener) { this.nrOfMessages = nrOfMessages; this.nrOfElements = nrOfElements; this.listener = listener; this.workerRouter = this.getContext().actorOf(Props.create(Worker.class).withRouter( new RoundRobinRouter(nrOfWorkers)), "workerRouter"); } public void onReceive(Object message) { if (message instanceof Calculate) { for (int start = 0; start < nrOfMessages; start++) { workerRouter.tell(new Work(start, nrOfElements), getSelf()); } } else if (message instanceof Result) { Result result = (Result) message; pi += result.getValue(); nrOfResults += 1; if (nrOfResults == nrOfMessages) { // Send the result to the listener Duration duration = Duration.create(System.currentTimeMillis() - start, TimeUnit.MILLISECONDS); listener.tell(new PiApproximation(pi, duration), getSelf()); // Stops this actor and all its supervised children getContext().stop(getSelf()); } } else { unhandled(message); } } } public static class Listener extends UntypedActor { public void onReceive(Object message) { if (message instanceof PiApproximation) { PiApproximation approximation = (PiApproximation) message; System.out.println(String.format("\n\tPi approximation: \t\t%s\n\tCalculation time: \t%s", approximation.getPi(), approximation.getDuration())); getContext().system().shutdown(); } else { unhandled(message); } } } public void calculate(final int nrOfWorkers, final int nrOfElements, final int nrOfMessages) { ActorSystem system = ActorSystem.create("PiSystem"); final ActorRef listener = system.actorOf(Props.create(Listener.class), "listener"); ActorRef master = system.actorOf(Props.create(Master.class, nrOfWorkers, nrOfMessages, nrOfElements, listener), "master"); // ActorRef master = system.actorOf(new Props(new UntypedActorFactory() { // public UntypedActor create() { // return new Master(nrOfWorkers, nrOfMessages, nrOfElements, listener); // } // }), "master"); master.tell(new Calculate(), null); } }