skynet:cluster
skynet跟mq扮演的角色類似,每個skynet進程維護了一個MQ,會dispatch msg到每個skynet_context的私有mq。有skynet就沒必要再在自己項目里引入MQ了。
skynet 支持兩種集群模式。
master/slave 模式(局域網)
當單臺機器的處理能力達到極限后,可以考慮通過內置的 master/slave 機制來擴展。具體的配置方法見?Config?。
集群服務用到的配置項:
- cluster?它決定了集群配置文件的路徑。
- standalone?如果把這個 skynet 進程作為主進程啟動(skynet 可以由分布在多臺機器上的多個進程構成網絡),那么需要配置standalone 這一項,表示這個進程是主節點,它需要開啟一個控制中心,監聽一個端口,讓其它節點接入。
- master?指定 skynet 控制中心的地址和端口,如果你配置了 standalone 項,那么這一項通常和 standalone 相同。
每個 skynet 進程都是一個 slave 節點。但其中一個 slave 節點可以通過配置 standalone 來多啟動一個 cmaster 服務,用來協調 slave 組網。對于每個 slave 節點,都內置一個 harbor 服務用于和其它 slave 節點通訊。
每個 skynet 服務都有一個全網唯一的地址,這個地址是一個 32bit 數字,其高 8bit 標識著它所屬 slave 的號碼。即 harbor id 。在 master/slave 網絡中,id 為 0 是保留的。所以最多可以有 255 個 slave 節點。
在 master/slave 模式中,節點內的消息通訊和節點間的通訊是透明的。skynet 核心會根據目的地址的 harbor id 來決定是直接投遞消息,還是把消息轉發給 harbor 服務。
不要把這個模式用于跨機房的組網。所有 slave 節點都應該在同一局域網內(最好在同一交換機下)。不應該把系統設計成可以任意上線或下線 slave 的模式。
slave 的組網機制也限制了這一點。如果一個 slave 意外退出網絡,這個 harbor id 就被廢棄,不可再使用。這樣是為了防止網絡中其它服務還持有這個斷開的 slave 上的服務地址;而一個新的進程以相同的 harbor id 接入時,是無法保證舊地址和新地址不重復的。
?
cluster 模式
cluster 模塊,它大部分用 lua 編寫,只有通訊協議處理的部分涉及一個很小的 C 模塊。
它的工作原理是這樣的:
在每個 skynet 節點(單個進程)內,啟動一個叫 clusterd 的服務。所有需要跨進程的消息投遞都先把消息投遞到這個服務上,再由它來轉發到網絡。
?
要使用它之前,你需要編寫一個 cluster 配置文件,配置集群內所有節點的名字和對應的監聽端口。并將這個文件事先部署到所有節點
db = "127.0.0.1:2528"接下來,你需要在 db 的啟動腳本里寫上?cluster.open "db"
有兩種方式可以訪問到這個節點
可以通過 cluster.call(nodename, service, ...) 提起請求。這里 nodename 就是在配置表中給出的節點名。service 可以是一個字符串,或者直接是一個數字地址(如果你能從其它渠道獲得地址的話)。當 service 是一個字符串時,只需要是那個節點可以見到的服務別名,可以是全局名或本地名。但更推薦是 . 開頭的本地名,因為使用 cluster 模式時,似乎沒有特別的理由還需要在那個節點上使用 master/slave 的架構(全局名也就沒有特別的意義)。cluster.call 有可能因為 cluster 間連接不穩定而拋出 error 。但一旦因為 cluster 間連接斷開而拋出 error 后,下一次調用前 cluster 間會嘗試重新建立連接。
可以通過 cluster.proxy(nodename, service) 生成一個本地代理。之后,就可以像訪問一個本地服務一樣,和這個遠程服務通訊。但向這個代理服務 send 消息,有可能因為 cluster 間的連接不穩定而丟失。詳見 cluster.send 的說明。
如果想單向推送消息,可以調用 cluster.send(nodename, service, ...) 。但注意,跨越節點推送消息有丟失消息的風險。因為 cluster 基于 tcp 連接,當 cluster 間的連接斷開,cluster.send 的消息就可能丟失。而這個函數會立刻返回,所以調用者沒有機會知道發送出錯。
Cluster 是去中心化的,所以需要在每臺機器上都放置一份配置文件(通常是相同的)。通過調用 cluster.reload 可以讓本進程重新加載配置。如果你修改了每個節點名字對應的地址,那么 reload 之后的請求都會發到新的地址。而之前沒有收到回應的請求還是會在老地址上等待。如果你老的地址已經無效(通常是主動關閉了進程)那么請求方會收到一個錯誤。
?
某個節點配置多個通道
在skynet框架中使用cluster模式,經常有消息在節點之間傳遞。大部分情況,我們在節點A和節點B之間只需要建立一個連接通道,但是在有些時候我們希望讓一些比較獨立的業務能占用一條單獨的通道進行處理,不希望跟到正常的業務邏輯去搶通道資源。這個時候,我們就需要為某個節點配置多個通道了。
比如,我們要在節點A中再開辟一條連接連通節點B的通道,由于一條通道就是一條tcp連接,所以我們需要為節點B再配置一個端口。我們打開集群的cluster配置文件,添加一個節點B的記錄,新分配一個端口:
nodea?=?"127.0.0.1:50653" nodeb?=?"127.0.0.1:50654" nodeb2=?"127.0.0.1:50655"?然后重新啟動節點,在節點B的啟動腳本中,我們也需要在集群中打開nodeb2:
cluster.open("nodeb2")然后,在節點A中,我們就可以進行跨節點訪問了,這個時候,我們可以分別用nodeb和nodeb2進行訪問,框架將使用2條tcp通道進行分別處理。你也可以使用netsta命令,查看nodeb和nodeb2的連接情況。
cluster.call("nodeb",".main","xxxxxx") cluster.call("nodeb2",".main","xxxxxx")?
關于cluster的實現
為什么要cluster:
除非你的業務本來就是偏重 IO 的,也就是你根本不打算利用單臺硬件的多核心優勢來增強計算力,抹平本機和網絡的差異是沒有意義的。無論硬件怎樣發展,你都不可能看到主板上的總線帶寬和 TCP 網絡的帶寬工作在同一數量級的那一天,因為這是物理基本規律決定的。
當你的業務需要高計算力,把 actor 放在一臺機器上才可以正常的發揮 CPU 能力去合作;如果你的系統又需要分布式擴展,那么一定是有很多組獨立無關的業務可以平行處理。這兩類工作必須由構架系統的人自己想清楚,規劃好怎么部署這些 actor ,而不可能隨手把 actor 扔在分布式系統中,隨便挑臺硬件運行就夠了。
恰巧網絡游戲服務就是這種業務類型。多組服務器、多個游戲場景之間交互很弱,但其中的個體又需要很強的計算力。這就是 skynet 切合的應用場景。
?
實現:
skynet 的核心層之上,設計了 cluster 模塊。它大部分用 lua 編寫,只有通訊協議處理的部分涉及一個很小的 C 模塊。用 Lua 編寫可以提高系統的可維護性,和網絡通訊的帶寬相比,Lua 相對 C 在處理數據包的性能降低是微不足道的。
在每個 skynet 節點(單個進程)內,啟動一個叫 clusterd 的服務。所有需要跨進程的消息投遞都先把消息投遞到這個服務上,再由它來轉發到網絡。
?
參考:
GettingStarted
skynet_cluster
轉載于:https://www.cnblogs.com/losophy/p/9204573.html
總結
以上是生活随笔為你收集整理的skynet:cluster的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pandas_收益率的分布
- 下一篇: 织梦dedecms百度快照劫持注入代码防