Akka 是一个用 Scala 编写的库,用于简化编写容错的、高可伸缩性的 Java 和 Scala 的 Actor 模型应用。Akka是一个开发库和运行环境,可以用于构建高并发、分布式、可容错、事件驱动的基于JVM的应用。使构建高并发的分布式应用更加容易。
Akka可以以两种不同的方式来使用
- 以库的形式:在web应用中使用,放到 WEB-INF/lib 中或者作为一个普通的Jar包放进classpath。
- 以微内核的形式:你可以将应用放进一个独立的内核。自己有一个main类来初始化Actor系统。
Akka平台竞争力
Akka提供可扩展的实时事务处理。
Akka是一个运行时与编程模型一致的系统,为以下目标设计:
Akka在设计时采用了异步通讯和分布式架构,并对上层进行抽象,如Actors、Futures ,STM等。
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);
}
}