BEAM Book 第14、15章节总结
第14章:Distribution(分布式)
14.1 节点与连接
节点的概念
- 定义:节点是ERTS的一个命名运行实例,只有命名节点才能通过Erlang分布进行通信
- 命名规范:由原子 + '@' + 主机名组成,例如:
node1@localhost
短名称 vs 长名称
| 特性 | 短名称 | 长名称 |
|---|---|---|
| 格式 | 仅原子(如 node1) | 原子@主机名 |
| 使用场景 | 所有节点在同一主机 | 节点分布在不同主机 |
| 互通性 | 只能与其他短名称节点通信 | 只能与其他长名称节点通信 |
关键点:短名称和长名称不能互相通信,需要保持一致
节点启动方式
- 无名节点:无法连接到其他节点(
Node.alive? -> false) - 有名节点:使用
--sname(短名)或--name(长名)启动,可以连接其他节点 - 动态启动:即使没有指定名称,也可通过
net_kernel:start([Name, shortnames])动态启动分布
连接建立
- 函数:
net_kernel:connect_node/1 - 默认行为:全连接拓扑 - 当N1连接到N2时,N1会自动连接到N2已连接的所有节点
- 禁用方式:启动时使用
-connect_all false标志
Cookie(魔法cookie)认证
- 作用:基本的安全认证机制,确保只有授权的节点能连接
配置方式:
- 启动时:
-setcookie选项 - 动态设置:
erlang:set_cookie/2函数
- 启动时:
默认行为:
- 节点启动时,在
~/.erlang.cookie中查找或创建 - 自动生成随机atom作为默认cookie
- 权限为用户只读(UNIX权限)
- 节点启动时,在
SSL支持
- Erlang支持节点间的SSL连接
- 配置:需要设置SSL证书、密钥和inet_dist选项
- 性能注意:SSL加密/解密会造成性能开销,需权衡
隐藏节点(Hidden Nodes)
- 特点:不在
nodes()返回列表中,不自动连接其他节点 - 连接方式:必须显式使用
net_kernel:connect_node/1 用途:
- 隔离特定操作或管理网络流量
- 大型动态网络中减少连接开销
- 创建子网拓扑
- 安全性:不是安全特性,不提供访问控制保护
第15章:How the Erlang Distribution Works(分布式工作原理)
15.1 EPMD(Erlang Port Mapper Daemon)
EPMD的角色
- 小型服务器,协助节点间建立连接
- 独立的OS进程,即使Erlang节点停止也继续运行
- 默认端口:4369
工作流程
- Erlang节点启动时,自动启动EPMD(如果尚未运行)
- 节点向EPMD注册,提供:节点名 + 监听端口
- 其他节点连接前,先询问EPMD要连接的目标节点的端口号
- EPMD返回端口,节点建立TCP连接
实现细节
- 源代码:
erts/epmd/src/epmd_srv.c - 简单的C实现,核心逻辑在单一C文件中
- 协议:小型固定格式二进制协议
15.2 Erlang Distribution Protocol(分布式协议)
握手过程(Handshake)
Node1 ──SEND_NAME──> Node2
<──ALIVE_ACK── (包含challenge随机数)
──CHALLENGE_REPLY──> (计算: challenge + magic_cookie)
<──CHALLENGE_ACK── (完成握手)关键点:
- SEND_NAME:包含协议版本和发起节点名
- ALIVE_ACK/NACK:接受/拒绝连接
- Challenge-Response:使用魔法cookie进行身份验证
- 连接建立后开始交换消息
三种消息类型
| 消息类型 | 用途 | 示例 |
|---|---|---|
| Control Messages | 分布式状态管理 | 进程链接/取消链接、监控、EXIT/KILL信号 |
| Data Messages | 进程间通信 | 发送项数据、RPC |
| System Messages | VM内部通信 | 分布式控制器、EPMD管理 |
15.3 Alternative Distribution(可选的分布式实现)
为什么需要可选分布式
| 原因 | 说明 |
|---|---|
| 性能 | 默认TCP可能不是最优的,可用更高效的协议 |
| 安全 | 增强加密、访问控制等超越魔法cookie的功能 |
| 可靠性 | 更精细的网络分区处理、更强的消息保证 |
| 互操作性 | 与其他语言系统(C、Scala等)通信 |
实现方式
Custom Distribution Driver(C语言驱动)
- 完全控制低层通信细节
- 协议和数据格式完全自定义
Distribution Callback Module(Erlang回调)
- 高层事件处理
- 连接建立/关闭、消息收发
Third-Party Libraries
- 封装好的高层API
- 抽象底层细节
实现步骤
- 编写分布式代码(C驱动或Erlang回调)
- 配置VM(使用
-proto_dist选项) - 测试机制(连接、消息传递、错误处理)
15.4 Processes in Distributed Erlang(分布式进程)
PID的结构和转换
本地PID格式: <node.index.serial>
例如: <0.10.0> (其中0代表本地节点)
远程PID格式: <NodeId.index.serial>
例如: <2.10.0> (其中2代表远程节点ID)PID自动转换
- 出站:将本地PID中的节点ID转换为真实远程节点ID(term_to_binary/1)
- 入站:接收时将远程节点ID转换回本地(0)
- 透明性:进程无需感知这种转换
Process Table的索引
- Index部分:在进程表中查找进程
- Serial部分:区分重用同一index的新旧进程
- 进程死亡时:标记为free,serial递增
分布式进程创建(spawn_request)
Node1 spawn/4请求
↓
Node1 ERTS发送SPAWN_REQUEST
↓
Node2 ERTS接收并在本地spawn
↓
Node2 创建进程:Module:Function(ArgList)
↓
Node2 ERTS发送SPAWN_REPLY + Flags
↓
Node1 ERTS返回PID给调用者SPAWN_REPLY中的Flags:
- Flag 1:是否建立链接(link)
- Flag 2:是否建立监控(monitor)
15.5 Remote Procedure Calls(RPC)
同步RPC:rpc:call/4
Result = rpc:call(Node, Module, Function, Args)执行流程:
- 发送消息给远程节点的rex服务器
- rex服务器在新进程中调用指定函数
- 函数执行完毕,结果返回给调用者
- rpc:call/4返回结果
rex服务器
- 名称:Remote EXecution
- 职责:处理来自其他节点的RPC请求
- 错误处理:捕获异常,返回给调用者
异步RPC:rpc:cast/4
- 不等待结果
- 立即返回
noreply - 适用于不关心返回值的场景
RPC的特性
- 使用标准Erlang分布式协议传输
- 支持选择性接收和模式匹配
- 本质上是普通Erlang消息
15.6 Large-Scale Distribution(大规模分布式系统)
主要挑战
连接数爆炸
- 全连接拓扑:连接数 = O(n²)
- 大量节点时网络流量激增
网络延迟
- 地理分散时问题严重
- Erlang异步模型可以有效应对,但不推荐用于地理分布式
故障处理
- 节点崩溃、网络断裂、数据损坏不可避免
- 解决方案:监督树、自动重启、故障检测
数据一致性
- 跨节点数据更新同步困难
- 推荐方案:避免分布式状态,保存单一真实来源
- Mnesia有性能问题,不适合大数据集
- 最佳实践:使用SQL数据库 + 消息队列
地理分布式建议
- 不推荐:用Erlang分布在地理分散的节点间
- 设计原则:Erlang分布适合数据中心或机架内通信
- 替代方案:异步消息模式、HTTP API等
15.7 Dist Port(分布式端口缓冲区)
缓冲区概述
- 用途:节点间通信缓冲
- 默认大小:128 MB
- 配置:
+zdbbl标志(单位:KB)
# 将缓冲区增加到192GB(实际应为192MB = 192000KB)
erl +zdbbl 192000缓冲区饱和的症状
2023-05-28 23:10:11.032 [warning] <0.431.0> busy_dist_port <0.324.0>根本原因和解决方案
| 原因 | 解决方案 |
|---|---|
| 网络问题 | 检查网络性能,升级基础设施 |
| 消息量过大 | 优化代码,批量发送,减少频率,尽量同节点通信 |
| 长时间任务 | 确保进程定期让出CPU,检查NIF实现 |
| VM调优 | 增加调度器数(+S)、IO线程数(+A)、其他VM参数 |
监控工具
etop:实时性能监控:observer:可视化监控应用
关键总结
Distribution架构
Application Layer
↓
Erlang Processes (PIDs with node info)
↓
Distribution Protocol (Handshake + 3 message types)
↓
EPMD (Port mapping) + TCP/IP
↓
Network核心特性
- 透明性:跨节点消息传递对应用透明
- 自动转换:PID和数据格式自动转换
- 认证机制:Cookie-based简单认证
- 可扩展:支持自定义分布实现
- 故障恢复:内置链接、监控机制
设计原则
- 适合:局域网、数据中心、同机架
- 不适合:地理分散的系统
- 状态管理:倾向于中央化数据存储而非分布式状态