Akka 库和模块概述
在深入研究编写 actor 的一些最佳实践之前,预览最常用的 Akka 库会很有帮助。 这将帮助您开始考虑要在系统中使用的功能。 所有核心 Akka 功能都可以作为开源软件 (OSS) 使用。 Lightbend 赞助 Akka 开发,但也可以帮助您提供商业产品,例如培训、咨询、支持和企业功能——一套用于管理 Akka 系统的综合工具。
Akka OSS 包含以下功能,并在本页后面介绍:
- Actor 库
- 远程调用
- 集群
- 集群分片
- 集群单例
- 持久化
- Projections
- 分布式数据
- 流
- Alpakka
- HTTP
- gRPC
此页面并未列出所有可用模块,但概述了主要功能,并让您了解在 Akka 之上开始构建系统时可以达到的复杂程度。
Actor 库
<properties>
<scala.binary.version>2.13</scala.binary.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-bom_${scala.binary.version}</artifactId>
<version>2.6.19</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor-typed_${scala.binary.version}</artifactId>
</dependency>
</dependencies>
核心 Akka 库是 akka-actor-typed
,但 Actor 在 Akka 库中使用,提供一致的集成模型,使您无需单独解决并发或分布式系统设计中出现的挑战。 从鸟瞰的角度来看,actor 是一种编程范式,它将封装(OOP 的支柱之一)发挥到了极致。 与对象不同,Actor不仅封装了它们的状态,还封装了它们的执行。 与Actor的通信不是通过方法调用,而是通过传递消息。 虽然这种差异可能看起来很小,但实际上它使我们能够在并发和远程通信方面摆脱 OOP 的限制。 如果这个描述感觉太高而无法完全掌握,请不要担心,下一章我们将详细解释Actor。 目前,重要的一点是,这是一个在基础级别处理并发和分布的模型,而不是临时修补尝试将这些特性引入 OOP。
Actor解决的挑战包括以下内容:
- 如何构建和设计高性能的并发程序。
- 如何处理多线程环境中的错误。
- 如何保护我的项目免受并发陷阱的影响。
远程调用
<properties>
<scala.binary.version>2.13</scala.binary.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-bom_${scala.binary.version}</artifactId>
<version>2.6.19</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-remote_${scala.binary.version}</artifactId>
</dependency>
</dependencies>
远程处理使居住在不同计算机上的参与者能够无缝地交换消息。 虽然作为 JAR 工件分发,但 Remoting 更像是一个模块,而不是一个库。 您主要通过配置启用它,它只有几个 API。 多亏了actor模型,远程和本地消息发送看起来完全一样。 您在本地系统上使用的模式直接转换为远程系统。 您很少需要直接使用 Remoting,但它提供了构建 Cluster 子系统的基础。
远程调用解决的挑战包括:
- 如何找到活跃在远程主机上的Actor系统。
- 如何找到远程Actor系统上的单个Actor。
- 如何将消息转换为网络上的字节。
- 如何透明地管理主机之间的低级网络连接(和重新连接),检测崩溃的Actor系统和主机。
- 如何在同一网络连接上多路复用来自一组不相关Actor的通信,所有这些都是透明的。
集群
<properties>
<scala.binary.version>2.13</scala.binary.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-bom_${scala.binary.version}</artifactId>
<version>2.6.19</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-cluster-typed_${scala.binary.version}</artifactId>
</dependency>
</dependencies>
如果您有一组协作解决某些业务问题的Actor系统,那么您可能希望以规范的方式管理这些系统集。 Remoting 解决了远程系统组件的寻址和通信问题,而集群使您能够将这些组件组织成一个由成员协议绑定在一起的“元系统”。 在大多数情况下,您希望使用 Cluster 模块而不是直接使用 Remoting。 集群在远程处理之上提供了大多数实际应用程序所需的一组附加服务。
集群模块解决的挑战包括:
- 如何维护一组可以相互通信并将彼此视为集群的一部分的actor系统(一个集群)。
- 如何安全地将新系统引入到现有成员的集合中。
- 如何可靠地检测暂时无法访问的系统。
- 如何删除发生故障的主机/系统(或缩小系统规模),以便所有剩余成员就集群的剩余子集达成一致。
- 如何在当前成员下进行分布式计算。
- 如何将集群的成员指定为某个角色,即提供某些服务而不提供其他服务。
集群分片
<properties>
<scala.binary.version>2.13</scala.binary.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-bom_${scala.binary.version}</artifactId>
<version>2.6.19</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-cluster-sharding-typed_${scala.binary.version}</artifactId>
</dependency>
</dependencies>
分片有助于解决在 Akka 集群的成员之间分配一组Actor的问题。 分片是一种模式,主要与持久化一起使用,以平衡大量持久实体(由Actor支持)到集群成员,并在成员崩溃或离开时将它们迁移到其他节点。
分片解决的挑战包括:
- 如何在一组系统上建模和扩展大量有状态实体。
- 如何确保集群中的实体正确分布,以便在机器之间正确平衡负载。
- 如何确保在不丢失状态的情况下从崩溃的系统迁移实体。
- 如何确保一个实体不会同时存在于多个系统上,从而保持一致。
集群单例
<properties>
<scala.binary.version>2.13</scala.binary.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-bom_${scala.binary.version}</artifactId>
<version>2.6.19</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-cluster-singleton_${scala.binary.version}</artifactId>
</dependency>
</dependencies>
分布式系统中的一个常见(事实上,有点太常见)用例是让一个实体负责给定的任务,该任务在集群的其他成员之间共享,并在主机系统出现故障时迁移。不可否认,这给整个集群带来了一个共同的瓶颈,限制了扩展,但在某些情况下,使用这种模式是不可避免的。Cluster singleton允许集群选择一个Actor系统,该系统将承载一个特定的参与者,而其他系统始终可以独立于服务所在地访问该服务。
Singleton 模块可用于解决这些挑战:
- 如何确保整个集群中只有一个服务实例在运行。
- 如何确保即使承载该服务的系统当前在缩减过程中崩溃或关闭,该服务仍处于运行状态。
- 假设它可以随时间迁移到其他系统,如何从集群的任何成员访问此实例。
持久化
<properties>
<scala.binary.version>2.13</scala.binary.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-bom_${scala.binary.version}</artifactId>
<version>2.6.19</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-persistence-typed_${scala.binary.version}</artifactId>
</dependency>
</dependencies>
就像 OOP 中的对象一样,actor 将其状态保存在容易丢失的内存中。 一旦系统正常关闭或由于崩溃而关闭,内存中的所有数据都会丢失。 持久性提供了一些模式,使Actor能够持久化导致其当前状态的事件。 启动时,可以重新加载事件以恢复Actor所托管的实体的状态。 可以查询事件流并将其馈送到其他处理管道(例如外部大数据集群)或备用视图(如报告)。
持久化解决了以下挑战:
- 如何在系统重新启动或崩溃时恢复实体/Actor的状态。
- 如何实现 CQRS 系统。
- 面对网络错误和系统崩溃,如何确保消息的可靠传递。
- 如何内省导致实体进入其当前状态的领域事件。
- 如何在您的应用程序中利用事件溯源来支持长期运行的流程,同时项目继续发展。
Projections
<properties>
<scala.binary.version>2.13</scala.binary.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-bom_${scala.binary.version}</artifactId>
<version>2.6.19</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-projection-core_${scala.binary.version}</artifactId>
</dependency>
</dependencies>
Projections提供了一个简单的API,用于消费事件流,并将其映射到各种下游选项中。核心依赖项只提供API,其他提供者依赖项是不同源和接收器实现所必需的。
Projections 解决的挑战包括:
- 在事件流上构建替代或聚合视图。
- 将事件流传播到另一个下游介质,例如 Kafka的Topic。
- 在事件源和CQRS系统的上下文中构建读取端投影的简单方法
分布式数据
<properties>
<scala.binary.version>2.13</scala.binary.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-bom_${scala.binary.version}</artifactId>
<version>2.6.19</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-cluster-typed_${scala.binary.version}</artifactId>
</dependency>
</dependencies>
在可以接受最终一致性的情况下,可以在 Akka 集群中的节点之间共享数据,并且即使面对集群分区也可以接受读写。 这可以使用无冲突复制数据类型 (CRDT) 来实现,其中不同节点上的写入可以同时发生,然后以可预测的方式合并。 分布式数据模块提供了共享数据和许多有用数据类型的基础设施。
分布式数据旨在解决以下挑战:
- 即使面对集群分区,如何接受写入。
- 如何在共享数据的同时确保低延迟的本地读写访问。
流
<properties>
<scala.binary.version>2.13</scala.binary.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-bom_${scala.binary.version}</artifactId>
<version>2.6.19</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-stream-typed_${scala.binary.version}</artifactId>
</dependency>
</dependencies>
Actors 是并发的基本模型,但也有一些常见的模式,它们的使用要求用户一遍又一遍地实现相同的模式。 非常常见的情况是,参与者的链或图需要处理潜在的大型或无限的顺序事件流并适当地协调资源使用,以便更快的处理阶段不会压倒链或图中较慢的处理阶段。 Streams 在actors之上提供了一个更高层次的抽象,简化了编写这样的处理网络,在后台处理所有的细节,并提供了一个安全的、类型化的、可组合的编程模型。 Streams 也是 Reactive Streams 标准的实现,可以与该标准的所有第三方实现集成。
Streams 解决了以下挑战:
- 如何以高性能处理事件流或大型数据集,利用并发性并保持资源使用紧张。
- 如何将可重用的事件/数据处理部分组装到灵活的管道中。
- 如何以灵活的方式将异步服务以高性能的方式相互连接。
- 如何提供或使用符合 Reactive Streams 的接口来与第三方库交互。
Alpakka
Alpakka 是一个独立于 Akka 的模块。
HTTP
Akka HTTP 是一个独立于 Akka 的模块。
gRPC
Akka gRPC 是一个独立于 Akka 的模块。