强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Erlang/OTP 完全指南 / 01 - Erlang 简介

第 01 章:Erlang 简介

“Erlang 不是一门语言,它是一种构建可靠系统的方式。” — Joe Armstrong


1.1 历史背景

1.1.1 诞生故事

Erlang 诞生于 1986 年,由瑞典爱立信(Ericsson)公司的 Joe ArmstrongRobert VirdingMike Williams 创造。

时间事件
1986Joe Armstrong 开始设计 Erlang
1987首个原型实现完成
1991Erlang 首次公开发布
1996OTP(Open Telecom Platform)框架发布
1998Erlang/OTP 开源
2006Erlang 在并发编程领域重新受到关注
2008WhatsApp、RabbitMQ 等项目兴起
2017Erlang/OTP 20 引入 Maps 和新特性
2024+Erlang/OTP 26+ 持续演进

1.1.2 设计目标

Erlang 最初为电信系统设计,核心要求:

  1. 高并发(Concurrency):同时处理大量呼叫
  2. 高可用(Availability):99.9999999%(九个九)的正常运行时间
  3. 软实时(Soft Real-time):低延迟响应
  4. 热代码升级(Hot Code Upgrade):不停机更新
  5. 容错(Fault Tolerance):局部故障不影响整体

1.1.3 “九个九"的含义

可用性等级每年停机时间典型场景
99% (两个九)3.65 天普通 Web 应用
99.9% (三个九)8.76 小时电商平台
99.99% (四个九)52.6 分钟金融系统
99.999% (五个九)5.26 分钟电信核心网
99.9999999% (九个九)31 毫秒爱立信 AXD301 ATM 交换机

1.2 Erlang 的特性

1.2.1 函数式编程

Erlang 是一门函数式编程(Functional Programming)语言:

%% 变量不可变(Single Assignment)
X = 1.
%% X = 2.  % 错误!变量已绑定

%% 函数是一等公民
Double = fun(X) -> X * 2 end.
Double(5).  %% => 10

%% 无副作用(理想情况)
%% 不修改输入数据,而是返回新的数据

1.2.2 轻量级进程

Erlang 的"进程"不是操作系统进程,也不是线程:

特性OS 进程OS 线程Erlang 进程
内存占用数 MB数百 KB约 2 KB
创建时间数毫秒数十微秒约 1 微秒
数量上限数千数万数百万
调度方式OS 内核OS 内核BEAM 虚拟机
通信方式IPC共享内存消息传递
%% 创建 100 万个进程
Pids = [spawn(fun() -> receive stop -> ok end end)
        || _ <- lists:seq(1, 1000000)].
length(Pids).  %% => 1000000

1.2.3 消息传递

进程间通信的唯一方式是消息传递(Message Passing):

%% 进程 A 发送消息给进程 B
Pid ! {hello, "world"}.

%% 进程 B 接收消息
receive
    {hello, Msg} -> io:format("收到: ~p~n", [Msg])
end.

1.2.4 容错设计

Erlang 的容错基于 “Let it crash” 哲学:

%% 不要这样写(防御性编程)
handle(Data) ->
    if
        is_list(Data) -> process_list(Data);
        is_tuple(Data) -> process_tuple(Data);
        true -> error  %% 覆盖所有情况?
    end.

%% Erlang 方式(Let it crash)
handle(Data) ->
    process(Data).  %% 让它崩溃,由 Supervisor 处理

1.3 OTP 框架

1.3.1 什么是 OTP?

OTP(Open Telecom Platform)是一个用于构建并发、容错应用程序的框架和库集合:

┌─────────────────────────────────────────┐
│              你的应用程序                  │
├─────────────────────────────────────────┤
│  GenServer  GenStateMachine  GenEvent    │  ← 行为模式(Behaviours)
├─────────────────────────────────────────┤
│  Supervisor         Application          │  ← 监督树
├─────────────────────────────────────────┤
│  ETS    Mnesia    Logger    Crypto       │  ← 标准库
├─────────────────────────────────────────┤
│              BEAM 虚拟机                  │
└─────────────────────────────────────────┘

1.3.2 OTP 三大支柱

组件英文名作用
通用服务器GenServer封装有状态的并发服务
监督者Supervisor监控子进程,崩溃时自动重启
应用Application组织和管理应用生命周期
%% 一个简单的 OTP 应用结构
%% 应用(Application)
%%   └── 监督者(Supervisor)
%%         ├── 服务器(GenServer)1
%%         ├── 服务器(GenServer)2
%%         └── 服务器(GenServer)3

1.3.3 监督树示例

          [Application]
               │
          [Supervisor]
          /    |    \
   [GS1]   [GS2]   [GS3]
               │
          [Supervisor2]
          /          \
     [Worker1]    [Worker2]

1.4 适用场景

1.4.1 电信领域

Erlang 的"老家”:

  • 交换机控制:爱立信 AXD301 ATM 交换机
  • 信令网关:SS7/SIP 协议处理
  • 移动核心网:4G/5G 核心网元

