使用Akka的Actor模型和領域驅動設計構建反應式系統

binga 6年前發布 | 21K 次閱讀 領域驅動設計 AKKA

核心要點

  • 面向Actor編程是面向對象編程的一種替代方案;
  • 借助Actor,開發高并發的系統會變得非常容易;
  • Actor并不局限于單個節點上的單個進程,它可以作為分布式集群運行;
  • Actor和Actor模型提供了“反應式”編程所需的所有內容;
  • Actor與領域驅動設計是絕佳的組合。

隨著移動和數據驅動應用的爆發性增長,用戶需要在任何地點實時訪問任何內容。系統的彈性和響應性不再是“最好能有”的特征,而是已經成為重要的業務需求。業務越來越需要從靜態、脆弱的架構轉換為靈活、彈性的系統。

因此,反應式開發得到了迅速地增長。為了支持反應式開發, Actor模型 結合 領域驅動設計 能夠滿足現代彈性的需求。

Actor模型的一些歷史

Actor模型最初是隨著Smalltalk的出現而構思出來的,當時面向對象編程(Object-Oriented Programming,OOP)本身剛剛出現不久。

大約在2003年左右,計算機的核心特性經歷了一個重要的變化,處理器的速度達到了一個頂點。在接下來的近十五年里,時鐘速度是呈線性增長的,而不是像以往那樣以指數級的速度增長。

但是,用戶的需求在持續增長,計算機領域必須要找到某種方式來應對,多核處理器應運而生。計算處理變成了“團隊協作”,效率的提升通過多個核心的通信來實現,而不是傳統的時鐘速度的提升。

這也是線程發揮作用的地方,這個概念要比看上去復雜得多。以某個稀缺資源的簡單計數器為例,比如倉庫中某個貨品的數量或者某個活動的可售門票。在這樣的例子中,可能會有很多請求同時獲取一個或多個倉庫中的貨品或門票。

我們考慮一種常用的實現方式,每個購買請求都對應一個線程。在這種方式中,很可能會有多個并發運行的線程都去調整計數器。為了滿足語義方面的需求,我們的模型必須要確保在同一個時間只能有一個線程去遞減計算器的值。這樣做的原因在于遞減操作涉及到兩個步驟:

  1. 檢查當前的計數器,確保它的值要大于或等于要減少的值;
  2. 遞減計數器。

使用Akka的Actor模型和領域驅動設計構建反應式系統

下面的樣例闡述了這兩個步驟為什么要作為一個整體操作來完成。每個請求代表了購買一個或多個貨品,也可能是購買一張或多張門票。假設有兩個線程并發地調整計數器,該計數器目前的值是5。線程一想要將計數器的值遞減3,而線程二想要將計數器的值遞減4。它們都會檢查當前計數器的值,并且會斷定計數器的值大于要遞減的數量。然后,它們都會繼續運行并遞減計數器的值。最后的結果就是5 - 4 - 3 = -2。這樣的結果會造成貨品的過度分配,違反了特定的業務規則。

防止這種過度分配的一種原生方式就是將檢查和遞減這兩個步驟放到一個原子操作中。將兩個步驟鎖定到一個操作中能夠消除購買已售罄物品的可能性,比如兩個線程同時嘗試購買最后一件商品。如果沒有鎖的話,就有可能多個線程同時斷定計數器的值大于或等于要購買的數量,然后錯誤地遞減計數器,從而導致出現負數值。

每次一個線程的方式有一個潛在的問題,那就是在高度競爭的階段,有可能出現很長的線程隊列,它們都在等待遞減計數器。在現實世界中,類似的例子就是人們排隊等待購買某個活動的門票。

使用Akka的Actor模型和領域驅動設計構建反應式系統

這種方式有個較大的弱點就是可能會造成眾多的阻塞線程,每個線程都在等待輪到它們去執行一個序列化的操作。

如果應用的設計者不小心的話,內在的復雜性有可能會將多核心處理器、多線程的應用變成單線程的應用,或者導致工作線程之間存在高度競爭。

多線程環境的更好方案

Actor模型優雅地解決了這個難題,為真正多線程的應用提供了一個基礎支撐。Actor模型的設計是消息驅動和非阻塞的,吞吐量自然也被考慮了進來。它為開發人員提供了一種簡便的方式來進行多核心編程,不再需要關心復雜難懂的并發。讓我們看一下它是如何運行的。

