Akka 2.5.11 路由 Routing

當處理到來的消息流時,我們需要一個actor來引導(dǎo)消息路由到目標actor,從而提高消息的分配效率。在Akka中這個 actor就是Router。它所管理的一些目標actor叫做routees

根據(jù)不同的情況需要,Akka提供了幾種路由策略。當然也可以創(chuàng)建自己的路由及策略。

一個簡單的Router

如何使用Router 還有如何管理routees。

Akka提供的路由策略如下:(詳細見下文路由的使用)

akka.routing.RoundRobinRoutingLogic? ?輪詢

akka.routing.RandomRoutingLogic? ? 隨機

akka.routing.SmallestMailboxRoutingLogic? ?空閑

akka.routing.BroadcastRoutingLogic? ?廣播

akka.routing.ScatterGatherFirstCompletedRoutingLogic? ?分散聚集?

akka.routing.TailChoppingRoutingLogic? ? ??尾部斷續(xù)?

akka.routing.ConsistentHashingRoutingLogic? ? 一致性哈希


創(chuàng)建Router Actor

創(chuàng)建router actor 有兩種方式:

? ? ? ? ? ? 1. Pool(池)——routees都是router?的子actor,如果routees終止,router將把它們移除

? ? ? ? ? ? 2.Group(群組)——routees都創(chuàng)建在router的外部,router通過使用actor來選擇將消息發(fā)送到指定路徑,但不監(jiān)管routees是否終止。

Router actor 向 routees 發(fā)送消息,與向普通actor發(fā)送消息一樣通過其ActorRef。Router actor 不會改變消息的發(fā)送人,routees 回復(fù)消息時發(fā)送回原始發(fā)件人,而不是Router actor。

Pool(池)

可以通過配置并使用代碼在配置中獲取的方法來實現(xiàn)? (例如創(chuàng)建一個輪詢Router向5個routees發(fā)送消息)

也可以只使用編程的方式來實現(xiàn)

遠程部署Router

既可以創(chuàng)建本地actor來作為Router,也可以命令Router在任一遠程主機上部署子actor。

需要將路由配置放在RemoteRouterConfig下,在遠程部署的路徑類中要添加akka-remote模塊

發(fā)送者

默認情況下,當一個routee發(fā)送消息,它隱式地設(shè)置自己為發(fā)送者。

sender() ! x // replies will go to this actor

但是通常將routee的父Router作為發(fā)送者更有用處。這樣可以將routees的信息隱藏起來。

sender().tell("reply", context.parent) // replies will go back to parent

sender().!("reply")(context.parent) // alternative syntax (beware of the parens!)

監(jiān)管

在Pool中,routees是Router 的子actor,所以Router也負責監(jiān)管。

可以使用Pool 的supervisorStrategy屬性來配置監(jiān)管策略。如果沒有提供配置,默認策略是“always escalate”(總是上升)。就是錯誤都會上傳到Router的監(jiān)管者進行處理。但是Router的監(jiān)管者會認為是Router本身發(fā)生錯誤,因此會重啟Router,所有的routees也將被重啟,這樣導(dǎo)致監(jiān)管的效率變低。所以我們要指定監(jiān)管策略。

Group(群組)

有時我們需要單獨的創(chuàng)建routees,然后提供一個Router來供其使用??梢酝ㄟ^將routees的路徑傳遞給Router的配置,消息將通過ActorSelection來發(fā)送到這些路徑。

同樣Group像Pool一樣有兩種方法創(chuàng)建。(為三個routee actor創(chuàng)建Router)

編程方式實現(xiàn):


路由的使用

