1. 程式人生 > >AKKA文件(java版)—角色的引用、路徑和地址

AKKA文件(java版)—角色的引用、路徑和地址

2.5 角色的引用、路徑和地址

這一章描述,角色在一個有可能是分散式的角色系統中是如何被識別和定位的。它關係到了角色系統形成的內在監管層級以及角色跨越多個網路節點之間通訊的位置透明化。

上述圖片顯示了角色系統中幾個最重要實體之間的關係,請仔細閱讀。

2.5.1什麼是一個角色引用?

一個角色引用是ActorRef的一個子型別,它的主要目的是為它所代表的角色提供傳送訊息的功能。每個角色可以通過self欄位訪問自己指定(本地)的引用,這個引用包括髮送者引用,預設會發送所有訊息給別的角色。相反的,在訊息處理期間,這個角色可以訪問傳送者引用,通過sender方法來呈現當前的訊息。

這裡提供了幾個基於角色系統配置的不同型別的角色引用:

  1. 角色系統中的純本地引用被配置成不支援網路功能的,這些角色引用傳送的訊息不能通過一個網路傳送到另一個遠端的JVM。
  2. 角色系統中的本地引用在被啟用時,它代表了那些在同一個JVM裡的角色支援網路功能。為了傳送訊息給別的網路節點,這些引用包含了協議和遠端地址資訊。
  3. 這裡有一個用於路由器的本地角色引用的子型別(即角色混合了路由器的特性)。它的邏輯結構和上述的本地引用一樣,有一點不同的是,向它們傳送的訊息會被分發給它們的子角色中的一個。
  4. 遠端角色引用表示了哪個角色可以通過遠端通訊到達,即傳送訊息給它們會透明的序列化訊息,並把它們傳送給遠端的JVM。
  5. 這裡有幾個角色引用的特殊型別,它們代表了角色引用的所有實用目的:
  • PromiseActorRef是Promise的一個特殊代表,它被用於完成一個角色的響應。akka.pattern.ask建立這個角色引用。
  • DeadLetterActorRef是死亡信件服務的預設實現,定義那些Akka路徑中終點是關閉或不存在的訊息。
  • EmptyLocalActorRef是Akka查詢一個不存在的本地角色路徑時返回的:它等同於DeadLetterRef,不過它保留了它的路徑,這樣Akka可以通過網路把它傳送出去,然後可以通過它的路徑和別的已經存在的角色引用進行比較,這樣就能得到一些已經死亡的角色。
  1. 還有一些你可能還沒見過的一次性的內部實現:
  • 有一個角色引用,它並不呈現為一個角色,它只作為一個偽管理員的根部守護者(guardian,下同),我們稱它為“行走在時空泡沫中”。
  • 第一個日誌服務開啟之前,事實上激起角色建立的工具是一個偽造的角色引用,它能接收日誌事件並把它們直接列印到標準輸出中,它就是Logging.
  • StandardOutLogger。

2.5.2什麼是一個角色路徑?

既然角色們在嚴格的層級結構中建立,也就存在有一個角色名稱的惟一序列,這些名稱是遞迴地通過雙親與子女之間的監管關係命名的,一直到角色系統的根 。這個序列可以看成是檔案系統中的資料夾,因此我們採用路徑(path)這樣的名字來關聯它。在一些真實的檔案系統中,它們也叫“符號連結”,即一個角色可以通過不止一條路徑來訪問,其中除了一個涉及到一些從角色的實際監管祖先行列中分離出來的轉換。這些特性會在下面的小節中描述。

一條角色路徑包含一個錨,它可以識別角色系統,後面緊跟著的是路徑元素,從根守護者到指定的角色。路徑元素遍歷角色的名字,用斜槓隔開。

2.5.2.1 角色引用和角色路徑之間有什麼區別?

一個角色引用指定單個角色,並且它的生命週期和角色的生命週期一致;一條角色路徑表示一個名字,它可能被一個角色佔據,並且它沒有生命週期,它不會變成無效狀態。建立一條角色路徑的同時可以不用建立角色,而角色引用則不一樣,它必須建立與之關聯的角色。

注意:這些定義是不支援actorFor的,這就是為什麼棄用actorFor而選用actorSelection的原因之一。

你可以建立一個角色,終止它,然後用相同的角色路徑建立一個新的角色。新建立的角色是另一個新的角色,和終止的角色不是同一個。舊角色的角色引用對於新的角色是無效的。傳送給舊角色引用的訊息不會交付給新的角色,儘管它們有相同的路徑。

2.5.2.2 角色路徑錨

每一個角色路徑都有一個地址元件,描述協議和位置,這樣使得關聯的角色是可達的,接著是從層次結構根部起的角色名稱。例如:

  1. “akka://my-sys/user/service-a/worker1”          // 純本地
  2. “akka.tcp://[email protected]:5678/user/service-b” //遠端

這裡的akka.tcp是2.2版本預設的遠端運輸協議,可以插入別的協議。一個遠端主機如果使用UDP來訪問,可以通過akka.udp。主機和埠部分取決於所使用的傳輸機制,但它必須遵循URI的結構規範。

