问题描述
我正在用Akka.Cluster
创建一个具有三个节点A,B和C的示例,其中A是灯塔.到目前为止,从日志来看,当没有参与者或参与者是本地参与者(使用spawn
和spawnOpt
创建)时,集群可以正常工作.我想从B创建一个演员,然后从C访问它.
I'm creating a sample with Akka.Cluster
with three nodes A, B and C where A is the lighthouse. So far, from the logs, the cluster works fine when there are no actors or when actors are local (created with spawn
and spawnOpt
). I want to create an actor from B and access it from C.
使用
let _ = spawne system "r-actor" <@ actorOf (fun msg -> printfn "Received: %s" msg) @> []
我知道
使用
let r = FromConfig.Instance :> RouterConfig |> SpawnOption.Router
let _ = spawne system "r-actor" <@ actorOf (fun msg -> printfn "Received: %s" msg) @> [r]
引发异常
节点C上的测试功能是
let rec calculate content =
printfn "Processing %s" content
let actor = select "/user/r-actor" system
actor <! content
let text = Console.ReadLine()
if text <> "quit" then
calculate text
calculate "sample1"
HOCON(节点B)
HOCON (Node B)
akka {
actor {
provider = "Akka.Cluster.ClusterActorRefProvider, Akka.Cluster"
serializers {
wire = "Akka.Serialization.WireSerializer, Akka.Serialization.Wire"
}
serialization-bindings {
"System.Object" = wire
}
deployment {
/user/add {
router = round-robin-pool
nr-of-instances = 10
cluster {
enabled = on
max-nr-of-instances-per-node = 10
allow-local-routees = off
}
}
/user/r-actor {
router = round-robin-pool
nr-of-instances = 10
cluster {
enabled = on
max-nr-of-instances-per-node = 10
allow-local-routees = off
}
}
}
}
remote {
log-remote-lifecycle-events = DEBUG
log-received-messages = on
helios.tcp {
transport-class = "Akka.Remote.Transport.Helios.HeliosTcpTransport, Akka.Remote"
applied-adapters = []
transport-protocol = tcp
hostname = "127.0.0.1"
port = 0
}
}
loggers = ["Akka.Logger.NLog.NLogLogger,Akka.Logger.NLog"]
cluster {
seed-nodes = [
"akka.tcp://[email protected]:7001"
]
roles = ["add-service"]
auto-down-unreachable-after = 10s
}
}
如何创建一个可由集群中另一个节点调用的actor?
How do I create an actor that can be called by another node in the cluster?
推荐答案
在定义路由器配置时,请勿使用/user
前缀-它会自动添加.
When defining router configuration, don't use /user
prefix - it's added automatically.
此外,如果要选择驻留在另一个节点上的actor,则需要使用完整的actor路径(带有节点地址)-由于事实,可能有不同的actor驻留在具有相同路径的不同节点上.你必须很精确.
Also if you want to select actor that resides on another node, you need to use full actor path (with node address) - it's due to fact, that there may be different actors living on different nodes with the same path. You must be precise.
通常在编译时不知道节点的地址.有两种提取方法:
Usually address of the node won't be known to you at compile time. There are two ways to extract it:
这更容易,但是您失去了对加入/离开节点做出反应的能力.您每次都必须检查它,这很慢.本示例使用ActorSelection.ResolveOne
检索实际的IActorRef
实例.
It's easier but you're loosing the ability to react on joining/leaving nodes. You're forced to check it every time, which is slow. This example uses ActorSelection.ResolveOne
to retrieve actual IActorRef
instance.
async {
let members = Cluster.Get(system).State.Members
let actorRefs =
members
|> Seq.filter (fun m -> m.Roles.Contains("expected")) // use roles to filter out nodes that shouldn't be checked
|> Seq.map (fun m ->
let selection = select (m.Address.ToString() + "user/r-actor") system
let actorRef = selection.ResolveOne(timeout) |> Async.AwaitTask)
|> Async.Parallel }
2.订阅集群事件并在加入/离开节点时做出反应
在这里,您可以在节点加入/离开时对它们做出反应.它还使用Identify
/ActorIdentity
接收实际的IActorRef
,这是较快的选择.
2. Subscribe to cluster events and react on joining/leaving nodes
Here you can react on nodes as they join/leave. It also uses Identify
/ActorIdentity
to receive actual IActorRef
, which is faster option.
let aref =
spawn system "listener"
<| fun mailbox ->
let cluster = Cluster.Get (mailbox.Context.System)
cluster.Subscribe (mailbox.Self, [| typeof<ClusterEvent.IMemberEvent> |])
mailbox.Defer <| fun () -> cluster.Unsubscribe (mailbox.Self)
let rec loop () =
actor {
let! (msg: obj) = mailbox.Receive ()
match msg with
| :? ClusterEvent.MemberUp as up ->
// new node joined the cluster
let selection = select (up.Member.Address.ToString() + "user/r-actor") mailbox
selection <! Identify(null) // request actor under selection to identify itself
| :? ActorIdentity as id when id.Subject <> null ->
// actor has identified itself
id.Subject <! "hello"
| :? ClusterEvent.MemberRemoved as rem ->
// node leaved the cluster, invalidate all actors from that node
| _ -> ()
return! loop () }
loop ()
如有疑问,我写了一个博客帖子有关从F#创建Akka.NET群集.也许您会发现它有用.
In case of doubts, I've written a blog post about creating Akka.NET clusters from F#. Maybe you'll find it useful.
这篇关于如何在F#中的集群配置中创建actor的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!