1. 程式人生 > 程式設計 >高效能、高容錯性的分散式框架AKKA瞭解一下?

高效能、高容錯性的分散式框架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的簡單介紹就到這裡了,第一次寫,寫的不好還望指點。