為什么企業(yè)級軟件難以開發(fā)
??在介紹響應(yīng)式編程技術(shù)會使軟件開發(fā)工作變得簡單之前巾遭,讓我們先了解一下開發(fā)企業(yè)級軟件為何如此之難巧鸭。當(dāng)然蛹批,你可能在開發(fā)企業(yè)級軟件時遇到過各種難題衙荐,如需要經(jīng)常使用的數(shù)據(jù)庫出問題瓶埋、應(yīng)用程序服務(wù)器拖慢了你開發(fā)的軟件的運行速度希柿,或者更為嚴(yán)重的情況,你使用的編程語言帶來了問題养筒。這些問題是普遍存在的曾撤。
??根據(jù)領(lǐng)域驅(qū)動設(shè)計(DDD)實踐,使用端口和適配器(也稱為六邊形)架構(gòu)闽颇,可以簡化開發(fā)企業(yè)級軟件的工作盾戴。要實現(xiàn)完整的企業(yè)級應(yīng)用程序,必須考慮架構(gòu)兵多、設(shè)計尖啡、配置、實現(xiàn)和組件的詳細部署工作剩膘,如圖所示
??事實上衅斩,即使對于大多數(shù)資深架構(gòu)師和開發(fā)者來說,這也是一項需要花費數(shù)個月才能完成的工作怠褐,更何況那些初中級開發(fā)者呢畏梆?將這項工作交給初中級開發(fā)者完成,你是否會放心奈懒?將這樣復(fù)雜的工作交給初中級開發(fā)者來做顯然是有風(fēng)險的奠涌。每位開發(fā)者都需要從頭至尾了解并熟練掌握的工作的數(shù)量是驚人的。
領(lǐng)域事件
??持久存儲的領(lǐng)域事件代表了業(yè)務(wù)領(lǐng)域中發(fā)生的事情磷杏。它們能夠傳輸領(lǐng)域模型中出現(xiàn)過的情況溜畅,它們的信息量很大,而且只要你處理領(lǐng)域事件极祸,就需要用到它們慈格。領(lǐng)域事件僅是一種結(jié)果。每個領(lǐng)域事件都是作為在領(lǐng)域中執(zhí)行的某個命令的輸出結(jié)果而被創(chuàng)建的遥金。在命令模式(GoF)中浴捆,應(yīng)用程序中的對象表達了用戶或應(yīng)用程序的目的,從而實現(xiàn)業(yè)務(wù)操作稿械。一旦該目的被實現(xiàn)选泻,那么獲得的結(jié)果就是領(lǐng)域事件。如果你向系統(tǒng)(如瀏覽器、智能手機滔金、云計算色解、消息系統(tǒng)等)輸入命令,就會獲得Actor對象和領(lǐng)域事件餐茵。因而科阎,你最終實現(xiàn)的是“響應(yīng)式堆棧”和Actor模型忿族,如下圖所示锣笨。
什么是Actor模型?
??使Actor對象能夠像第一類值一樣被處理道批,并通過消息傳遞功能加強了Actor對象之間的通信操作错英。Actor是一種無鎖的并發(fā)代理對象,而且執(zhí)行它們的線程通常不會被阻塞隆豹,所以使用Actor對象設(shè)計的應(yīng)用程序能夠完美地利用系統(tǒng)的基礎(chǔ)線程資源椭岩。
Actor模型應(yīng)用程序僅需要關(guān)注下列幾個重要概念。
- 接收哪些類型的消息一一命令和/或事件璃赡?發(fā)出哪些類型的消息一一命令和/或事件判哥?
- 為了回應(yīng)接收到的消息,應(yīng)用程序應(yīng)對其當(dāng)前狀態(tài)做出哪些改變碉考?
響應(yīng)式應(yīng)用程序簡介
??定義:響應(yīng)式應(yīng)用程序具有較好的響應(yīng)性塌计、韌性和靈活性,而且應(yīng)該是由消息驅(qū)動的侯谁,從而能夠使用戶獲得實時操作的感覺锌仅。
響應(yīng)式應(yīng)用程序的目的:
- 對用戶和其他應(yīng)用程序組件做出回應(yīng):響應(yīng)式應(yīng)用程序的響應(yīng)時間應(yīng)符合或高于非功能性需求。
- 對失效情況做出回應(yīng):響應(yīng)式軟件應(yīng)通過使韌性成為本身的重要特征墙贱,從而獲得恢復(fù)任何類型組件的能力热芹。
- 對加載操作做出回應(yīng):響應(yīng)式程序應(yīng)通過以獨立方式管理離散資源(如系統(tǒng)實體),努力避免出現(xiàn)資源爭用情況惨撇。這種設(shè)計方式能夠使系統(tǒng)擁有韌性和高吞吐量剿吻。
- 對消息做出回應(yīng):響應(yīng)式應(yīng)用程序的基礎(chǔ)設(shè)計思想是通過其核心的異步消息傳遞模式,實現(xiàn)消息驅(qū)動模式串纺。
響應(yīng)式應(yīng)用程序的關(guān)鍵特性
響應(yīng)性
??響應(yīng)式應(yīng)用程序必須像用戶界面的功能需求一樣具備響應(yīng)性。這些功能需求包括實時用戶界面的功能需求椰棘,實時用戶界面允許多個用戶同時執(zhí)行重疊的編輯操作纺棺。而且,即使出現(xiàn)故障邪狞,響應(yīng)性也必須仍然存在祷蝌。通過被觀察者和觀察者模型可以實現(xiàn)響應(yīng)性;被觀察者和觀察者模型是指當(dāng)系統(tǒng)發(fā)生改變時帆卓,系統(tǒng)有能力通知對該改變感興趣的一方或多方巨朦。該模型需要使用能夠根據(jù)用戶消耗資源的數(shù)量進行調(diào)整的事件流和可視化模型米丘,而不是使用根據(jù)業(yè)務(wù)操作調(diào)整的系統(tǒng)模型。
韌性
??應(yīng)用程序擁有故障恢復(fù)的能力糊啡。響應(yīng)式應(yīng)用程序通過監(jiān)督較低層級的響應(yīng)式組件來預(yù)測故障情況拄查。這種模式擁有異步操作邊界,而且能夠?qū)⒐收暇唧w化為消息棚蓄,并通過重要的專用消息通道發(fā)送[Read-Write]堕扶。監(jiān)督者會被賦予對被監(jiān)督組件的故障做出回應(yīng)的能力。正確的回應(yīng)可能是徹底停止故障組件梭依,也可能是重新啟動故障組件稍算,還可能是通過忽略故障原因來命令故障組件繼續(xù)運行。監(jiān)督者甚至可以選擇使本身失效役拴,從而使它的監(jiān)督者能夠選擇上述恢復(fù)操作之一糊探。
??這種方式傾向于將故障隔離在它們出現(xiàn)的應(yīng)用程序區(qū)域中,從而使程序員能夠以對癥下藥的方式處理它們河闰。同時這還能夠保護應(yīng)用程序的其他組成部分科平,避免故障以連鎖反應(yīng)的方式影響一個或多個不相關(guān)的應(yīng)用程序區(qū)域。
靈活性
??每當(dāng)我們思考可伸縮性時淤击,總是會橫向或縱向擴展思考范圍匠抗。縱向可伸縮性可以通過添加擁有更多中央處理器(CPU)的高性能計算機實現(xiàn)污抬,每臺計算機都擁有多核處理器(如IntelXeon Phi處理器)和大量的內(nèi)存汞贸。橫向可伸縮性可以通過添加多臺提供日常服務(wù)的服務(wù)器實現(xiàn),每臺服務(wù)器都應(yīng)擁有中等性能的CPU(如一塊或兩塊Intel i7 Quad Core 4700HQ處理器)印机。
??當(dāng)然矢腻,為了滿足特定的可伸縮性需求,也可以同時使用這兩種擴展方式射赛。但從實踐的觀點看多柑,靈活性比可伸縮性更為重要,因為靈活性還意味著通過調(diào)整滿足當(dāng)前應(yīng)用程序的需求楣责。也就是說竣灌,可能需要在非高峰時間通過調(diào)整使用較少的計算資源。不論增加計算資源還是減少計算資源秆麸,你編寫的軟件都應(yīng)該全天候提供與預(yù)期相符的響應(yīng)性初嘹。靈活性能夠提供這項支持,因為靈活性意味著根據(jù)需求進行調(diào)整沮趣,這種調(diào)整方式是響應(yīng)性的核心屯烦。
??響應(yīng)式組件的消息驅(qū)動特性和它們的位置透明性都為根據(jù)需求調(diào)整應(yīng)用程序提供了幫助,即實現(xiàn)了應(yīng)用程序的靈活性。
消息驅(qū)動
??系統(tǒng)組件僅會在收到消息時做出回應(yīng)驻龟,所以系統(tǒng)能夠使用可用線程運行應(yīng)用程序中必須立刻對消息做出回應(yīng)温眉,當(dāng)前沒有正在對消息做出回應(yīng)的組件不會占用寶貴的CPU資源。消息的類型包括命令消息翁狐、文檔消息和事件消息类溢。響應(yīng)式應(yīng)用程序中的組件會通過異步消息傳遞模式,接收其他組件發(fā)送的消息谴蔑,所以能夠自然而然地降低各種組件之間的接口和時間耦合性豌骏。響應(yīng)式組件能夠選擇以獨立方式對每條消息做出回應(yīng)的方式,所以它們能夠做好接收預(yù)期內(nèi)消息的準(zhǔn)備工作隐锭。這就進一步降低了發(fā)送消息組件和接收消息組件接口的耦合性窃躲,因為客戶端無須知道發(fā)送消息的次序。響應(yīng)式組件本身是小型的類似原子的單元钦睡,而且它們在同一時刻僅會對一條異步消息做出回應(yīng)蒂窒,所以它們能夠排除所有鎖策略。
企業(yè)級應(yīng)用程序
??也許你所在的企業(yè)項目正處在項目的初始階段荞怒。使用“普通”企業(yè)級軟件開發(fā)工具可能已經(jīng)獲取了一些成果洒琢,但為了達到策略應(yīng)用程序的目標(biāo),還必須進一步擴大這些成果褐桌∷ヒ郑可以考慮使用Actor型來滿足剛性和之前看起來遙不可及的需求。除了性能和可伸縮性需求外荧嵌,還需要創(chuàng)建軟件模型呛踊,以便反映業(yè)務(wù)預(yù)測的心智模型。領(lǐng)域驅(qū)動設(shè)計(DDD)就是專門用于支持SIS(DDD)開發(fā)的啦撮。
??此外谭网,當(dāng)你面對新的企業(yè)策略挑戰(zhàn)時,必定需要整合企業(yè)中已經(jīng)存在的系統(tǒng)赃春。開發(fā)企業(yè)策略解決方案和整合各種企業(yè)系統(tǒng)工作中的一個要點是對工具的選擇愉择。通常,架構(gòu)師會選擇不使任何人失去工作的解決方案织中。這些解決方案通常是膨脹的锥涕、緩慢的、不具備可伸縮性的狭吼、無彈性的并且昂貴的站楚。當(dāng)前這些常見的解決方案已經(jīng)受到了挑戰(zhàn),而你的目標(biāo)就是在這類膨脹的解決方案中搏嗡,尋找精煉的、成本效益高的處理方式。
了解Actor模型
Actor是一種計算實體采盒,它會對收到的消息做出回應(yīng)旧乞,并且可以做下列事情:
- 向其他Actor對象發(fā)送一定數(shù)量的消息。
- 創(chuàng)建一定數(shù)量的新Actor對象磅氨,設(shè)定對下一條消息做出的回應(yīng)方式尺栖。
??執(zhí)行這些操作的次序不分先后,而且可以通過并行方式執(zhí)行它們烦租。在功能齊全的Actor系統(tǒng)中延赌,所有事物都是Actor對象。這意味著我們通常使用的基本數(shù)據(jù)類型(如字符串和整型)都是Actor對象叉橱。最實用的模式是設(shè)計一種將Actor對象用作特殊類型系統(tǒng)組件的Actor系統(tǒng)挫以。在這種系統(tǒng)中,Actor對象的尺寸比整型值大窃祝,但也不會比整型值的尺寸超出太多掐松。要確定Actor對象的適當(dāng)尺寸,可將它們視為專門化的應(yīng)用服務(wù)粪小,如單個的領(lǐng)域模型實體或小型的領(lǐng)域模型集合
Actor系統(tǒng)和Actor對象具有下列基本特點
- 直接通過異步消息傳遞方式進行通信:如果Actor對象A1要向Actor對象A2發(fā)送消息M1大磺,那么Actor對象A1就必須知道Actor對象A2的地址。如果Actor對象A1知道Actor對象A2的地址探膊,那么它就能夠直接向Actor對象A2發(fā)送消息M1杠愧,但Actor對象A2會使用獨立線程接收和處理消息M1。換言之逞壁,消息M1是通過異步方式被發(fā)送給Actor對象A2的流济。實際上,在發(fā)送者Actor對象和接收者Actor對象之間還存在一個間接處理層——郵箱(消息緩存單元)猾担。
- 狀態(tài)機:Actor模型支持有限狀態(tài)機袭灯。當(dāng)Actor對象轉(zhuǎn)換為某個預(yù)設(shè)狀態(tài)時,就能夠改變對未來接收到的信息的處理模式绑嘹。通過變?yōu)榱硪环N消息處理器稽荧,Actor對象就成了一種有限狀態(tài)機。
- 無共享:一個Actor對象不會與其他Actor對象或相關(guān)組件共享可變狀態(tài)工腋。
- 無鎖的并發(fā)處理方式:因為Actor對象不會共享它們的可變狀態(tài)姨丈,而且它們在同一時刻僅會接收一條消息,所以在對消息做出回應(yīng)前擅腰,Actor對象永遠都不需要嘗試鎖定它們的狀態(tài)蟋恬。
- 并行性:并發(fā)處理方式和并行處理方式是不同的概念。并發(fā)處理方式是指多個計算操作同時出現(xiàn)趁冈。并行處理方式是指以并發(fā)處理方式完成單個目標(biāo)歼争。并行性是通過將單個的復(fù)雜處理過程拆分成較小的任務(wù)并以并發(fā)處理方式執(zhí)行它們實現(xiàn)的拜马。當(dāng)?shù)燃壿^高的Actor對象能夠?qū)⒍鄠€任務(wù)分派給多個下級Actor對象,或者任務(wù)中含有復(fù)雜的處理層級時沐绒,就適合通過Actor模型使用并行處理方式俩莽。
- Actor對象的系統(tǒng)性:單個Actor對象不具備并行性。Actor對象的量級非常輕乔遮,因此在單個系統(tǒng)中創(chuàng)建許多Actor對象是受推薦的處理方式扮超。任何問題都可以通過添加Actor對象來解決。
Action擴展特性(Akka系統(tǒng))
- 位置透明性:使用抽象引用代表Actor對象的地址蹋肮。如果Actor對象A1獲得了Actor對象A2的引用出刷,Actor對象A1就能夠向Actor對象A2發(fā)送消息。提供支持的Actor系統(tǒng)會負責(zé)處理傳送消息的操作坯辩,不論Actor對象A2是位于本地Actor系統(tǒng)還是位于遠程Actor系統(tǒng)中馁龟。
- 監(jiān)督:在Actor對象之間建立依賴關(guān)系,父Actor對象監(jiān)督子(下級)Actor對象濒翻。當(dāng)監(jiān)督者Actor對象向下級Actor對象分派任務(wù)時屁柏,就必須對這些下級Actor對象出現(xiàn)的失效情況做出回應(yīng)。合法的回應(yīng)包括繼續(xù)運行有送、重啟和停止下級Actor對象淌喻。監(jiān)督者還可以通過使本身失效從而使失效情況升級,這會將失效控制權(quán)上交給監(jiān)督者的父對象(監(jiān)督者的監(jiān)督者)雀摘。監(jiān)督機制適于在并行處理方式中使用裸删,在該方式中監(jiān)督者會將多個任務(wù)分派給多個下級對象,從而形成任務(wù)處理層級阵赠。
- Future/Promise對象:這兩種對象提供了接收異步操作結(jié)果的手段涯塔,不論該結(jié)果是代表異步操作成功完成還是異步操作出現(xiàn)失效情況。為了管理接收到的結(jié)果清蚀,系統(tǒng)需要使用特殊的Actor對象(如Future和Promise)匕荸。擁有Future對象的組件可以選擇以等待/阻塞方式接收結(jié)果,也可以選擇以異步方式接收結(jié)果枷邪。
管理不確定性系統(tǒng)
??什么是不確定性榛搔,為什么我們要關(guān)心它呢?在應(yīng)用程序開發(fā)過程中东揣,不確定性系統(tǒng)是指當(dāng)使用相同的輸入數(shù)據(jù)多次執(zhí)行程序時践惑,會輸出不同結(jié)果的系統(tǒng)。事件驅(qū)動的響應(yīng)式應(yīng)用程序天生就具有不確定性嘶卧,實際上尔觉,不應(yīng)將不確定性和不可靠混為一談,只要你了解了應(yīng)用程序產(chǎn)生不確定輸出結(jié)果的情況芥吟,就不必過于擔(dān)心程序的不確定性侦铜。具有天生不確定性的是由事件驅(qū)動的架構(gòu)专甩,而Actor模型只不過恰好是一種由事件驅(qū)動的架構(gòu)。而且钉稍,通過引入Actor對象(Actor對象本身是一種具有原子確定性的單元)配深,Actor 模型還能夠幫助我們推導(dǎo)天生具有不確定性的并發(fā)業(yè)務(wù)系統(tǒng)。因此嫁盲,真正的決策點是使用無法伸縮的單線程架構(gòu)設(shè)計程序,還是使用可管理的烈掠、多線程的羞秤、由事件驅(qū)動的架構(gòu)設(shè)計程序。
對象性能模型
Actor對象只能根據(jù)發(fā)送消息才能交互左敌●埃可通過下列方式獲得引用。
- 初始情況:Actor對象A可能一開始就已經(jīng)擁有Actor對象B的引用矫限。
- 父子關(guān)系:當(dāng)Actor對象A創(chuàng)建了Actor對象B后哺哼,Actor對象A立刻就獲得了Actor對象B的唯一引用。
- 贈予:當(dāng)Actor對象A創(chuàng)建了Actor對象B后叼风,Actor對象A可以將Actor對象B的引用贈予其他Actor對象取董。
- 介紹:如果Actor對象A擁有Actor對象B和Actor對象C的引用,那么Actor對象A可以通過發(fā)送消息使Actor對象B獲得Actor對象C的引用无宿。
??Actor對象B可以保留該引用并在將來使用該引用茵汰。
Actor模型的明晰性
??利用Actor模型可以大幅度簡化企業(yè)級應(yīng)用程序。領(lǐng)域驅(qū)動設(shè)計(DDD)的主要目標(biāo)之一孽鸡,是在軟件模型(DDD)中使業(yè)務(wù)概念變得明確和清晰蹂午。另一方面,精簡的架構(gòu)僅含有用戶界面和清晰的軟件模型彬碱。據(jù)此甚至能夠推斷出用戶界面也是軟件模型的組成部分豆胸,因為它反映和表現(xiàn)了業(yè)務(wù)專家的心智模型(SIS),通過這種方式幫助用戶做出重要決策巷疼。下圖進一步突出了軟件模型具有明晰性的重要性晚胡。指定消息的接收者是明確的,不論這條消息是命令消息還是事件消息皮迟。