## ​​分布式计算技术之Actor计算模式​​

The Actor Model for Concurrent Computation

## 什么是 Actor？

Actor 类似于一个“黑盒”对象，封装了自己的状态和行为，使得其他 Actor 无法直接观察到它的状态，调用它的行为。多个 Actor 之间通过消息进行通信，这种消息类似于电子邮箱中的邮件。Actor 接收到消息之后，才会根据消息去执行计算操作。

Actor 模型，代表一种异步消息模式的分布式并行计算模型。在 Actor 模型里，每个 Actor 相当于系统中的一个组件，都是基本的计算单元。

Actor 模型的计算方式与传统面向对象编程模型(Object-Oriented Programming，OOP)类似，一个对象接收到一个方法的调用请求(类似于一个消息)，从而去执行该方法。

OOP 因为数据封装在一个对象中，不能被外部访问，当多个外部对象通过方法调用方式，即同步方式进行访问时，会存在死锁、竞争等问题，无法满足分布式系统的高并发性需求。

## Actor模型

Actor模型是处理并行计算的概念模型。它定义了系统部件行为和交互的一些规则。使用这个模型的最著名的编程语言是Erlang。

actor作为群体存在，单一的actor不是actor模式。在actor模型中，actor是唯一组成部分，actor带有地址以便互相发送消息。

actor按次序处理消息，比如你发送三个消息给一个actor，它们不会被并发处理。如果你想让这三个消息得到并发处理，你需要创建3个actor，然后分别发送给它们。

## Actor计算模式

Actor模型的三要素：

1. 状态：Actor组件本身的信息
2. 行为：Actor的计算处理操作
3. 消息：Actor的消息以邮件的形式在多个Actor之间通信传递，每个Actor都会有一个自己的邮箱.

## 工作流程

Actor2从MailBox队列中依次取出Actor1和Actor3发送的消息执行相应的操作

## Actor的行为

1. 创建更多的actor
2. 发送消息到其他actor
3. 指派对下一条消息做什么处理。

Erlang语言中有个“由它失败”的思想。就是你不可能考虑到所有导致失败的问题，与其绞尽脑汁处理这些问题，不如让它自然失败，然后指派给失败处理者处理(例如恢复到稳定状态)，在actor模型中，这是可行的。

actor之间的隔离性导致actor失败不会影响其他actor，监控者可以对自然失败的actor做直接处理而不会带来连锁问题。这让“自愈系统”成为可能，就是说一个actor异常后，监控者可以恢复一致性，可能以初始状态重起actor。

actor发消息时不在乎目标actor是本地运行的还是运行在其他节点。试想，如果actor只是只有内部状态的邮箱，只对消息做出反应，那就没人在乎它在哪里运行，知道有个地址让消息可以到达即可。这让我们可以创建分布式系统，并且在节点失败时独立恢复而不影响整个系统。

## Actor关键特征

### 优势

Actor 的通信机制与日常的邮件通信非常类似。因此，我们可以进一步总结出 Actor 模型的一些特点：

1. 实现了更高级的抽象
Actor 与 OOP 对象类似，封装了状态和行为。但是，Actor 之间是异步通信的，多个 Actor 可以独立运行且不会被干扰，解决了 OOP 存在的竞争问题。

2.非阻塞性

3.无需使用锁
Actor 从 MailBox 中一次只能读取一个消息，也就是说，Actor 内部只能同时处理一个消息，是一个天然的互斥锁，所以无需额外对代码加锁。

4.并发度高

5.易扩展

### 不足

Actor 提供了模块和封装，但缺少继承和分层，这使得即使多个 Actor 之间有公共逻辑或代码部分，都必须在每个 Actor 中重写这部分代码，也就是说重用性小，业务逻辑的改变会导致整体代码的重写。
Actor 可以动态创建多个 Actor，使得整个 Actor 模型的行为不断变化，因此在工程中不易实现 Actor 模型。此外，增加 Actor 的同时，也会增加系统开销。

Actor 模型不适用于对消息处理顺序有严格要求的系统。因为在 Actor 模型中，消息均为异步消息，无法确定每个消息的执行顺序。虽然可以通过阻塞 Actor 去解决顺序问题，但显然，会严重影响 Actor 模型的任务处理效率。

1. 可重用性低，业务逻辑的改变会导致整体代码的重写
2. 工程上难以实现
3. 不适用于对消息处理顺序有严格要求的系统

## Actor 主要应用

1.Erlang/OTP: Erlang是面向并发的编程语言，OTP是Erlang技术栈中的标准库

2.Akka: 为java和scala构建高度并发、分布式和弹性的消息驱动应用程序的工具包

1. Quasar(Java): 开源的JVM库

## 框架与语言

Actor 模型在 1973 年被提出，已广泛应用在多种框架和语言中。可以说，很多框架或语言支持 Actor 编程模型，是为了给开发者提供一个通用的编程框架，让用户可以聚焦到自己的业务逻辑上，而不用像面向对象等编程模型那样需要关心死锁、竞争等问题。

