我可以从远程节点调用 GenServer 客户端函数吗?
Posted
技术标签:
【中文标题】我可以从远程节点调用 GenServer 客户端函数吗?【英文标题】:Can I call GenServer client functions from a remote node? 【发布时间】:2019-01-28 22:42:45 【问题描述】:我在远程节点上有一个 GenServer,模块中有实现和客户端功能。我可以以某种方式远程使用 GenServer 客户端功能吗?
使用GenServer.call(RemoteProcessName, :"app@remoteNode", :get)
可以正常工作,但很麻烦。
如果我想清理它,我是否认为我必须在调用(客户端)节点上编写客户端函数?
【问题讨论】:
【参考方案1】:您可以使用:rpc.call/4,5
函数。
:rpc.call(:"app@remoteNode", MyModule, :some_func, [arg1, arg2])
【讨论】:
【参考方案2】:对于大量呼叫,最好使用用户gen_server:call/2-3
。
如果你想使用rpc:call/4-5
,你应该知道它只是每个节点上一个名为rex
的进程,用于处理所有请求。所以如果它正在运行一个Mod:Func(Arg1, Arg2, Argn)
,此时它无法响应其他请求!
【讨论】:
知道这一点很有用,但这是否意味着如果我打算使用 GenServer 回复多个客户端进程,我必须放弃在 GenServer 中使用客户端功能? 确实——来自其他语言的人们习惯性地使用 rpc 模块,但我实际上从来没有找到它的用例,因为你可以Pid ! Message
甚至产生一个进程直接在单独的节点上(只要它可以访问您在本地调用它的相同代码)。
这不是关于一个 gen_server。因为一个 gen_server 通常可以按顺序发送对请求的回复。这是关于在远程节点上有几个 gen_servers。因此,当您使用 rpc 时,此时只有其中一个 gen_server 可以回复请求。如果您不想经常断开与远程节点的连接,您可以从当前节点上的远程节点动态加载该模块并使用其功能。【参考方案3】:
TL;DR
是的
讨论
有 PID、消息、监视器和链接。不多也不少。那是你的宇宙。 (除非您进入运行时实现的一些相当深奥的方面——但在 EVM 语言所代表的抽象级别上,前面所述的元素(应该)构成您的宇宙。)
在 Erlang 环境中(无论是本地还是分布在网格中)任何 PID 都可以向任何其他 PID 发送消息(无需中间人),如以及建立监视器等等。
gen_server:cast
发送一个 gen_server 打包消息(因此它将以handle_cast/2
的形式到达,将被调用)。 gen_server:call/2
建立一个监视器和一个超时来接收标记的回复。简单地执行PID ! SomeMessage
与gen_server:cast
(发送消息)基本相同,而没有任何背后的 gen_server 机制(更混乱地抽象为接口)。
仅此而已。
考虑到这一点,当然您可以跨节点使用gen_server:call/2
,只要它们通过 disterl 连接到集群/网格中即可。两个断开连接的节点必须以不同的方式进行通信(网络套接字),并且不知道彼此的内部 PID 映射,但只要使用 disterl,它们都可以很容易地在它们之间转换 PID。命名进程是事情变得有点棘手的地方,但这就是 global
模块和实用程序(如 gproc
)的目的(尽管超过某个点对此类设施的依赖通常表明存在架构问题)。
当然,仅仅因为来自任何节点的 PID 可以与来自另一个节点的 PID 通信并不总是意味着它们应该。当您开始发送高频或大型消息(大量gen_server:call
s)时,网络的物理拓扑(带宽、延迟、抖动)开始发挥作用,并且您总是必须考虑分区容限——但要关闭- 加载繁重的工作(罕见)或在一个非常大的系统(更常见)中对子系统进行物理分区,直接发送消息是采用为单个节点编码的程序并将其分布在集群中的一种非常简单的方法。
(考虑到所有这些,很少看到使用 rpc 模块。)
【讨论】:
以上是关于我可以从远程节点调用 GenServer 客户端函数吗?的主要内容,如果未能解决你的问题,请参考以下文章
Elixir GenServer handle_cast 未被调用
JenkinsJenkins配置从节点,实现远程主机调用功能