分布式任务和配置

启动节点A, 并定义一个模块

1
root@c87c9967219c:~# iex --sname A
iex(foo@c87c9967219c)1> defmodule Hell do
...(foo@c87c9967219c)1>   def world, do: IO.puts "hello world"
...(foo@c87c9967219c)1> end

启动节点C,并在节点C上Spawn一个在节点A上运行的进程, 并放回消息到C节点的终端

1
root@c87c9967219c:~# iex --sname C
iex(bar@c87c9967219c)1> Node.spawn_link :"foo@c87c9967219c", fn -> Hello.world end
hello world
#PID<9010.79.0>

在节点C上定义要执行的代码, 并在A上运行, 然后把运行结果返回给C

1
iex> Node.spawn_link :"A@c87c9967219c", fn -> Hello.world end

收发消息:

1
iex(B@c87c9967219c)1> pid = Node.spawn_link :"A@c87c9967219c", fn ->
...(B@c87c9967219c)1>   receive do
...(B@c87c9967219c)1>     {:ping, client} ->
...(B@c87c9967219c)1>       send client, :pong
...(B@c87c9967219c)1>   end
...(B@c87c9967219c)1> end
#PID<8005.65.0>
iex(B@c87c9967219c)2> send pid, {:ping, self}
{:ping, #PID<0.60.0>}
iex(B@c87c9967219c)3> flush
:pong
:ok

每次我们想要执行分布式计算的时候, 我们可以通过Node.spawn_link/2在其他节点上spawn一个进程, 但是我们应该避免在 supervision 树的外部去spawn子进程.

对于Node.spawn_link2, 有更好的替代

  • 可以使用:rpc模块执行远程节点上的函数, 比如:

    1
    # 在A@c87c9967219c节点上, 执行Hello模块的:world函数, 没有参数
    :rpc.call(:"A@c87c9967219c", Hello, :world, [])
  • 通过GenServer API请求运行在其他节点上的服务器, 比如:

    1
    GenServer.call({name, node}, arg)
  • 可以使用任务,任务可以在本地或远程节点上Spawn进程

参考资料

  1. Distributed tasks and configuration
    http://elixir-lang.org/getting_started/mix_otp/10.html