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

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

第 01 章:Erlang 简介

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


1.1 历史背景

1.1.1 诞生故事

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

时间 事件
1986 Joe Armstrong 开始设计 Erlang
1987 首个原型实现完成
1991 Erlang 首次公开发布
1996 OTP(Open Telecom Platform)框架发布
1998 Erlang/OTP 开源
2006 Erlang 在并发编程领域重新受到关注
2008 WhatsApp、RabbitMQ 等项目兴起
2017 Erlang/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 即时通讯

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

1.4.4 数据库与存储

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

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 其他虚拟机

特性 BEAM JVM .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 核心工具

工具 用途
erlc Erlang 编译器
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 其他语言

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

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 - 环境搭建