Actor包含發送者和接收者;設計簡單的消息驅動對象實現異步性。

我們重新回顧一下上面所描述的門票計數器場景,將基于線程的實現替換為Actor。當然,Actor也要在線程中運行,但是Actor只有在有事情可做的時候才會使用線程。在我們的計數器場景中,請求者代表了Customer Actor。門票的數量現在由Actor來維護,它持有當前計數器的狀態。Customer Actor和Tickets Actor在空閑(idle)或沒有事情做的時候(也就是沒有消息要處理)都不會持有線程。

要初始購買操作,Customer Actor需要發送一條buy消息給一個Tickets Actor。在這樣的buy消息中包含了要購買的數量。當Tickets Actor接收到buy消息時,它會校驗購買數量不超過當前剩余的數量。如果購買請求是合法的,數量就會遞減,Tickets Actor會發送一條信息給Customer Actor,表明訂單被成功接受。如果購買數量超出了剩余數量的話,Tickets Actor將會發送給Customer Actor一條消息,表明訂單被拒絕了。Actor模型本身確保處理是按照同步的方式進行的。

在下面的圖中,我們展現了一些Customer Actor,它們各自發送buy消息給Tickets Actor。這些buy消息會在Tickets Actor的收件箱(mailbox)中排隊。

使用Akka的Actor模型和領域驅動設計構建反應式系統

圖3:Customer Actor發送buy消息

Ticket Actor處理每條消息。如下展示的是請求購買五張門票的第一條消息。

使用Akka的Actor模型和領域驅動設計構建反應式系統

圖4:Tickets Actor處理消息

Tickets Actor檢查購買數量沒有超出剩余門票的數量。在當前的情況下,門票數量是15,因此購買請求能夠接受,剩余門票數量會遞減,Tickets Actor還會發送一條消息給發出請求的Customer Actor,表明門票購買成功。

使用Akka的Actor模型和領域驅動設計構建反應式系統

圖5:Tickets Actor處理消息隊列

Tickets Actor會處理其收件箱中的每條消息。需要注意,這里沒有復雜的線程或鎖。這是一個多線程的處理過程,但是Actor系統會管理線程的使用和分配。

在下面的圖中,我們會看到當請求的數量超過剩余值時,Tickets Actor會如何進行處理。這里所展現的是當我們請求兩張門票,但是僅剩一張門票時的情況。Tickets Actor會拒絕這個購買請求并向發起請求的Customer Actor發送一條“sold out”的消息。

使用Akka的Actor模型和領域驅動設計構建反應式系統

圖6:Tickets Actor拒絕購買請求

當然,在線程方面有一定經驗的開發人員會知道,可劃分為兩個階段的行為檢查和門票數量遞減能夠通過同步的操作序列來完成。以在Java中為例,我們可以使用同步的方法或語句來實現。但是,基于Actor的實現不僅在每個Actor中提供了自然的操作同步,而且還能避免大量的線程積壓,防止這些線程等待輪到它們執行同步代碼區域。在門票樣例中,每個Customer Actor會等待響應,此時不會持有線程。這樣所形成的結果就是基于Actor的方案更容易實現,并且會明顯降低系統資源的占用。

Actor:對象的合法繼承者

Actor是對象的自然繼承者,這并不是什么新的理念,事實上也不是那么具有革命性。Smalltalk的發明者Alan Kay定義的很多對象范式(paradigm)依然在使用。他強調消息的重要性,甚至還說對象的內部實現其實是次要的。

盡管Smalltalk最初并不是異步的,但它依然是基于消息的,本質上來講一個對象是通過向另外一個對象發送消息來完成功能的。因此,現代的Actor模型遵循了Alan Kay最早的面向對象設計理念。

如下是Akka Actor系統中一個簡單的Java Actor實現樣例(我們為每個Actor設置了一個唯一的“魔力”序列數字,使用它來闡述狀態)。

public class DemoActor extends AbstractActor {
  private final int magicNumber;
  public DemoActor(int magicNumber) {
    this.magicNumber = magicNumber;
  }
  @Override
  public Receive createReceive() {
    return receiveBuilder()
      .match(Integer.class, i -> {
        getSender().tell(i + magicNumber, getSelf());
      })
      .build();
  }
  public static Props props(int magicNumber) {
    // Akka Props is used for creating Actor instances
    return Props.create(DemoActor.class, () -> new DemoActor(magicNumber));
  }
}

