閱讀515 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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://my-sys@host.example.com: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中,一個角色選擇就像產生了一個它的雙胞胎兄弟,而不是從啟動它的角色所在角色樹的根查找。路徑元素中包含兩個點(”..”)可以用來訪問父角色。你可以像下麵的例子一樣向它的兄弟發送一條消息:

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

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

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

它們都能正常的工作。

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

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

1 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”,其下所有角色的人工路徑,這些角色的監管者都是遠程角色引用。

 

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

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

 

最後更新:2017-05-23 16:04:21

  上一篇:go  演講實錄丨黃偉 AI已來,未來已來
  下一篇:go  阿裏雲推出雲上首個支持廣電級非編NAS產品 4K編輯無卡頓