2.5.2.3 角色的邏輯路徑

通過父代監管者的連結指向的根守護者得到的唯一路徑叫做角色的邏輯路徑。這條路徑完全匹配由祖先建立的角色,所以一旦角色系統的遠端配置(和路徑的地址元件)設定之後它就被完全確定。

2.5.2.4 角色的物理路徑

當角色的邏輯路徑描述一個角色系統內的功能位置的時候,基於配置的遠端部署意味著一個角色可能創建於與它的父角色不同的網路主機上,即在不同的角色系統中。在這種情況下,從根守護者中獲得角色需要遍歷網路,這一操作要付出昂貴的代價。因此,每一個角色也有一個物理路徑,開始於角色實際駐留的角色系統的根守護者。用這個路徑作為傳送者引用,當需要查詢別的角色時,會讓他們直接回復給這個角色,這樣可以最小化由路由帶來的延遲。

重要的一點就是,一個角色的物理路徑不會跨越多個角色系統或虛擬機器。這意味著如果角色的祖先其中有一個是遠端監管,那麼它的邏輯路徑和物理路徑會被分離開。

2.5.3如何獲得角色引用?

有兩種方法來獲得角色的引用:通過建立角色或者查詢,後者通過具體的角色路徑和查詢角色的邏輯層次來建立兩種風格的角色。

2.5.3.1建立角色

一個角色系統通常通過使用ActorSystem.actorOf方法在守護者角色下開始建立角色,然後利用這個方法在已建立的角色下生成一個角色樹。這些方法會返回一個引用給新建立的角色。每一個角色可以直接訪問(通過它的ActorContext)到它的父角色,自己以及子角色的引用。這些引用會被包含在訊息中傳送給別的角色,使它們能夠直接回復。

2.5.3.2通過具體路徑查詢角色

另外,角色引用可以通過ActorSystem.actorSelection這個方法來查詢。被選擇的角色可以與上述角色(審校者注:原文為the selection can be used for communicating with said actor,而本文到此為止僅提到過幾種角色型別和建立角色的方式,尚未提及具體角色,本人認為所謂said actor應是前面提到的幾種型別角色)通訊,而投遞訊息時被選擇的相關角色會被查詢。

為獲得一個被繫結到某個特定角色生命週期的ActorRef,你需要傳送一個訊息(例如內建Identify的訊息)給這個角色並使用角色通過sender()回覆的引用。

注意:棄用actorFor而選用actorSelection的原因是,利用它來獲取角色引用對於本地和遠端的角色表現是不一樣的。例如一個本地角色引用,被指定的Actor需要在查詢之前存在,否則獲得的引用將會是一個EmptyLocalActorRef,即使一個擁有確切路徑的角色在獲得角色引用之後被建立。通過actorFor獲得的遠端角色引用的行為不同,而且將訊息傳送給這樣一個引用,會為了每一條訊息的傳送在遠端系統中通過路徑查詢角色。

絕對路徑 VS 相對路徑

ActorSystem.actorSelection或ActorContext.actorSelection,可在任何角色內部通過context.actorSelection得到該物件的引用。在ActorSystem中,一個角色選擇就像產生了一個它的雙胞胎兄弟,而不是從啟動它的角色所在角色樹的根查詢。路徑元素中包含兩個點(”..”)可以用來訪問父角色。你可以像下面的例子一樣向它的兄弟傳送一條訊息:

context.actorSelection(“../brother”) ! msg

通常情況下也可以通過絕對路徑在上下文中進行查詢:

context.actorSelection(“/user/serviceA”) ! msg

它們都能正常的工作。

2.5.3.3 在角色邏輯層次結構中查詢

既然角色系統建立一個類檔案系統層次結構,通過某些方式由Unix shell支援的路徑匹配方式也是有可行的:你可以用萬用字元(“*”和“?”)來替換路徑名稱來表示選項,它可以匹配0個或更多的角色。因為結果不是單個的角色引用,它有一個不同的ActorSelection型別,並且不支援ActorRef的全套操作。選擇集可以通過ActorSystem.actorSelection和ActorContext.actorSelection來制定,並支援傳送訊息:

