命名节点
学习如何在 Elixir 中使用和实现命名节点。
节点并不神秘,它只是一个正在运行的 Erlang 虚拟机(VM)。在整个课程中,我们一直在节点上运行代码。
Erlang VM,称为 Beam,远不止是一个简单的解释器。它就像一个独立的小型操作系统,运行在我们的主机操作系统之上。它负责处理自己的事件、进程调度、内存管理、命名服务以及进程间通信。除此之外,一个节点还可以连接到同一台计算机上的其他节点,或通过局域网甚至互联网连接到远程节点,并在这些连接之间提供与本地进程相同的服务。
实现
到目前为止,我们并未给节点命名,因为我们只使用了一个节点。如果我们询问 Elixir 当前节点的名称,它会返回一个自动生成的名字:
1iex> Node.self 2:nonode@nohost
我们可以在启动节点时设置其名称。在 IEx 中,可以使用 --name 或 --sname 选项。前者设置完整的节点名称。要运行下面的命令,请使用“Ctrl+C”两次退出当前的 iex 会话。
1$ iex --name wibble@educative.local 2iex(wibble@educative.local)> Node.self 3:"wibble@educative.local"
--sname 选项用于设置短名称:
1$ iex --sname wobble 2iex(wobble@educative)> Node.self 3:"wobble@educative"
返回的名称是一个原子(atom),由于包含不允许出现在字面量原子中的字符,因此用引号括起来。
注意: 在这两种情况下,IEx 提示符中都包含了节点名称和机器名称(
educative)。
现在,我们创建一个匿名函数,用于输出当前节点的名称。
1iex(node_one@educative)> func = fn -> IO.inspect Node.self end 2#Function<erl_eval.20.82930912>
我们可以使用 spawn 函数来运行这个函数。
1iex(node_one@educative)> spawn(func) 2#PID<0.59.0> 3node_one@educative
但 Node.spawn 还允许我们指定目标节点名称,这样进程就会在指定的节点上启动。
1iex(node_one@educative)> Node.spawn(:"node_one@educative", func) 2#PID<0.57.0> 3node_one@educative
我们当前运行在节点 one 上。当我们告诉 spawn 在 node_one@educative 上执行时,看到了两行输出:第一行是 spawn 返回的 PID,第二行是函数中打印出的 Node.self 的值。
节点、Cookie 与安全
尽管这很酷,但也可能引发一些担忧。如果我们可以随意在任何节点上运行代码,那么任何一个公开可访问的节点就等于把机器交给了任意黑客。但实际上并非如此。
在节点允许另一个节点连接之前,会检查远程节点是否有权限。它是通过比较两个节点的 Cookie 来完成的。Cookie 只是一个任意字符串,理想情况下应足够长且高度随机。作为分布式 Elixir 系统的管理员,我们需要创建一个 Cookie,并确保所有节点都使用相同的值。
如果我们使用 iex 或 elixir 命令,可以通过 --cookie 选项传入 Cookie。
1$ iex --sname one --cookie chocolate-chip 2iex(one@educative)> Node.get_cookie 3:"chocolate-chip"
1$ iex --sname node_one --cookie cookie-one 2iex(node_one@educative)> Node.connect :"node_two@educative" 3false
尝试连接的节点会收到 false,表示连接未成功建立。
请在下方终端中运行上述命令: