Akka 設(shè)計(jì)Reactive System架構(gòu)指南(A-Z翻譯系列)

摘要

也許您已經(jīng)聽說過Akka,一種用于建造可伸縮,彈性且高效應(yīng)用程序的工具包,支持Java和Scala編程語言。Akka包括了16個(gè)開源或商業(yè)的模塊,幫助開發(fā)者構(gòu)建從單JVM的Actor到網(wǎng)絡(luò)分區(qū)修復(fù),跨多個(gè)JVM的分布式集群等功能。如此多的特性,架構(gòu)師和開發(fā)者如何從高層的角度理解Akka?讀完本系列白皮書,您將更好的理解Akka “從A到Z”,這趟旅程從簡單的Actor開始,直到集群系統(tǒng)結(jié)束,您將會(huì)學(xué)到以下知識:

  • Akka Actors如何運(yùn)作,從創(chuàng)建系統(tǒng)到管理監(jiān)督和路由
  • Akka 使用Akka Streams 和 Alpakka實(shí)現(xiàn)Reactive Streams的方式
  • 如何用Akka建造分布式集群系統(tǒng),甚至集群中的集群
  • 對于分布式數(shù)據(jù),分布式持久化,發(fā)布-訂閱 和 ES/CQRS,Akka工具包如何通過多種組件提供開箱即用的解決方案
  • 可用的Akka商業(yè)版技術(shù)有哪些,它們是如何工作的

Akka的歷史

Akka開始與1973(以IT世界的時(shí)間計(jì)算的話,相當(dāng)于8000年前),在MIT的實(shí)驗(yàn)室,數(shù)學(xué)博士Carl Hewitt 合作發(fā)表了論文《A Universal Modular Actor Formalism for Artificial Intelligence》,在這篇論文中,介紹了一種數(shù)據(jù)模型,將actors作為并發(fā)計(jì)算的通用原子類型。

“提出Actor 模型是基于高度并行計(jì)算的前景,計(jì)算系統(tǒng)可能由成百上千的獨(dú)立微處理器組成,每個(gè)處理器都擁有自己的本地內(nèi)存和通訊處理器,可以通過高性能通訊網(wǎng)絡(luò)在相互之間進(jìn)行通訊”
--Carl Hewitt

在那個(gè)時(shí)候,跨多種云基礎(chǔ)架構(gòu)的低延遲并發(fā)計(jì)算在商業(yè)上并不可行,一直到企業(yè)級云計(jì)算的到來。
2009年,灣光公司的合伙人兼CTO Jonas Bonér,創(chuàng)建了Akka項(xiàng)目,希望在JVM上構(gòu)造一種分布式,高并發(fā),事件驅(qū)動(dòng)的Actor模型實(shí)現(xiàn),就像 Erlang語言實(shí)現(xiàn)的Actor模型一樣。
現(xiàn)在到了2018年,離Akka十周年之剩一年之際,我們?nèi)栽诶^續(xù)我們的目標(biāo),將構(gòu)建多核,異步,自愈,并且高伸縮性系統(tǒng)的能力帶給Java和Scala的架構(gòu)師和開發(fā)者,而無需關(guān)注所有隱藏在后的底層細(xì)節(jié)。


figure1.png

值得注意的是,Akka是一個(gè)JVM工具包,而不是一個(gè)框架(例如Play 或者 Lagom).雖然面臨開源和商業(yè)組件的選擇(Lightbend Enterprise Suite的一部分),本系列文章將關(guān)注在actors, streams,HTTP,集群,持久化和部署概念上。
這趟旅程將從獨(dú)立的actors開始,介紹監(jiān)督和自愈的行為模式,然后講解通過Akka Streams, Akka HTTP 和 Alpakka實(shí)現(xiàn)Reactive Steams,再介紹事件Sroucing的分布式持久化和CQRS,微服務(wù)。最后到分布式集群以及如何管理,監(jiān)控,編排集群。
了解了藍(lán)圖,讓我們從Akka Actors開始吧。

第一部分 Akka Actors 及其工作方式

Actor 模型

讓我們從Akka系統(tǒng)的原子或分子級別來看看actors,相對于大多數(shù)開發(fā)者來說,這是一種完全不同的編程方式。許多開發(fā)者學(xué)習(xí)過面向?qū)ο缶幊?,甚至函?shù)式編程,大多數(shù)情況下,這是必要的,同步方式編程設(shè)計(jì)到了很多線程和相關(guān)元素。
然而Actor 模型有很大不同,一個(gè)Actor本身是一個(gè)class,可以用Java或者Scala實(shí)現(xiàn),actor具備方法,但是actor最大的不同在于actor的方法并不是在actor外部直接被別的類訪問調(diào)用的。
不直接調(diào)用actor的方法,這需要改變原來的習(xí)慣。和actor交互的唯一方式是通過Akka提供的 actor system向actor發(fā)送消息。


figurep1-1.png

在actors中,actor之間消息是異步發(fā)送的,而不是同步的,如圖一所示,消息首先存入待處理消息收件箱,actor遍歷收件箱,一個(gè)一個(gè)地處理消息。這就是actor的基本機(jī)制,Akka系統(tǒng)就是由許多個(gè)actor構(gòu)成,actor之間互相通過發(fā)送消息進(jìn)行通訊。

figurep1-2.png

其工作原理如圖2所示: actor A 發(fā)送消息給 actor B. 這是一個(gè)異步消息,就像兩個(gè)人互相發(fā)送短信。A 發(fā)送給 B一條消息, A可以繼續(xù)干別的事情,A并不會(huì)掛起等待B的回應(yīng),這和傳統(tǒng)的面向?qū)ο蟮姆椒ㄕ{(diào)用不一樣,傳統(tǒng)的方法調(diào)用必須等待方法返回。在這個(gè)例子中,A發(fā)了消息就繼續(xù)往下執(zhí)行了,或者執(zhí)行別的代碼,或者沒有代碼執(zhí)行,啥也不干。


figurep1-3.png

在圖3中 B 收到A發(fā)送的消息,觸發(fā)了狀態(tài)的改變,例如B代表一個(gè)銀行賬戶,消息代表取款動(dòng)作的發(fā)生,因此狀態(tài)改變即更新賬戶余額,如果需要,B可以給A發(fā)送一條回執(zhí)消息:“已完成狀態(tài)更新”
現(xiàn)實(shí)中,actors A和B可能運(yùn)行在分布式環(huán)境,B可能在另一個(gè)機(jī)器上無法回應(yīng)。從一開始,這就提出了關(guān)于該做什么的問題;B從A獲得消息,完成任務(wù),也許會(huì)發(fā)送一條回執(zhí)消息。但這個(gè)流程也可能發(fā)生故障。


figurep1-4.png

圖4 展示了A能夠直接向Akka的actor system報(bào)告一個(gè)請求: “請?jiān)谖磥砟硞€(gè)時(shí)間點(diǎn)給我發(fā)送一個(gè)消息“,可以是幾毫秒,幾秒或者幾分鐘之后。這個(gè)使用的場景是A向B發(fā)送消息,得不到回應(yīng)的情況下,一個(gè)超時(shí)的消息將會(huì)被發(fā)送。


figurep1-5.png

在圖5中,A獲取到超時(shí)消息,A處理兩種類型的消息:從B得到的回應(yīng)消息或者超時(shí)消息。換句話說,A知道這兩種情形下分別該如何處理,這和異常處理不同,大多數(shù)異常只是被拋出,而在Akka中,彈性(resilience)是架構(gòu)中就考慮的特性,而不是事后的想法。

Actor監(jiān)督 (自修復(fù))

figurep1-6.png

彈性是Akka設(shè)計(jì)的一部分,讓我們來看看Actor的監(jiān)督機(jī)制。Actor能夠創(chuàng)建子Actor,形成Actor的層級關(guān)系,就像我們在圖6中看到的一樣。在這個(gè)例子中,actor A是監(jiān)督者,創(chuàng)建了多個(gè)干活的actor,他們之間是一種"父-子"關(guān)系或者 “監(jiān)督者-工作者”的關(guān)系。

監(jiān)督者和工作者之間的關(guān)系是一種監(jiān)督策略,當(dāng)干活的actor處理消息遇到問題的時(shí)候,它自己并不處理這個(gè)異常,而是由監(jiān)督者來處理,這種監(jiān)督策略是定義好的,但也可以定制化??傊?,對于工作actor出現(xiàn)的異常,監(jiān)管actor始終有一個(gè)應(yīng)對計(jì)劃。

監(jiān)督者A的響應(yīng)包括:異常不嚴(yán)重的情況下恢復(fù)工作actor,繼續(xù)執(zhí)行;或者重啟工作actor;或者這個(gè)問題實(shí)在太嚴(yán)重,需要停止工作actor;最極端的情況是,監(jiān)督者也無法處理此問題,因此將問題向上報(bào)告給它的上級監(jiān)督者。

因此,根據(jù)嚴(yán)重程度,問題可以在層次結(jié)構(gòu)中逐級上升,這都處于開發(fā)者的控制之下。要記住的是,這是處理問題的明確方式。

對于actor系統(tǒng)的初學(xué)者,往往容易在actor中寫入很多的邏輯。隨著對actor模型越來越熟悉,會(huì)更容易地使用分而治之的策略。

figurep1-7.png

分而治之的目的是為了降低風(fēng)險(xiǎn),通過構(gòu)建層次結(jié)構(gòu)的Actor來代理有風(fēng)險(xiǎn)的操作,從而降低影響。