context.actorSelection(“../*”) ! msg

上述程式碼會給當前角色和所有的兄弟角色傳送msg。至於通過actorFor來獲得引用,為了執行訊息傳送的功能,需要完成監管層級結構的遍歷。角色集合的具體匹配可能會改變,即使一個訊息已經在傳送給接收者的途中,監控一個選擇集的現場變化是不可能的。為了解決傳送請求與收集所有應答的不確定性,需要提取出傳送者引用,然後監控發現的所有具體角色。這個問題將會在未來的版本中得到改善。

概括:actorOf VS actorSelection VS actorFor

注意:上述章節內容可以概括如下,這樣有助於記憶:

  1. actorOf只能建立一個新的角色,當這個方法被呼叫的時候(可能是任何的角色或角色系統),它會建立一個上下文的直接子角色。
  2. actorSelection只能在投遞訊息的時候查詢已經存在的角色,也就是說選擇集被建立時,既不能建立角色也不能驗證當角色的存在性。
  3. actorFor(已被actorSelection取代)只能查詢一個已經存在的角色,不能建立角色。

2.5.4 角色引用和路徑等價

ActorRef的等價性體現瞭如下意圖,即ActorRef與目標角色的化身(審校者注:原文為incarnation,意思應該是角色的實際功能、內容、引用等意思,下同)相一致。當兩個角色的引用有相同的路徑並指向相同的角色化身的時候就被認為是等價的。一個引用指向一個終止的角色不等價於指向另一個有相同路徑的角色(重建)。注意,由於故障而重啟的角色跟之前的是同一個,即重啟對於ActorRef的使用者來說是不可見的。

通過actorFor獲得的遠端角色引用不包括底層角色的完整資訊,因此這些引用不等價於通過actorOf,sender或context.self獲得的引用。因此actorFor被棄用,而被actorSelection代替。

如果你需要在一個集合中跟蹤角色引用,並且不關心角色的真正化身,你可以用ActorPath作為鍵,因為在比較角色路徑的時候,目標角色的標識不是要考慮的因素。

2.5.5 重複使用角色路徑

當一個角色終止,它的引用會指向一個死信郵箱,DeathWatch會發布它最終的轉換,通常不再希望起死回生(因為角色的生命週期不允許這樣)。但它後面可能會建立一個路徑完全相同的角色——只是由於在沒有保留已經有效建立的所有角色的情況下無法執行相反的操作——這不是好的實踐:通過actorFor獲得的遠端角色,在死亡後,又突然又開始工作,然而在這個轉換和其它任何事件之間的順序沒有任何擔保,因此該路徑的新角色可能會接收到傳送給以前角色的資訊。

這可能是在非常特殊情況下的正確的事情,如果恰恰是角色監管人的話,就要去限制處理,因為它是唯一一個可以可靠檢測正確注消命名的角色,一旦它出問題,之前新建立的子角色都會失敗。

當被檢測者不得不在特定路徑上例項化的時候,在測試期間也可能要求這樣(審校者注:此處應指重複使用角色路徑)在這種情況下,最好去模擬它的監管人,這樣它就可以在測試過程中把終止資訊投遞給合適的節點,使得後者能夠等待名字正確的取消。

2.5.6 遠端部署的相互影響

當一個角色建立子角色,角色系統的釋出者會決定是否把新的角色放在同一個JVM或另一個節點上。第二點,角色的建立會在不同的JVM之間觸發一個網路連線,從而包含在不同的角色系統中。遠端系統會把新的角色放置在一個指定的路徑下,新角色的監管者會是一個遠端角色引用(表示建立它的角色)。在這個情況下,context.parent(監管者引用)和context.path.parent(這個角色路徑中的父節點)不是同一個角色。然而,在監管者內部查詢子角色的名字,會在遠端節點上找到它,本地僅保持邏輯結構,例如給未定(審校者注:原文為resolved actor)角色引用傳送訊息。

2.5.7 地址部分用來幹什麼?

當在網路中傳送一個角色引用,它通過路徑來表示。因此,該路徑必須充分編碼,把底層角色需要的所有資訊傳送給它。這一點通過如下方式實現:通過把編碼協議、主機和埠作為路徑字串的地址部分。當角色系統從一個遠端節點接收到一個角色路徑,它會檢查該路徑地址是否匹配本角色系統,如果匹配本角色系統,它被解析為本地角色引用。否則,它就是一個遠端角色引用的表示。

2.5.8 角色路徑的頂級作用域

在路徑層次結構的底部有一個根部守護者,在它上面可以找到所有其它的角色;它用”/”來表示。下一個等級由如下列表所示組成:

  1. “/user”是所有使用者建立最高等級角色的守護者角色;通過ActorSystem.actorOf來建立。
  2. “/system”是所有系統建立最高等級角色的守護者角色,例如日誌監聽器或者在角色系統啟動時通過配置自動部署的角色。
  3. “/deadLetters”是死信角色,所有傳送給已停止的或不存在的角色的訊息都被重新路由到此處(以盡力而為原則,訊息也有可能在本地JVM中丟失)。
  4. “/temp”是所有短命的系統建立角色的守護者,例如那些用於實現ActorRef.ask的角色。
  5. “/remote”,其下所有角色的人工路徑,這些角色的監管者都是遠端角色引用。

為角色構建名稱空間的需要,是源於一個非常簡單的中心設計目標:在層次結構中萬物皆角色,以及所有的角色以相同的方式運作。因此你不僅僅可以查詢你建立的角色,你還可以查詢系統守護者並給它傳送訊息(在這種情況下它會踏實的丟棄)。這個強大的原則,意味著沒有奇怪的東西需要去記住,它使整個系統更加的統一和一致。

如果你想要了解更多關於角色系統最高等級結構的知識,請檢視頂級監管者