Actor模型
Actor模型由状态(State)、行为(Behavior)和邮箱(MailBox,可以认为是一个消息队列)三部分组成:
1.状态
Actor模型中的状态指Actor对象的变量信息,状态由Actor模型自己管理,避免了并发环境下的锁和内存原子性等问题。
2.行为
Actor模型中的计算逻辑,通过Actor模型接收到的消息来改变Actor模型的状态。
3.邮箱
邮箱是Actor和Actor之间的通信桥梁,邮箱内部通过FIFO(先入先出)消息队列来存储发送方Actor的消息,接收方Actor再从邮箱队列中获取消息(如图3所示)。
参考文档:
https://mp.weixin.qq.com/s?__biz=MzI1Njk3MTAwNg==&mid=2247491229&idx=1&sn=ee00510c4e4e6fac36daedcad15bb015&chksm=ea1fc70cdd684e1a9c9ef12c88c47323b6526496271536a4272ee447e89f135143eb03e006c2&scene=27
https://www.cnblogs.com/xingchong/p/16202290.html
Akka
轻量级事件处理(1GB内存可容纳百万级别个Actor)
它提供了一套容错机制,允许在Actor出现异常时进行一些恢复或重置操作。
https://developer.lightbend.com/guides/
1. 中文文档
https://github.com/guobinhit/akka-guide
2. docs /akka-quickstart-java
https://developer.lightbend.com/guides/akka-quickstart-java/define-actors.html
3. 定义Actors和messages消息对象
Each actor defines a type T for the messages it can receive.
每个Actor都会定义了一个他自己接受并处理的消息类型
Case classes and case objects make excellent messages
since they are immutable
因为他们是不可变的
and have support for pattern matching,
和支持匹配
something we will take advantage of in the Actor
有时我们会利用Actor的这一优势
when matching on the messages it has received.
当接受消息是匹配
The Hello World Actors use three different messages: 示例Actor使用了三个不同消息
Greet: command sent to the Greeter actor to greet 是发送给GreeterActor的命令 去问候
Greeted: reply from the Greeter actor to confirm the greeting has happened 从GreeterActor回复 去确认 问候已发生
SayHello: command to the GreeterMain to start the greeting process 是GreeterMain的命令 去启动问候的进程
When defining Actors and their messages, keep these recommendations in mind:
当定义Actor和他们的消息的试试,坚持以下建议在心中:
Since messages are the Actor’s public API,
消息是Actor公开的API
it is a good practice to define messages with good names and rich semantic and domain specific meaning,
这时一个良好实践,定义消息用一个好名字,丰富的语义,特殊含义的域
even if they just wrap your data type.
即使他们只是包装了你的数据类型
This will make it easier to use, understand and debug actor-based systems.
这将会更容易被使用,理解,调试 基于系统的Actor
Messages should be immutable, since they are shared between different threads.
消息应该不可变,因为他们被不同线程共享
It is a good practice to put an actor’s associated messages as static classes in the AbstractBehavior’s class.
良好实践,将Action的消息作为静态类 在AbstractBehavior’s的类中
This makes it easier to understand what type of messages the actor expects and handles.
更容易理解 Action期盼和处理的消息类型
It is a good practice obtain an actor’s initial behavior via a static factory method
通过静态工厂方法获取参与者的初始行为是一个很好的做法
Lets see how the implementations for Greeter, GreeterBot and GreeterMain demonstrate these best practices.
一块看看Greeter, GreeterBot and GreeterMain是怎么践行这些良好实践的
This small piece of code defines two message types,
简单代码定义了两个消息类型
one for commanding the Actor to greet someone
一个命令Actor去 问候别人
and one that the Actor will use to confirm that it has done so.
另一个消息被Actor用来确认 已问候
The Greet type contains not only the information of whom to greet,
Greet类型不仅仅包括 问候谁的信息
it also holds an ActorRef that the sender of the message supplies
还包括了一个Actor的引用 ActorRef,消息发送者Action的引用
so that the Greeter Actor can send back the confirmation message.
这样Greeter就可以回复确认消息
The behavior of the Actor is defined as the Greeter AbstractBehavior with the help of the newReceiveBuilder behavior factory.
Action的行为被定义为AbstractBehavior,使用newReceiveBuilder的行为工程
Processing the next message then results in a new behavior that can potentially be different from this one.
处理下一个信息 结果在一个行为对象中 不同于当前这个消息
The state can be updated by modifying the current instance as it is mutable.
状态可以被更新 通过修改当前实例 当做必须的
In this case we don’t need to update any state,
在这个场景下,不需要更新任何状态
so we return this without any field updates,
返回 没有更新任何字段
which means the next behavior is “the same as the current one”.
意思是 下一个行为 是:跟当前一样
The type of the messages handled by this behavior is declared to be of class Greet.
被处理消息的类型 被这个行为 被定义为Greet
Typically, an actor handles more than one specific message type
处理了一个特别的消息类型
and then there is one common interface
他们有共同的接口
that all messages that the actor can handle implements.
所有消息 Actor可以处理 具体实现
On the last line we see the Greeter Actor send a message to another Actor,
最后一行 Greeter Actor发送了一个消息到另外一个Actor
which is done using the tell method.
使用已知的方法
It is an asynchronous operation that doesn’t block the caller’s thread.
这时一个异步操作 不会阻塞调用者的线程
Since the replyTo address is declared to be of type ActorRef<Greeted>,
当返回地址被定义为类型ActorRef<Greeted>
the compiler will only permit us to send messages of this type,
编译器将只允许我们发送这个类型的消息
other usage will be a compiler error.
使用其他的类型 将报编译错
The accepted message types of an Actor together with all reply types defines the protocol spoken by this Actor;
Action接收到的消息类型 一块的有回复的类型 定义 Action应答的协议
in this case it is a simple request–reply protocol but Actors can model arbitrarily complex protocols when needed.
这个场景下,这时一个简单的请求应答协议,但Actors可以 定义复杂协议 当需要时
The protocol is bundled together with the behavior that implements it in a nicely wrapped scope—the Greeter class.
协议 跟行为 捆绑在一块,在友好的封装范围内实现 Greeter类
Note how this Actor manages the counter with an instance variable.
注意这个Actor是咋样管理 计数器 用一个实例变量
No concurrency guards such as synchronized or AtomicInteger are needed since an actor instance processes one message at a time.
没有并发指导 类似synchronized或者AtomicInteger 被使用
在Actor实例 处理一个消息 同一时间
A third actor spawns the Greeter and the GreeterBot and starts the interaction, creating actors and what spawn does is discussed next.
第三个Actor封装了Greeter,GreeterBot,以及启动步骤,创建Actor,以及接下来封装
2. 创建Actors
So far we have looked at the definitions of Actors and their messages.
我们已经看到Actor和他们消息的定义
Now let’s dive a bit deeper into the power of location transparency and see how to create Actor instances.
现在在深入看看强大的 怎么创建实例
The power of location transparency 位置透明的力量
In Akka you can’t create an instance of an Actor using the new keyword.
在Akka你不能使用new关键字创建一个Actor实例
Instead, you create Actor instances using a factory spawn methods.
替代,你可以使用封装的工程方法创建Actor实例
Spawn does not return an actor instance,
封装,但并不直接返回一个Actor实例
but a reference, akka.actor.typed.ActorRef, that points to the actor instance.
是一个引用,全路径:akka.actor.typed.ActorRef的引用,指向Actor的实例
This level of indirection adds a lot of power and flexibility in a distributed system.
这种间接的方法 在分布式系统中 增强了灵活性
In Akka location doesn’t matter.
在Akka中,位置没关系
Location transparency means that the ActorRef can, while retaining the same semantics, represent an instance of the running actor in-process or on a remote machine.
位置透明意味着,保持相同语义的同时,代表一个实例 运行到一个线程或者远程机器
If needed, the runtime can optimize the system by changing an Actor’s location or the entire application topology while it is running.
如果需要,运行时可以优化系统 通过修改Actor的位置 或者整个系统拓扑 在运行的时候
This enables the “let it crash” model of failure management in which the system can heal itself by crashing faulty Actors and restarting healthy ones.
这使得故障管理的“让它崩溃”模型得以实现,在这种模型中,系统可以通过崩溃故障的Actor和重新启动健康的Actor来自我修复。
The Akka ActorSystem
An ActorSystem is the intial entry point into Akka.
ActorSystem是Akka的初始入口
Usually only one ActorSystem is created per application.
通常,一个系统只能创建一个ActorSystem
An ActorSystem has a name and a guardian actor.
一个ActorSystem有一个名字和一个守护Actor
The bootstrap of your application is typically done within the guardian actor.
应用程序的引导通常在守护者中完成。
The guardian actor of this ActorSystem is GreeterMain.
在这个里边 守护Actor是GreeterMain
final ActorSystem<GreeterMain.SayHello> greeterMain = ActorSystem.create(GreeterMain.create(), "helloakka");
It uses Behaviors.setup to bootstrap the application.
使用Behaviors.setup去启动应用
package $package$;
import akka.actor.typed.ActorSystem;
import java.io.IOException;
public class AkkaQuickstart {
public static void main(String[] args) {
//#actor-system
final ActorSystem<GreeterMain.SayHello> greeterMain = ActorSystem.create(GreeterMain.create(), "helloakka");
//#actor-system
//#main-send-messages
greeterMain.tell(new GreeterMain.SayHello("Charles"));
//#main-send-messages
try {
System.out.println(">>> Press ENTER to exit <<<");
System.in.read();
} catch (IOException ignored) {
} finally {
greeterMain.terminate();
}
}
}
Spawning child actors 孵化子Actor
Other actors are created using spawn methods on ActorContext.
其他Actor的创建,使用ActorContext的封装方法
The GreeterMain creates a Greeter actor this way on startup,
GreeterMain创建了Greeter actor 在刚开始
as well as a new GreeterBot each time it receives a SayHello message.
每个GreeterBot 不同时间 接受到一个SayHell消息
greeter = context.spawn(Greeter.create(), "greeter");ActorRef<Greeter.Greeted> replyTo =
getContext().spawn(GreeterBot.create(3), command.name);greeter.tell(new Greeter.Greet(command.name, replyTo));
3. 异步通信
Actors are reactive and message driven.
Actor是被动的,消息驱动的
An Actor doesn’t do anything until it receives a message.
一个Actor不会做任何时期,直到接受一个消息
Actors communicate using asynchronous messages.
相互交流也是使用异步消息
This ensures that the sender does not stick around waiting for their message to be processed by the recipient.
这就确保了发送者不会等待消息被处理
Instead, the sender puts the message in the recipient’s mailbox and is free to do other work.
替代的是,发送者 发送消息到收件人的mailbox并 做其他事情去了
The Actor’s mailbox is essentially a message queue with ordering semantics.
mailbox是有序的队列
The order of multiple messages sent from the same Actor is preserved, but can be interleaved with messages sent by another Actor.
从同一Actor发送的多个消息的顺序将保留,但可以与另一个Actor发送的消息交织。
You might be wondering what the Actor is doing when it is not processing messages,
你可以想知道,Actor不处理消息的时候在干啥
i.e. doing actual work?
做啥实际工作
It is in a suspended state in which it does not consume any resources apart from memory.
挂起状态 除了内存其他资源根本不小韩
Again, showing the lightweight, efficient nature of Actors.
再次,展示了演员的轻量级、高效的本质。
Sending messages to an Actor
发送消息给其他Actor
To put a message into an Actor’s mailbox, use the
tell
method on theActorRef
. For example, the main class of Hello World sends messages to theGreeter
Actor like this:greeterMain.tell(new GreeterMain.SayHello("Charles"));The
Greeter
Actor also sends a message to acknowledge it has received the greeting:command.replyTo.tell(new Greeted(command.whom, getContext().getSelf()));We’ve looked at how to create actors and send messages. Now, let’s review by looking at the
Main
class in its entirety.
4. 主类
The AkkaQuickstart object in Hello World creates ActorSystem with a guardian.
AkkaQuickstart对象在Hello World实例中,创建了ActorSystem以及 一个守护Actor
The guardian is the top level actor that bootstraps your application.
守护Actor是最高层级Actor来启动你的应用
The guardian is typically defined with Behaviors.setup that contains the initial bootstrap.
守护Action用Behaviors.setup启动,包含初始化应用中
package $package$;
import akka.actor.typed.ActorSystem;
import java.io.IOException;
public class AkkaQuickstart {
public static void main(String[] args) {
//#actor-system
final ActorSystem<GreeterMain.SayHello> greeterMain = ActorSystem.create(GreeterMain.create(), "helloakka");
//#actor-system
//#main-send-messages
greeterMain.tell(new GreeterMain.SayHello("Charles"));
//#main-send-messages
try {
System.out.println(">>> Press ENTER to exit <<<");
System.in.read();
} catch (IOException ignored) {
} finally {
greeterMain.terminate();
}
}
}
5. 所有示例代码
Here below is the complete source code from the three classes, Greeter, GreeterBot, GreeterMain and AkkaQuickstart, that creates the sample application:
完整代码
As another best practice we should provide some test coverage.
作为另一个最佳实践,我们应该提供一些测试覆盖。
6. 测试Actors
The tests in the Hello World example illustrates use of the JUnit framework.
The test coverage is not complete.
It shows how to test actor code and provides some basic concepts.