Actor的實現形式為一個類,這個類擴展自Akka的抽象基類。Actor的實現必須要覆蓋一個方法,也就是createReceive方法,該方法負責創建一個消息接收的構建器,定義傳入到Actor實現中的消息對象該如何進行處理。

還要注意這個Actor是有狀態的。Actor的狀態可以非常簡單,就像本例中的魔數一樣,也可以非常復雜。

要創建Actor的實例,我們需要一個ActorSystem。ActorSystem啟動之后,創建Actor一般只需要一行代碼。

ActorSystem system = ActorSystem.create("DemoSystem");
ActorRef demo = system.actorOf(DemoActor.props(42), "demo");

Actor創建操作的返回值是一個actor引用(actor reference),這個actor引用用來給Actor發送消息。

demo.tell(123, ActorRef.noSender());

上面展現了定義、創建運行實例以及給Actor發送消息的基本步驟。當然,實際要做的會比這個簡單例子更多一些,但是在大多數情況下,使用Actor開發系統需要學習如何以Actor系統的形式實現應用和服務,這些Actor之間通過交換異步消息進行交互。

為更好的網絡構建更好的應用

除了內核和線程以外,如今的環境還允許開發人員利用更快速的存儲設備、大量的內存以及高度可伸縮且廣泛連接的設備。這些技術都通過用戶可接受的價格以云托管方案和快速網絡的方式連接在一起。

但是隨著系統越來越按照分布式的方式來實現,延遲的增加是不可避免的。分布式系統會被停機或網絡分區所中斷,這可能是由于一個或多個服務器脫離集群、生成新服務器所導致的延遲造成的。對象模型并不適合處理這種問題。因為每個請求和每個響應都是異步的,所以Actor模型能夠幫助開發人員處理該問題。

借助Actor模型,我們能夠很自然地減少延遲。鑒于此,我們不再預期得到即時的結果,系統只會在需要發送或接收消息的時候做出反應。當探測到延遲降級時,系統會自動做出反應和調整,而不是將系統關閉。

在節點所組成的分布式集群中,每個節點都運行Actor的一個子集,在這樣的環境中,Actor之間通過異步消息進行交互是非常自然的事情。另外,Actor有一項基本的功能,那就是消息的發送者和接收消息的Actor并不一定局限在同一個JVM進程中。Akka最棒的特性之一就是我們可以構建在集群中運行的系統。Akka集群是運行在獨立JVM中的一組節點。從編程的角度來說,將消息發送至另外一個JVM中運行的Actor與將消息發送給本地JVM中的Actor一樣容易。如下面的圖所示,分布在多個集群節點上的Actor可以發送消息給其他集群節點上的Actor。

使用Akka的Actor模型和領域驅動設計構建反應式系統

能夠在集群環境中運行增加了Actor系統在整體架構上的動態性。在一臺服務器、一個進程和一個JVM中運行是一回事兒,在一個跨網絡的JVM集群中運行系統則完全是另外一回事兒。

在單個JVM的場景下,Actor運行在Actor系統之中,JVM要么處于運行中,要么沒有運行。但是在集群中運行的時候,任何一個時間點集群的拓撲結構都可能發生變化。集群節點可能瞬間就能添加進來或移除掉。

從技術上來講,只要有一個節點處于啟動狀態,集群本身就是啟動的。某個節點上的Actor可能會非常高興地與其他節點上的Actor交換信息,然后,沒有任何預警,節點突然就可能會宕機,位于該節點上的Actor也就被移除了。其他的Actor該如何應對這些變化呢?

集群節點的丟失會影響到消息的交換,既會影響消息的發送者也會影響消息的接收者。

對于消息的接收者來說,始終存在預期的消息永遠接收不到的可能性。接收的Actor要將這種情況考慮進去,需要存在一個B計劃。在處理異步消息時,預期的消息可能接收不到是難免的。在大多數場景中,處理傳入消息的丟失并不需要感知到集群的存在。

而另一方面,對于消息的發送者來說,通常要在一定程度上感知到集群的存在。路由器Actor(Router Actor)負責將消息發送到其他Actor的物流事宜,接收消息的Actor可能會以分布式的方式存在于集群之中。路由器Actor接收到消息,但是它自己并不會處理消息。它將消息轉發給一個工作者Actor。這些工作者Actor通常被稱為被路由者(routee)。路由器Actor負責按照一定的路由算法將消息轉發給其他的被路由者Actor。實際的路由算法因情況而異,它要依賴于每個路由器的需求。路由算法的例子包括輪詢(round robin)、隨機或最小收件箱等等。