(具體配置見Routing

1.RoundRobinPool RoundRobinGroup

Router對routees使用輪詢機制

2.RandomPool RandomGroup

Router隨機選擇routees發(fā)送消息

3.BalancingPool

嘗試從繁忙的routee重新分配任務(wù)到空閑routee,所有的routee共享一個mailbox

4.SmallestMailboxPool

Router創(chuàng)建的所有routees中誰郵箱中的消息最少發(fā)給誰

5.BroadcastPool BroadcastGroup

廣播的路由器將接收到的消息轉(zhuǎn)發(fā)到它所有的routee。

6.ScatterGatherFirstCompletedPool 和?ScatterGatherFirstCompletedGroup

將消息發(fā)送給所有的routees,然后等待到收到第一個回復(fù),將結(jié)果發(fā)送回原始發(fā)送者。其他的回復(fù)將被丟棄

7.TailChoppingPool 和?TailChoppingGroup

將首先發(fā)送消息到一個隨機挑取的routee,短暫的延遲后發(fā)給第二個routee(從剩余的routee中隨機挑選),以此類推。它等待第一個答復(fù),并將它轉(zhuǎn)回給原始發(fā)送者。其他答復(fù)將被丟棄。

此Router的目標是通過查詢到多個routee來減少延遲,假設(shè)其他的actor可能比第一個actor更快響應(yīng)。

8.ConsistentHashingPool ConsistentHashingGroup

對消息使用一致性哈希(consistent hashing)選擇routee

有三種方式定義哪些數(shù)據(jù)作為一致性哈希鍵

·? ? 你可以定義路由的hashMapping,將傳入的消息映射到它們一致哈希鍵。這使決策對發(fā)送者透明。

·? ? 這些消息可能會實現(xiàn)akka.routing.ConsistentHashingRouter.ConsistentHashable。鍵是消息的一部分,并很方便地與消息定義一起定義。

·? ? 消息可以被包裝在一個akka.routing.ConsistentHashingRouter.ConsistentHashableEnvelope中,來定義哪些數(shù)據(jù)可以用來做一致性哈希。發(fā)送者知道要使用的鍵。


特殊處理的消息

Broadcast消息

用于向Router所有的routee發(fā)送一條消息,不管該Router通常是如何路由消息的。

PoisonPill消息

無論哪個actor收到PosionPill消息都會被停止。但是對于PoisonPill消息Router不會將其傳給routees。但仍然能影響到routees,因為Router停止時它的子actor也會停止,就可能會造成消息未處理。因此我們可以將PoisonPill包裝到Broadcast消息中。這樣Router所管理的所有routees將會處理完消息后再處理PoisonPill并停止。

Kill消息

當Kill消息被發(fā)送到Router,Router將內(nèi)部處理該消息,并且不會將它發(fā)送到其routee。Router將拋出ActorKilledException并失敗,然后Router根據(jù)監(jiān)管的策略,被恢復(fù)、重啟或終止。

Router的子routee也將被暫停,也受Router監(jiān)管的影響,但是獨立在Router外部創(chuàng)建的routee將不會被影響。

Managagement消息

發(fā)送akka.routing.GetRoutees到一個Router actor,使其回送一個包含當前使用routee的akka.routing.Routees消息。

發(fā)送akka.routing.AddRoutee到一個Router?actor會將那個routee添加到其routee集合中。

發(fā)送akka.routing.RemoveRoutee到一個Router?actor將從其routee集合刪除該routee。

發(fā)送akka.routing.AdjustPoolSize到一個Pool (Router?actor)將從其routee集合中添加或刪除該數(shù)目的routee。


動態(tài)改變大小的池

大多數(shù)Pool的routees數(shù)量是固定的,但是可以制定調(diào)整策略來動態(tài)改變routees的數(shù)量

兩種調(diào)整方式(resizer):?默認的ResizerOptimalSizeExploringResizer

Resizer是根據(jù)壓力的大小來調(diào)整的,繁忙的routees 占總數(shù)的百分比高于或低于某個閾值就會進行調(diào)整

OptimalSizeExploringResizer?:將池的大小調(diào)整為最佳大小,來提供最多的消息吞吐量。

它跟蹤每個Pool 的消息吞吐量來定期執(zhí)行以下三個調(diào)整操作。

? ??·? ??如果在一段時間內(nèi)沒有看到所有routees被充分利用的,就縮小規(guī)模。

? ? ·? ??隨機探索附近的池大小,以嘗試收集吞吐量指標。

? ? ·????對附近的池大小進行優(yōu)化(比其他任何附近池的)吞吐量指標更好。


Akka中的路由是如何設(shè)計的

從表面看,Router就像普通的actor,但是它們實際實現(xiàn)是不同的。路由器在收消息和快速發(fā)消息給routee被設(shè)計的極度優(yōu)化。

Router可以通過優(yōu)化原有消息處理pipeline來支持多線程,從而達到更高的吞吐量。通過將路由策略直接嵌入到其ActorRef ,發(fā)送到路由器ActorRef 的消息可以直接被路由到routees,直接跳過了單線程的Router actor。


自定義Router

在你創(chuàng)建自己的Router之前,要考慮到普通的actor性能不如Router actor高,因此你的程序可以接受較低的消息吞吐量。

假設(shè)你想獲得最大的性能,請參考


配置調(diào)度器

為子Pool創(chuàng)建調(diào)度器將從Props中取,調(diào)度器中有描述

為了可以很容易地定義池中routee的調(diào)度器,你可以在配置的部署一節(jié)中定義內(nèi)聯(lián)調(diào)度器。

啟用一個池專用調(diào)度器,你唯一需要做的

Router的“頭”,不能總在相同的調(diào)度器上運行,因為它處理各種各樣不同類型的消息,因此這個“頭”是個特殊的actor,不使用Props驗證的調(diào)度器。但是在RouterConfig中的?routerDispatcher 是標準Router actor默認調(diào)度器,可以在Router 的構(gòu)造器和工廠方法中配置。 即使是自定義的Router也必須要實現(xiàn)默認調(diào)度器。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 持久化 當我們在集群系統(tǒng)中,一臺機器向另一臺機器發(fā)送一段數(shù)據(jù),負責接收的機器在接收數(shù)據(jù)前突然宕機,就會造成數(shù)據(jù)丟失...
    mango_knight閱讀 4,902評論 0 4
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,554評論 19 139
  • Actor系統(tǒng)的實體 在Actor系統(tǒng)中,actor之間具有樹形的監(jiān)管結(jié)構(gòu),并且actor可以跨多個網(wǎng)絡(luò)節(jié)點進行透...
    JasonDing閱讀 3,521評論 2 6
  • 本章描述了Actor如何被識別和定位在于一個分布式Actor系統(tǒng)。這與固有的主管層次一樣是Actor系統(tǒng)的核心內(nèi)容...
    兒哥欠三百首閱讀 2,012評論 0 0
  • 筆者這一周終于學(xué)會了如何把md文件生成report。雖然起步比其他同學(xué)慢了點,但是多試試結(jié)果終究會不一樣的。 先前...
    嘈雜碎碎念閱讀 806評論 0 1

友情鏈接更多精彩內(nèi)容