高性能、高容错性的分布式框架AKKA了解一下?

框架介绍

AKKA是一款高性能、高容错性的分布式&并行应用框架,遵循Apache2开源许可,基于经典的Actor 并发模型,底层通过Scala语言实现,提供Java和Scala API。

  • 并行与并发:提供对并行与并发的高度抽象。
  • 异步非阻塞:Akka-Actor 消息通信都是基于异步非阻塞。
  • 高容错性:为跨多JVM 的分布式模型提供强劲的容错处理,号称永不着机。
  • 持久化:Actor 携带的状态或消息可以被持久化,以便于在JVM 崩溃后能恢复状态。
  • 轻量级:每个Actor 大约只占300bytes ,1G内存可容纳接近300 万个Actor 。



邮箱:每个Actor都有自己的邮箱,其他Actor发送过来的消息都会进入该邮箱。Akka自带多种邮箱类型,也提供自定义邮箱的接口。(默认邮箱类型为UnboundedMailbox,底层为ConcurrentLinkedQueue,无阻塞,无界队列)

路由:消息除了通过普通的Actor 发送之外,也可以通过路由发送。路由策略有轮询、广播等。路由也可以是一个Actor。

状态持久化:基于内存堆的日志、基于本地文件系统的快照存储以及基于LevelDB的日志。

网络:用于实现远程Actor和分布式集群,包含I/O、网络通信(TCP/UDP)、序列化配置、分布式通信协议(Gossip)、节点管理、集群分片等内容。

HTTP模块:Akka提供了简单易用的HTTP模块,支持完整的HTTP 服务端与客户端开发,快速构建性能极强的Rest Web服务。

Actor 模型

Actor是1973年就提出的一个分布式并发编程模型,设计是基于消息驱动和非阻塞的。认为万物皆Actor。

Actor是Akka最核心的概念,也是最基本的执行单元。Actor认为并行计算的最小单元就是一个Actor实例,而每个实例拥有自己的状态和行为,在一个大型系统中,可能存在成千上万Actor 实例,它们之间通过消息的方式进行通信,每个Actor 都能发送消息给其他Actor,也能从其他Actor 接收消息。

参考文章:

https://www.jianshu.com/p/d803e2a7de8eActor

Actor 特点

引用:不能通过传统"new"的方式直接创建一个Actor对象,通过actorOf 或者actorSelection 等方式返回一个ActorRef 对象,该对象有可能存在于本地,也可能存在于远程节点。

状态: Actor 在不同时刻可能有着不同的状态,这些状态用变量来表示,可进行持久化操作。

行为: Actor 有接收和发送消息的能力,每当它接收一条消息后,就可以执行某个业务操作,同时也可以把消息转发到其他节点进行处理。

监管策略: Actor 系统是一个层级结构,当任务被某个Actor分摊到子Actor 时,父Actor 就拥有监管子Actor的义务。在监管时,我们需要根据不同的情况选择不同的处理方案(比如停止、重启、恢复或者失败上溯)和策略 。

线程安全: Actor 运行于线程池之上,AKKA为每个Actor抽象出一个轻量级的执行“线程”,所以单个Actor 总是线程安全的,并且本身在处理接收到的消息时是串行的。

轻量级: 在Akka 中, 每个Actor 只占用300 字节左右,支持分布式模式。

Actor 定义

在Akka中,Actor 大致分为两类:

  • UntypedActor:基于经典的Actor 模型实现,消息驱动,推荐使用它来定义Actor 。
  • TypedActor :把正常OOP 的代码包装成异步执行的Actor ,比较符合程序员的API 调用逻辑,但是使用过程稍复杂,本次暂不讨论。

通过继承UntypedActor定义一个Actor,onReceive 方法是用于接收并处理消息的地方,对消息类型进行匹配,当匹配不到相应的消息类型时,使用unhandled进行处理。


Actor 创建

首先下载所需要的依赖

<dependency>    
    <groupId>com.typesafe.akka</groupId>    
    <artifactId>akka-actor_2.11</artifactId>  
    <version>2.4.1</version>
</dependency>
<dependency>
    <groupId>com.typesafe.akka</groupId>   
    <artifactId>akka-remote_2.11</artifactId>   
    <version>2.4.1</version>
</dependency>复制代码

通过ActorSystem 的actorOf 方法创建Actor:

ActorSystem system = ActorSystem.create(“hiseePS”); ActorRef actorRef = system.actorOf(Props.create(ActorDemo.class),"actorDemo");

  • actorOf 返回的不是Actor 本身,而是ActorRef,即Actor 的引用,我们就是通过该引用来进行消息通信的。
  • 假如Actor 的构造函数有参数,可以通过create 方法传人。
  • 通过ActorSystem 创建的是一个顶级的Actor(即/user下的分支Actor),如果要创建层级关系的Actor 网络,任务交给子Actor 去处理,父级负责去监督子级。可以使用Actor中的getContext 来创建子Actor。

ActorRef childActor = getContext().actorOf(Props.create(ChildActor.class ),"childActor");


每个Actor 在被创建后都拥有自己的路径,该路径遵循ActorSystem 的层级结构:akka://mysys/user/parentActor/childActor akka.tcp://[email protected]:2554/user/parentActor/childActor

mysys 是ActorSystem 的名字,/user 是用户创建Actor 的默认根节点, parentActor和childActor 分别是父子Actor。

Actor 消息

通过ActorRef 对象和Actor 进行消息通信,有两种方式给一个Actor 发送消息,tell 和ask 。它们都以异步的方式发送消息,不同的是,前者发完后立即返回,而后者期待得到一个返回结果,假如在设置的时间(Timeout)内没有得到返回结果,发送方会收到一个超时异常。任何给Actor 发送的消息都会通过receive 方法收到。

tell 方法:actorRef.tell("Hello Akka", ActorRef.noSender());

第一个参数是“消息”,它可以是任何可序列化的数据或对象,第二个参数表示发送者,即另外一个Actor 的引用,noSender()表示无发送者(系统默认deadLetters的Actor)。如果在Actor内部要获取消息发送者,可以调用getSender()方法。在调用tell 方法后, Actor 就会异步的去处理该消息,不会阻塞后续代码的运行。

ask 方法:当我们需要从Actor 得到一个返回结果时,可以使用ask,这是一种典型的"请求一响应"模式。ask 方法会将返回结果包装在scala.concurrent.Future 中(可以理解为Future模式线程),可以(阻塞)获取这个值,也可以通过异步回调函数获取这个值,考虑到性能问题,我们往往会采用后者。

Ask 方法测试


Actor 消息转发

消息转发:

除了直接给某个Actor 发送消息外,我们还可以通过forward 方式对消息进行转发,比较典型的使用场景是实现消息路由及负载等功能,消息发送者不会改变。


其他用法

1.对于己存在的Actor,我们可以根据路径来进行查找

ActorSelection=[ActorSystem/ActorContext].actorSelecton([path]);

2.Actor 行为切换: 示例代码(BecomeActor)

3.Actor 生命周期

Actor 在运行时中会经历不同的阶段,比如创建、运行、重启和销毁等,这一系列的过程或状态,我们称之为生命周期。

4.监督与容错处理

5.Circuit Breaker (熔断)

就不一一介绍了有兴趣的同学可以自己了解一下。

好了AKKA的简单介绍就到这里了,第一次写,写的不好还望指点。


猜你喜欢

转载自juejin.im/post/5d8accd66fb9a04e247c7871