在圖1-7中,我們有A1,B1和C3,C3將一些有風(fēng)險(xiǎn)的行為委托給actor D(D3),葉子節(jié)點(diǎn)用紅色標(biāo)記這些Actor做的是有風(fēng)險(xiǎn)的操作,例如通過網(wǎng)絡(luò)和數(shù)據(jù)庫通訊。有風(fēng)險(xiǎn)是因?yàn)榫W(wǎng)絡(luò)可能中斷,數(shù)據(jù)庫可能宕機(jī),或者其他的因素都可能導(dǎo)致錯(cuò)誤。

通過將風(fēng)險(xiǎn)的行為推給下層工作的Actor,上層的Actor得到了某種程度的保護(hù)。通過Actor的層次結(jié)構(gòu),工作被委托給更加細(xì)粒度的專門的Actor,就像圖中把風(fēng)險(xiǎn)行為推給樹的葉子節(jié)點(diǎn)。

路由和并發(fā)

Akka專注于多線程,多核并發(fā),使我們能輕松處理以前需要手工管理多線程的操作。多線程的事情很容易變復(fù)雜,所以Akka提供了開箱即用的并發(fā)特性,不會(huì)遇到Java和Scala中多線程編程的許多技術(shù)挑戰(zhàn)。


figurep1-8.png

在圖1-8中,我們有Actor A和B,以及作為路由的actor R,R創(chuàng)建了一批工作的actor W,A發(fā)送消息給路由actor R,要求完成某項(xiàng)工作,R實(shí)際并不做這些工作,而是將工作代理給底下的actor W

figurep1-9.png

在圖-9中,當(dāng)actor W在完成A的任務(wù)時(shí),這時(shí)B發(fā)了一個(gè)消息給路由actor R,要求完成一些工作。R會(huì)轉(zhuǎn)發(fā)消息給底下其他的某一個(gè)W,這樣我們就實(shí)現(xiàn)了多線程并發(fā)而不用寫任何代碼。從A和B的視角看,R在同一時(shí)刻做了很多工作,但是R在幕后實(shí)際上是通過代理工作到許多actor W來實(shí)現(xiàn)的。

figurep1-10.png

在圖1-10中,我們再來看看這個(gè)例子中的Akka監(jiān)督策略。假設(shè)A發(fā)送了一個(gè)消息給路由R,路由R再轉(zhuǎn)發(fā)給實(shí)際工作的W,但是W在運(yùn)行過程中出錯(cuò)了。
在常用的“try-catch”方法編程中,捕獲的異常通常是發(fā)送給A。然而在actor系統(tǒng)中,是監(jiān)督者收到這個(gè)異常。因此在這個(gè)場景中是監(jiān)督者R收到了異常,而不是A
這就是超時(shí)機(jī)制起作用的地方了,R發(fā)送一個(gè)響應(yīng)給A說:“這里有一些問題,我無法完成你要求的任務(wù)”。無論如何,A沒有看到異常,作為調(diào)用者無需處理問題。而且作為服務(wù)的消費(fèi)者,最好也不是由它來處理,而是由服務(wù)的提供者來處理。

Actor模型作為Akka的核心,提供了許多強(qiáng)大的內(nèi)置特性來管理并發(fā)和彈性。它展現(xiàn)了一種不同的思維方式,是一種高效且安全的方法構(gòu)建分布式系統(tǒng)的方法。

總結(jié):
? Actors 是消息驅(qū)動(dòng)的,有狀態(tài)的構(gòu)建模塊,模塊間異步傳遞消息。
? 與傳統(tǒng)的同步和阻塞不同,Actors 是輕量的,不阻塞線程
? Actor能創(chuàng)建Actor,使用監(jiān)督層次結(jié)構(gòu)來支持從錯(cuò)誤自愈(彈性)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Actor系統(tǒng)的實(shí)體 在Actor系統(tǒng)中,actor之間具有樹形的監(jiān)管結(jié)構(gòu),并且actor可以跨多個(gè)網(wǎng)絡(luò)節(jié)點(diǎn)進(jìn)行透...
    JasonDing閱讀 3,362評論 2 6
  • 持久化 當(dāng)我們在集群系統(tǒng)中,一臺機(jī)器向另一臺機(jī)器發(fā)送一段數(shù)據(jù),負(fù)責(zé)接收的機(jī)器在接收數(shù)據(jù)前突然宕機(jī),就會(huì)造成數(shù)據(jù)丟失...
    mango_knight閱讀 4,578評論 0 4
  • 前言 一 不得不說的Actor模型 1.1 Actor模型的誕生與發(fā)展 1.2 Actor模型是什么? 1.3 A...
    hedgehog1112閱讀 423評論 0 0
  • 周日,是立春。 劉芬坐在客廳里,望著一如既往臟亂的屋子,有些抓狂。滿眼的書本,袋子,衣服,零食,盤子……, 想著快...
    后知后覺的人閱讀 405評論 5 4
  • 我當(dāng)年讀書的高中,是省重點(diǎn)高中。我的歷史老師,她少有歷史的厚重感,卻能把塵封的歷史講成詩。 某一天臨下課,她用幾分...
    冷小雪閱讀 414評論 7 4