1. Erlang/OTP。Erlang 是一种通用的、面向并发的编程语言，使用 Erlang 编写分布式应用比较简单，而 OTP 就是 Erlang 技术栈中的标准库。Actor 模型在 Erlang 语言中得到广泛支持和应用，其他语言的 Actor 逻辑实现在一定程度上都是参照了 Erlang 的模式。实现了 Actor 模型逻辑的 Erlang/OTP，可以用于构建一个开发和运行时环境，从而实现分布式、实时的、高可用性的系统。
2. Akka。Akka 是一个为 Java 和 Scala 构建高度并发、分布式和弹性的消息驱动应用程序的工具包。Akka 框架基于 Actor 模型，提供了一个用于构建可扩展的、弹性的、快速响应的应用程序的平台。通过使用 Actors 和 Streams 技术， Akka 为用户提供了多个服务器，使用户更有效地使用服务器资源并构建可扩展的系统。Quasar (Java) 。
3. Quasar 是一个开源的 JVM 库，极大地简化了高度并发软件的创建。Quasar 在线程实现时，参考了 Actor 模型，采用异步编程逻辑，从而为 JVM 提供了高性能、轻量级的线程，可以用在 Java 和 Kotlin 编程语言中.

## The Actor Model (everything you wanted to know...)

Our CPUs are not getting any faster. What’s happening is that we now have multiple cores on them. If we want to take advantage of all this hardware we have available now, we need a way to run our code concurrently. Decades of untraceable bugs and developers’ depression have shown that ​​threads​​ are not the way to go. But fear not, there are great alternatives out there and today I want to show you one of them: The actor model.

### The model

The actor model is a conceptual model to deal with concurrent computation. It defines some general rules for how the system’s components should behave and interact with each other. The most famous language that uses this model is probably ​​Erlang​​. I’ll try to focus more on the model itself and not in how it’s implemented in different languages or libraries.

### Actors

An actor is the primitive unit of computation. It’s the thing that receives a message and do some kind of computation based on it.

The idea is very similar to what we have in object-oriented languages: An object receives a message (a method call) and does something depending on which message it receives (which method we are calling).

The main difference is that actors are completely isolated from each other and they will never share memory. It’s also worth noting that an actor can maintain a private state that can never be changed directly by another actor.

##### One ant is no ant

And one actor is no actor. They come in systems. In the actor model everything is an actor and they need to have addresses so one actor can send a message to another.

##### Actors have mailboxes

It’s important to understand that, although multiple actors can run at the same time, an actor will process a given message sequentially. This means that if you send 3 messages to the same actor, it will just execute one at a time. To have these 3 messages being executed concurrently, you need to create 3 actors and send one message each.

Messages are sent asynchronously to an actor, that needs to store them somewhere while it’s processing another message. The mailbox is the place where these messages are stored.

image

Actors communicate with each other by sending asynchronous messages. Those messages are stored in other actors' mailboxes until they're processed.

##### What actors do

When an actor receives a message, it can do one of these 3 things:

• Create more actors
• Send messages to other actors
• Designate what to do with the next message

The first two bullet points are pretty straightforward, but the last one is interesting.
I said before that an actor can maintain a private state. “Designating what to do with the next message” basically means defining how this state will look like for the next message it receives. Or, more clearly, it’s how actors mutate state.

Let’s imagine we have an actor that behaves like a calculator and that its initial state is simply the number ​​0​​​. When this actor receives the ​​add(1)​​​ message, instead of mutating its original state, it designates that for the next message it receives, the state will be ​​1​​.

### Fault tolerance

​Erlang​​ introduced the “let it crash” philosophy. The idea is that you shouldn’t need to program defensively, trying to anticipate all the possible problems that could happen and find a way to handle them, simply because there is no way to think about every single failure point.

What ​​Erlang​​ does is simply letting it crash, but make this critical code be supervised by someone whose only responsibility is to know what to do when this crash happens (like resetting this unit of code to a stable state), and what makes it all possible is the actor model.

Every code run inside a ​​process​​​ (that is basically how ​​Erlang​​​ calls its actors). This ​​process​​​ is completely isolated, meaning its state is not going to influence any other ​​process​​​. We have a supervisor, that is basically another ​​process​​​ (everything is an actor, remember?), that will be notified when the supervised ​​process​​ crashes and then can do something about it.

This makes it possible to create systems that “self heal”, meaning that if an actor gets to an exceptional state and crashes, by whatever reason, a supervisor can do something about it to try to put it in a consistent state again (and there are multiple strategies to do that, the most common being just to restart the actor with its initial state).

### Distribution

Another interesting aspect of the actor model is that it doesn’t matter if the actor that I’m sending a message to is running locally or in another node.

Think about it, if an actor is just this unit of code with a mailbox and an internal state, and it just respond to messages, who cares in which machine it’s actually running? As long as we can make the message get there we are fine.
This allows us to create systems that leverage multiple computers and helps us to recover if one of them fail.

### Next steps and other resources

This was a quick overview of the conceptual model that is the base of great languages like ​​Erlang​​​ and ​​Elixir​​​ and libraries like ​​Akka​​​ (for the ​​JVM​​​) and ​​Celluloid​​​ (for ​​Ruby​​).

If I was successful in making you curious about how this model is implemented and used in the real world, this is the list of books that I read or am reading about this topic and can recommend:

And if you are interested in more details about the conceptual idea itself, I can’t recommend this video enough: