在 Elixir 中构建分布式系统:第六部分——命名进程
本文阐述了将进程 PID 用作公开接口的局限性,并引入命名进程作为可发现地址的解决方案。当工作进程崩溃并重启时,会获得一个新的 PID,导致旧 PID 失效。向已死亡的本地 PID 发送消息不会引发错误,也不会重启该进程。为解决此问题,客户端应依赖名称而非 PID 发送消息,并在发送时解析该名称。文章演示了两种进程命名方法:本地注册和全局注册。Process.register/2 在当前 BEAM 节点上将 PID 与名称关联,可通过 Process.whereis/1 访问。消息可直接发送至已注册名称,运行时将其解析为当前 PID。然而,Process.register/2 仅限于节点本地,意味着不同节点上的同名进程指向不同的进程。对于集群范围内的查找,使用 Erlang 的 :global 模块。:global.register_name/2 和 :global.whereis_name/1 支持在已连接的节点间进行名称注册与查找。第三个示例展示了如何通过让工作进程自行注册并返回其公开名称,从而向客户端隐藏 PID;客户端随后向该名称发送请求,而非直接向 PID 发送。至关重要的是,进程命名并不能解决监督或生命周期管理问题,仅解决发现机制。当已注册的进程终止时,其注册信息会被移除,必须启动替代进程并重新注册。单个名称通常对应单一所有者,因此在缺乏进一步路由机制的情况下,不适用于工作进程池。建议客户端使用唯一引用对多个并发请求进行响应关联。最后,:global 注册支持分布式系统,但无法消除网络分区或并发抢占等挑战。本文的核心思想是:使用进程名称代表服务角色,而非临时 PID,以构建具有弹性的系统。