考慮下圖所示的樣例場景(要記住發送消息的客戶端并不知道接收消息的Actor會如何處理消息)。對于客戶端來說,接收消息的Actor就是一個黑盒。接收消息Actor可能會將工作委托給其他的工作者Actor來完成。在這種情況下,接收消息的Actor就是一個路由器。它將接收到的消息路由給代理Actor,讓它們來完成實際的工作。

使用Akka的Actor模型和領域驅動設計構建反應式系統

在這個樣例場景中,路由器Actor可能需要感知集群的存在,它會將消息路由到集群中分布式節點的Actor上。那么,集群感知意味著什么呢?

集群感知Actor會用到當前集群狀態的組成信息,以便于決定如何將傳入的消息路由到集群中分布式的其他Actor上。集群感知Actor最常見的場景之一就是路由器。集群感知路由器會基于當前集群的狀態決定如何將消息路由至目標Actor。例如,路由器知道分布式集群中被路由的Actor的位置,然后按照分布式工作的算法將消息發送至目標Actor。

Actor模型如何支持反應式系統

正如 反應式宣言(Reactive Manifesto) 所定義的那樣,“反應式是即時響應性的(responsive),反應式是具有彈性的(resilient),反應式是具有適應性的(elastic),反應式是消息驅動的”。本質上來講,消息驅動組件促進了反應式的其他三項特點的實現。

提高系統的響應性

反應式是即時響應的,也就是系統能夠動態適應不斷變化的用戶需求。對于一個反應式系統來說,以請求/響應的方式回應用戶的需求并不少見。如果借助Actor模型來支持反應式編程,開發人員能夠實現非常高的吞吐量。

支持系統的彈性

借助消息傳遞和消息驅動架構提供的功能,我們也能支持彈性。當客戶端Actor發送一條消息給服務器Actor接收者時,客戶端不必處理服務器對象或Actor可能拋出的異常。

請考慮一下典型的面向對象架構,在這種架構中,客戶端發送一條消息或者調用接收者的一個方法,我們需要強迫客戶端處理可能會出現的各種崩潰或拋出的異常。作為回應,客戶端一般會重新拋出或者將異常傳遞給更高層的組件,希望其他人處理它。但是,客戶端并不適合修復服務端的崩潰。

在Actor模型中,尤其是在使用Akka時,會建立一個用于監管的層級結構。當接收傳入消息的過程中出現服務器崩潰或者拋出異常時,不是客戶端來處理崩潰,而是由服務器Actor的父Actor或者負責服務器Actor的對象來進行處理。

父Actor能夠更好地理解子Actor可能會出現的崩潰,因此能夠對其作出反應并重啟該Actor。客戶端只需要知道接收到請求的響應或者沒有接收到響應時分別該如何處理就可以了。如果在一個可接受的時間范圍內,它沒有接收到響應,那么它可以向同一個Actor發送相同的請求,希望得到再次處理。所以(如果正確構建的話)Actor系統是非常有彈性的。

如下是一個樣例,實際展現了Actor的監管。在圖7中,Actor R是一個監管者,它創建了四個工作者Actor。Actors A和B會發送消息給Actor R,請求它執行一些操作。Actor R將工作委托給某一個可用的工作者Actor。

使用Akka的Actor模型和領域驅動設計構建反應式系統

圖7——Actor A的消息會被R委托給工作者Actor

在這個樣例中,工作者Actor遇到了問題并拋出了異常,如圖8所示。異常會被監管者Actor R來處理。監管者Actor會遵循一個定義良好的監管策略,以便于處理工作者的錯誤。監管者可以選擇恢復出現簡單問題的Actor或者重啟該工作者,也可能會將其停止掉,這依賴于問題的嚴重程度和恢復策略。

使用Akka的Actor模型和領域驅動設計構建反應式系統

圖8——工作者Actor拋出了異常

盡管異常會由監管者處理,但是Actor A還在期待收到響應信息。注意,Actor A只是期待會有響應消息,而不是一直在等待該消息。

