Distributed Publish Subscribe in Cluster
通過(guò)了解Akka集群后,我們可能會(huì)產(chǎn)生兩個(gè)問(wèn)題
如果我們要發(fā)送消息到某個(gè)actor但是我們不知道它在哪個(gè)節(jié)點(diǎn)運(yùn)行掌测,該如何發(fā)送锐想?
如果我們要給訂閱某種Topic的所有actor發(fā)送消息莫换,該如何發(fā)送?
于是Akka提供了一個(gè)中介actor:
akka.cluster.pubsub.DistributedPubSubMediator
它在所有的節(jié)點(diǎn)上啟動(dòng)陪竿,用來(lái)管理actor引用的注冊(cè)表(比如灭忠,將actor的id與其actorRef對(duì)應(yīng)存入Map中 )。而且這些注冊(cè)表是具有最終一致性肥败,當(dāng)某個(gè)節(jié)點(diǎn)發(fā)生變化趾浅,這個(gè)節(jié)點(diǎn)上的mediator不會(huì)立即通知其他節(jié)點(diǎn)愕提,而是將變化的信息進(jìn)行版本化,幾秒后通過(guò)gossip 協(xié)議將變化的增量 復(fù)制到其他節(jié)點(diǎn)的mediator皿哨。
因此你就可以通過(guò)任意一個(gè)節(jié)點(diǎn)上的mediator 來(lái)向任何其他節(jié)點(diǎn)的actor通信
對(duì)于一開(kāi)始的兩個(gè)問(wèn)題浅侨,mediator有兩種消息傳遞模式:Publish與Send,下面將介紹具體的實(shí)現(xiàn)方法和過(guò)程证膨。
Publish
這是一種 Pub/Sub 模式(如聊天室)如输,
通過(guò)DistributedPubSubMediator.Subscribe方法來(lái)將訂閱這個(gè)主題的actor注冊(cè)到本地的mediator中。
通過(guò) DistributedPubSubMediator.SubscribeAck ? 和DistributedPubSubMediator.UnSubscribeAck 確認(rèn)是否訂閱成功央勒,一段時(shí)間后會(huì)將該訂閱變化復(fù)制到其他節(jié)點(diǎn)的mediator
最后我們向本地的mediator發(fā)送DistributedPubSubMediator.Publish就可以將消息發(fā)布給所有訂閱的actor
如果actor被終止不见,它將在訂閱的注冊(cè)表中被自動(dòng)移除。
actor也可以用group id 來(lái)進(jìn)行訂閱崔步,發(fā)布的這個(gè)主題的消息就會(huì)向每個(gè)group中隨機(jī)選一個(gè)actor發(fā)送稳吮。如果恰好訂閱消息的都是同一個(gè)group 的actor。那么mediator只需要發(fā)送到其中一個(gè)actor就可以刷晋。
使用sendOneMessageToEachGroup? (true/false)可以設(shè)置是否將消息發(fā)送給使用group id訂閱的actor盖高。
Send
則是一個(gè) point-to-point 模式(例如 私聊),每個(gè)消息都會(huì)投遞到一個(gè)目的地眼虱,即使你不知道目的地在哪里喻奥。
發(fā)送的消息會(huì)通過(guò)一個(gè)匹配路徑(因?yàn)椴恢滥康牡卦谀模栽撀窂讲粠в械刂沸畔ⅲ﹣?lái)發(fā)給mediator捏悬。節(jié)點(diǎn)中的每個(gè)actor通過(guò)DistributedPubSubMediator.Put?將其ActorRef注冊(cè)到本地的mediator中撞蚕,所以在本地actor system中路徑是唯一的,通過(guò)path關(guān)鍵字即可找到目的actor过牙。
換句話說(shuō)甥厦,匹配路徑(path)=邏輯路徑,地址信息(address)=物理路徑寇钉。mediator 通過(guò)將帶有邏輯路徑的消息廣播給各個(gè)節(jié)點(diǎn)actor system刀疙。因?yàn)樵诿總€(gè)actor system中actor 的路徑是唯一的,所以消息只需要知道actor的邏輯路徑就可以找到相應(yīng)的actor來(lái)發(fā)送消息扫倡。
如果有多個(gè)actor與path匹配(具有相同path的actor可以在不同的節(jié)點(diǎn)上注冊(cè))谦秧,將使用RoutingLogic (默認(rèn)隨機(jī))發(fā)送到其中一個(gè)。(可以設(shè)置本地偏好撵溃,優(yōu)先選擇本地的mediator進(jìn)行發(fā)送)
用DistributedPubSubMediator.Send發(fā)給mediator帶有path的消息
同樣如果某個(gè)actor被終止疚鲤,它將會(huì)在注冊(cè)表中自動(dòng)刪除。
如果DistributedPubSubMediator.SendToAll 缘挑,可以實(shí)現(xiàn)消息廣播集歇,將消息發(fā)給所有匹配路徑的actor
實(shí)現(xiàn)上面的兩種模式都是通過(guò)mediator擴(kuò)展DistributedPubSub 來(lái)實(shí)現(xiàn),當(dāng)然mediator也可以是一個(gè)普通的actor语淘。
akka.extensions = ["akka.cluster.pubsub.DistributedPubSub"]
在分布式發(fā)布訂閱模式中只保證at-most-once delivery 诲宇,因此消息可能會(huì)丟失际歼。
如果想要at-least-once投遞保證,推薦Kafka Akka Streams integration
依賴
sbt:
"com.typesafe.akka" %% "akka-cluster-tools" % "2.4.16"
maven:??