【AKKA 官方文檔翻譯】actor模型如何滿足現代分佈式系統的需求

actor模型如何滿足現代分佈式系統的需求

akka版本2.5.8
版權聲明:本文爲博主原創文章,未經博主允許不得轉載。

正如之前所述,在構建現代的苛刻系統時,我們使用現在常見的編程模式並不能正確地去處理好它所遇到的問題。但是,actor模型以一種合理的方式解決了這些問題,使系統能夠按我們想象的方式去運行,並且不需要改變我們之前的編程經驗。Actor模型允許我們從信息交流的方式去考慮我們的代碼,而不像傳統編程中類似大型組織中的人員互相交流。

Actor模型允許我們:

1、在不使用鎖的情況下維持封裝的結構。

2、在協作的環境下,通過發送信號來改變協作實體的狀態。通過相互發送信息來推動整個用應用的運行。

3、這個模型不會與我們之前的編程經驗衝突。

使用消息傳遞的方式避免了鎖和阻塞

Actor不同於過去方法調用的方式,而是通過相互發送信息進行交互。執行任務的線程不會通過信息被傳遞到接收者,所以一個actor實體可以在發送完信息之後繼續運行其他的任務而不會被阻塞。因此,使用actor模型可以在相同時間內完成更多的工作。

在OOP編程裏,當方法返回時,它將釋放對執行線程的控制,actor模型在這點與OOP很相似。當actor實體執行完畢當前的信息之後,它會對信息做出響應並返回執行。通過這種方式,actor完成了我們想象中的對象執行過程:

這裏寫圖片描述

信息傳遞和方法調用之間的一個重要的區別就是信息傳遞沒有返回值。Actor通過發送信息來向其他actor委託任務,如果我們希望它有返回值,那麼發送信息的actor就需要被阻塞或者在當前線程上運行接收者的任務。而actor模型的做法是讓接收線程通過傳遞消息來傳遞運行結果。

第二個重要的方面就是actor模型恢復了對象的封裝。Actor對消息的響應就如同調用對象的方法一樣。不同的是,actor以序列的方式來處理消息,一次處理一個消息,並且消息的發送者和接受者可以獨立地運行不受相互干擾。這種運行方式避免了傳統多線程編程中多個線程併發對對象封裝的破壞。因此每個actor按順序執行它所接收到的消息,不同的actor就可以並行地工作,這樣整個系統就可以充分發揮硬件的並行能力。

由於每個actor每個時刻只能處理一個消息,所以actor內的變量可以不需要同步,這就避免了對代碼加鎖:

這裏寫圖片描述

總之,當一個actor接收到消息時會發生以下情況:

1、actor將消息放在隊列的末尾

2、如果actor沒有被安排執行,則標記它爲準備執行

3、一個(隱藏的)調度器會將這個actor啓動執行

4、Actor從隊列的頂端獲取消息

5、Actor更新內部狀態,並且向其他actor發送消息

6、Actor被取消調度

爲了完成這些工作,actor需要擁有:

1、郵箱(消息最終會到達的存儲隊列)

2、行爲(actor的內部狀態)

3、消息(表示信號的數據片段,就像方法調用參數一樣)

4、執行環境(調用actor的消息處理代碼使其能對消息作出迴應的機制)

5、地址(後續會講到)

當消息進入到actor的郵箱時,actor的行爲表現了其對消息的響應方式。運行環境會對其擁有的線程池進行分配,從而驅動所有的actor運行,而這些對actor都是透明的。

Actor是一個很簡單的模型,但是它解決了之前列舉的問題:

1、通過信令傳遞的方式將執行程序解耦,從而維持了對象的封裝(方法調用傳遞執行環境,但是消息傳遞不這麼做)

2、沒有必要使用鎖,actor的內部狀態只能通過傳遞消息來改變,並且同一時刻只有一個消息會被處理,這就消除了傳統編程中線程爭用導致的問題。

3、沒有任何地方使用鎖,並且消息發送者不會被阻塞。在十幾個線程上可以有效安排數百萬個actor。這充分發揮了現代CPU的潛力。通過消息進行任務委託是actor模型的常用操作模式。

4、Actor的內部狀態是本地的,並且不被共享和改變。數據通過消息進行傳遞,就像現代存儲的運行方式一樣(which maps to how modern memory hierarchy actually works)。在很多情況下,這意味着可以通過高速緩存進行消息傳遞,而把本地狀態和臨時數據放在原始CPU核中。這個模型也恰好和遠程通信類似:

將狀態保存在本機的RAM中,變化/數據作爲數據包在網絡中傳遞。

Actor可以優雅地處理錯誤

由於我們不再通過調用棧來讓發送者和接受者互相通信,我們就可以用一種不同的方式來處理錯誤。我們需要考慮以下兩點:

1、第一種情況,如果是由於任務中的錯誤導致(通常是一些校驗問題,比如用戶標識不存在)任務的失敗。在這種情況下,執行actor上的封裝不會被錯誤破壞,只是這個任務是失敗的。執行actor應該用消息來回復發件人,並說明錯誤的情況。這裏沒有什麼特別的地方,錯誤是領域的一部分,因此就是一個普通的消息。

2、第二種情況,如果服務本身遇到了內部錯誤。Akka會強制所有actor被組織成一個樹狀層析結構,如果一個actor是被另一個actor創建的,那麼它們就互爲父子關係,創建者爲被創建者的父actor。這就和操作系統組織其內部的進程樹的結構是一樣的。就像進程一樣,如果一個actor失敗了,它的父actor會被通知,這時候父actor就可以對這個錯誤作出反應。另外,如果父actor被停止了,那麼其所有的子actor都會被停止。這種機制被稱爲監督,是akka的核心。

這裏寫圖片描述

監管者(父actor)可以根據其子actor的錯誤類型來決定重啓它的子actor還是將它徹底停止。子actor永遠不會默默地死去(死循環除外),它們要麼失敗,在這種情況下父actor會對錯誤作出反應;要麼停止(在這種情況下,感興趣的人會被自動通知)。總會存在一個監管者來管理一個actor,就是它的父actor。Actor的重啓是對外部透明的,actor在重啓時,和其協作的actor依舊可以向它發送消息。

現在,我們來簡單介紹下akka提供的功能。

發佈了20 篇原創文章 · 獲贊 74 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章