這種異步消息的交互引入了一些很有意思的動態性。Actor A希望Actor R能夠像預期的那樣,對它的消息做出反應。但是,無法保證Actor A的消息會得到處理或者能夠返回響應信息。這個過程中發生的任何問題都有可能破壞請求和響應的周期。例如,考慮這樣一種情況,Actor A和Actor R運行在不同的節點上,Actor A和Actor R之間的消息發送要穿過一個網絡連接。網絡可能會被關閉,或者運行Actor R的節點可能會出現故障。另外,還有可能要執行的任務失敗了,比如在數據庫操作時,因為網絡故障或服務器停機造成了操作失敗。

鑒于這里缺乏任何保證,在實現Actor A時,有種常見的方式就是它預期會得到兩種可能的結果。第一種結果是當它發送消息給Actor R后,它最終接收到了一條響應消息。還有一種可能的結果就是Actor A會預期得到一條替代消息,這條消息表明沒有接收到預期的響應。如果按照這種方式的話,Actor A會涉及到發送兩條消息:第一條是發送給Actor R的消息,第二條是在未來特定的時間點發送給自己的消息。

使用Akka的Actor模型和領域驅動設計構建反應式系統

圖9——Actor A接收一條超時的消息

在這里所使用的基本策略就是同時存在A計劃和B計劃。A計劃指的是所有的事情都能正常運行。Actor A發送一條消息給Actor R,預期的任務得到執行并且響應消息能夠返回給Actor A。B計劃能夠應對Actor R無法處理請求消息的場景。

擴展系統的適應性

反應式系統需要具有適應性,它們可以根據需要擴展和收縮。真正的反應式設計沒有競爭點或中心化的瓶頸,所以我們可以共享或復制組件,并在它們之間分配輸入。它們通過提供相關的實時性能度量數據,實現預測和反應式伸縮算法。

Actor模型對適應性的支持是通過動態響應用戶活動的高峰和低谷來實現的,在有需要的時候,它會智能地提升性能,并在使用率較低的時候節省能源。消息驅動的特性能夠帶來更大程度的適應性。

適應性需要兩個關鍵要素。第一個就是當負載增加或降低時,能夠有一種機制擴展和收縮處理能力。第二個就是要有一種機制允許在處理能力發生變化的時候,系統對其作出適當的反應。

有很多方式來應對處理能力的擴展和收縮。通常來講,處理能力的變化可以手動或自動進行。手動處理的樣例場景就是為了準備客戶季節性的流量高峰,提前增加處理能力。典型的例子就是黑色星期五(Black Friday)和剁手星期一(Cyber Monday)或者光棍節。自動擴展是很多云廠商所提供的很有用的特性,比如Amazon AWS。

Actor模型以及該模型的實現Akka并沒有提供觸發處理能力調整的機制,但它是一個理想的平臺,能夠借助它來構建當集群拓撲結構發生變化時,做出適當反應的系統。正如前文所述,在Actor級別,可以實現集群感知的Actor,它們專門設計用來應對節點離開或加入集群的場景。在很多場景下,當我們設計和實現Actor系統使其更有彈性的時候,其實我們也為適應性打下了良好的基礎。當你的系統能夠處理分布式節點因為故障而離開集群,并且支持新節點取代故障節點的時候,其實在本質上來說節點因為故障離開或加入集群,這與為了應對用戶的活動而調整可用的處理能力并沒有什么差異。

消息至關重要

正如我前面講到的,Actor模型主要關注直接的異步消息。為了實現這一點,發送者有必要知道接收者的地址,這樣才能將消息發送給接收者。

Actor是無鎖的結構,它們不會共享任何內容。如果三個發送者分別向一個接收者發送消息,接收者會在它的收件箱中對這些消息進行排隊,每次只處理一條消息。因此,接收者不需要在內部使用鎖來保護它的狀態,以防止多線程對狀態的同時操作。接收者不會將它的內部狀態與其他的Actor共享。

Actor模型還允許接收消息的Actor為下一條即將到達的消息做出調整。例如,假設有兩個程序流序列。當第一個序列的發送者發送一條消息給接收者時,接收者對消息做出反應,然后將其自身轉換為另外一種類型的消息監聽者。現在,當第二個序列中的消息發送者發送消息給同一個Actor時,該Actor會在自己的receive代碼塊中使用不同的一組邏輯(當Actor改變狀態時,它可以替換消息的接收邏輯。在Akka文檔中,有一個 這種類型的樣例

用更少的資源做更多的事情

Actor模型幫助我們解決的另外一個主要問題就是用更少的資源做更多的事情。各種規模的系統都能從中受益,從Amazon和Netflix所使用的大型網絡到更小的架構均是如此。Actor模型允許開發人員充分發揮每臺服務器的最大能量,因此很有可能降低集群的規模。

基于Actor的服務可以有多少個Actor呢?五十個?一百個?都可以!基于Actor的系統非常靈活且具有適應性,它們可以支持大量的Actor,甚至能到百萬級別。

在典型的N層架構中,也可以稱為“ 端口與適配器(ports-and-adapters) ”或六邊形架構,存在大量不必要的復雜性,甚至會有偶發的復雜性。Actor模型最大的優勢之一就是它能夠消除很多的復雜性,它會將一組“控制器”適配器置于邊界之上。控制器可以發送消息給領域模型,從而任務委托出去,領域模型進而發布事件。通過這種方式,Actor模型能夠在很大程度上降低網絡復雜性,允許設計者用有限的資源和預算完成更多的事情。

使用領域驅動設計加速業務開發

領域驅動設計(DDD)的本質是在邊界上下文(bounded context)建模一個 通用(ubiquitous)語言 。讓我稍作解釋:考慮將某個特定類型的服務建模為邊界上下文。這個邊界上下文是一個語義邊界,該邊界內的所有的內容(包括領域模型)都有明確的定義,其中還包括一個團隊成員所使用的語言,該語言能夠幫助開發人員理解邊界上下文中每個概念的含義。

接下來就是上下文映射(context-mapping)能夠發揮作用的地方了,上下文映射會為每個邊界上下文如何與其他的上下文對應、團隊關系以及模型如何交互與集成等行為建模。使用上下文映射是非常重要的,因為邊界上下文本身要比很多人在單體架構中所習慣的思維模式小得多。

對于任何企業和開發團隊來說,響應快速變化的新業務方向都是很大的挑戰。在處理這些不斷演化的業務方向時,DDD可以進行必要的知識消化(knowledge crunching)。Actor和消息能夠幫助開發人員快速實現領域模型以應對他們的需求,并且有助于對領域模型形成清晰的理解。

Actor和DDD:完美組合

Alan Kay說過,“Actor模型保留了對象理念更多的好特性”。Kay還說過,“最大的理念是消息”。在創建通用語言的過程中,開發人員可以關注Actor(將其作為對象或組件)、領域模型的元素以及它們之間的消息。

單個反應式服務無法構成完整的服務,反應式服務是來源于系統的。因此開發人員最終要試圖完成的是構建整個系統,而不是單個服務。通過觸發領域事件到其他的邊界上下文或微服務,開發人員可以更容易地實現這一點。

為何Actor對業務更加有益?

Actor可以和DDD非常理想地協作,因為它們都使用通用語言來表述核心業務領域。它們的設計都非常優雅,能夠處理業務故障,不管網絡出現了何種問題都能維護系統的彈性和快速響應。它們幫助開發人員擴展系統以滿足并發的需求,當面臨峰值負載時,進行適應性地擴展,并在流量降低的時候,進行收縮,從而最小化基礎設施占用和硬件需求。這種模型非常適合當今高度分布式、多線程的環境,并且能夠產生遠遠超出服務器能力空間的業務收益。

關于作者

是一位Java Champion、前Java EE專家組成員、JavaLand的創始人,在世界范圍內的Java會議上是享有盛譽的講師,在企業級Java領域頗為知名。他在Lightbend擔任開發人員,讀者可以在推ter上 @myfear 聯系到他。

使用Akka的Actor模型和領域驅動設計構建反應式系統 Hugh McKee  是Lightbend的開發人員。在職業生涯中,他曾經長期構建演化緩慢的應用程序,這些應用無法高效地利用其基礎設施,并且非常脆弱和易于出錯。在開始構建反應式、異步、基于Actor的系統之后,一切都發生了變化。這種全新的構建應用程序的方式震撼了他。按照這種方式還有一個附加的好處,那就是構建應用系統會變得比以往更加有趣。現在,他主要幫助人們探索構建反應式、彈性、適應性和消息驅動應用程序的重要優勢和樂趣。

查看英文原文: Building Reactive Systems Using Akka’s Actor Model and Domain-Driven Design

 

來自:http://www.infoq.com/cn/articles/Reactive-Systems-Akka-Actors-DomainDrivenDesign

 

 本文由用戶 binga 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!