1.4.2 消息队列

项目描述使用 Erlang 的部分
RabbitMQ最流行的开源消息代理核心 broker 全部用 Erlang
EMQX大规模 MQTT 消息服务器核心引擎
VerneMQ分布式 MQTT broker全部用 Erlang

1.4.3 即时通讯

项目峰值规模
WhatsApp9 亿用户,50 名工程师
微信部分后端服务使用 Erlang

1.4.4 数据库与存储

项目描述
CouchDB文档数据库,HTTP REST API
Riak分布式 KV 数据库
MnesiaErlang 内置分布式数据库

1.4.5 实时系统

  • 游戏服务器:高并发玩家连接
  • 物联网(IoT):海量设备连接管理
  • 金融交易:低延迟订单处理
  • CDN 边缘计算:内容分发节点

1.4.6 何时不适合使用 Erlang?

场景原因替代方案
CPU 密集计算BEAM 调度器开销C/C++/Rust
科学计算缺乏数值库Python/Julia
桌面 GUI无成熟 GUI 框架C#/Swift
移动端开发不支持Kotlin/Swift
简单 CRUD Web生态不如主流语言Go/Node.js

1.5 BEAM 虚拟机

1.5.1 架构概览

源代码 (.erl)
    ↓
编译器 (erlc)
    ↓
字节码 (.beam)
    ↓
BEAM 虚拟机 (erl)
    ↓
操作系统

1.5.2 BEAM vs 其他虚拟机

特性BEAMJVM.NET CLR
并发模型Actor线程Task/TPL
进程开销~2KB~1MB 栈~1MB
GC 策略每进程独立 GC全局 GC分代 GC
热更新原生支持需要框架需要框架
调度抢占式抢占式抢占式
延迟保证软实时一般无一般无

1.5.3 Erlang 运行时系统

%% 查看运行时信息
erlang:system_info(otp_release).    %% OTP 版本
erlang:system_info(schedulers).     %% 调度器数量(通常等于 CPU 核心数)
erlang:system_info(process_count).  %% 当前进程数
erlang:memory().                    %% 内存使用情况

1.6 Erlang 生态系统

1.6.1 核心工具

工具用途
erlcErlang 编译器
erl交互式 Shell(REPL)
rebar3构建工具(类似 Maven/npm)
observer可视化监控工具
dialyzer静态类型分析

1.6.2 知名 Erlang 项目

WhatsApp      ── 即时通讯(9 亿用户)
RabbitMQ      ── 消息队列(最流行 AMQP broker)
CouchDB       ── 文档数据库
Riak          ── 分布式 KV 存储
EMQX          ── MQTT broker(百万连接)
Discord       ── 部分后端服务
Klarna        ── 支付系统
Ericsson      ── 电信设备
Nintendo      ── 部分在线服务

1.7 快速上手预览

1.7.1 Hello World

%% hello.erl
-module(hello).
-export([world/0]).

world() ->
    io:format("Hello, Erlang!~n").

1.7.2 简单并发

%% 创建一个打印消息的进程
Pid = spawn(fun() ->
    receive
        {greet, Name} ->
            io:format("Hello, ~s!~n", [Name])
    end
end).

Pid ! {greet, "Erlang"}.

1.7.3 简单监督树

%% Supervisor 启动两个 worker
init(_) ->
    Children = [
        #{id => worker1, start => {my_worker, start_link, []}},
        #{id => worker2, start => {my_worker, start_link, []}}
    ],
    {ok, {#{strategy => one_for_one, intensity => 5, period => 10}, Children}}.

1.8 Erlang vs 其他语言

维度ErlangGoJavaElixir
类型动态强类型静态强类型静态强类型动态强类型
并发模型ActorCSP (goroutine)线程/虚拟线程Actor (运行在 BEAM 上)
容错原生监督树手动处理需要框架原生监督树
热更新原生支持不支持需要框架原生支持
学习曲线中等中等中等
生态规模极大中等
运行平台BEAM原生JVMBEAM

1.9 注意事项

⚠️ 常见误区

  1. Erlang 不是银弹:不适合 CPU 密集型任务,数值计算性能远低于 C/Rust
  2. 动态类型的代价:Dialyzer 可以做静态分析,但无法替代编译期类型检查
  3. 生态较小:第三方库数量远少于 Java/Python/Go,需要自己造轮子
  4. 学习曲线:函数式思维 + OTP 设计模式需要时间适应
  5. 调试困难:并发 bug 难以复现,需要依赖 tracing 工具

💡 为什么学 Erlang?

  • 理解 Actor 模型和并发编程的最佳范本
  • OTP 的设计模式可以迁移到其他语言(Akka、Vert.x 等)
  • Elixir 运行在 BEAM 上,学会 Erlang 更容易上手 Elixir
  • 电信、消息队列、IoT 等领域仍有大量 Erlang 岗位

1.10 扩展阅读


下一章:02 - 环境搭建