BSP 图计算:Pregel 背后的并行模型
BSP 图计算:Pregel 背后的并行模型
先澄清一个概念:严格来说,没有“BSP 图”这种标准术语。
BSP 不是一种图,而是一种并行计算模型。
所谓“BSP 图”,通常是指:用 BSP 模型来跑图算法,典型代表就是 Google Pregel。
一句话记住:
图是数据,BSP 是计算节奏,Pregel 是编程写法。
1. BSP 到底是什么?
BSP = Bulk Synchronous Parallel,中文叫“整体同步并行”。
它最早由 Leslie Valiant 在 1990 年代提出,核心思想是:
把并行计算切成一轮一轮的“超步”,每一轮里大家各算各的,算完必须等所有人到齐,再统一进入下一轮。
flowchart LR
A[超步 S] --> B[本地计算]
B --> C[发送消息]
C --> D[同步屏障:等所有节点完成]
D --> E[超步 S+1]
E --> B
| 概念 | 含义 |
|---|---|
| 超步 | 一轮计算 |
| 本地计算 | 每个顶点/节点自己算 |
| 消息传递 | 节点之间通信 |
| 同步屏障 | 所有人必须到齐才能进下一轮 |
| 终止 | 没有活跃顶点,也没有在途消息 |
2. 为什么图计算需要 BSP?
图算法通常要反复迭代,比如 PageRank、最短路径、连通分量。
这些算法的共同点是:顶点根据邻居的消息更新自己,再把新状态传出去。
如果直接用 MapReduce 跑图算法,会有个大问题:
flowchart TB
A[图算法迭代] --> B[MapReduce 每轮全图 Shuffle]
B --> C[网络和磁盘开销巨大]
C --> D[迭代越多,越慢]
BSP 图计算换了个思路:
flowchart TB
A[图按顶点分区] --> B[数据留在 Worker 内存]
B --> C[超步内本地计算]
C --> D[只发消息给邻居]
D --> E[同步屏障]
E --> C
| 对比 | MapReduce | BSP 图计算 |
|---|---|---|
| 数据移动 | 每轮全图 Shuffle | 图分区保留,只传消息 |
| 迭代开销 | 很大 | 较小 |
| 编程视角 | 全局 Map/Reduce | 以顶点为中心 |
| 典型系统 | Hadoop | Pregel、Giraph、GraphX |
所以,BSP 图计算的核心价值是:
把图留在集群内存里,用超步迭代,用消息传播,用同步屏障保证每轮全局一致。
3. BSP 图计算怎么跑?
3.1 系统架构
flowchart TB
M[Master 协调者] --> W1[Worker 1]
M --> W2[Worker 2]
M --> W3[Worker N]
W1 --> P1[顶点分区 A]
W2 --> P2[顶点分区 B]
W3 --> P3[顶点分区 C]
P1 <-->|跨机消息| P2
P2 <-->|跨机消息| P3
M --> CP[(检查点存储)]
W1 --> CP
W2 --> CP
W3 --> CP
| 角色 | 职责 |
|---|---|
| Master | 协调超步、分配分区、触发检查点 |
| Worker | 维护顶点分区、执行 Compute、收发消息 |
| 分区 | 默认 hash(VertexID) mod N |
| 检查点存储 | 定期保存状态,用于故障恢复 |
3.2 超步循环
flowchart TD
A[开始超步 S] --> B[每个顶点读取 S-1 的消息]
B --> C[执行 Compute]
C --> D[更新自身状态/出边]
D --> E[向邻居发送消息]
E --> F[同步屏障]
F --> G{所有顶点 Halt 且无在途消息?}
G -- 否 --> A
G -- 是 --> H[结束,输出结果]
关键规则:
| 规则 | 含义 |
|---|---|
| 超步 S 发的消息 | 只能在超步 S+1 被接收 |
| 同步屏障 | 所有顶点完成后,才进入下一轮 |
VoteToHalt() |
顶点声明“我暂时没事了” |
| 重新激活 | 已 Halt 的顶点若收到新消息,会再次活跃 |
| 终止条件 | 所有顶点 Halt,且没有在途消息 |
3.3 顶点内部:Compute 流程
flowchart TD
A[超步开始] --> B[读取上一超步消息]
B --> C[执行用户 Compute]
C --> D{状态是否变化?}
D -- 是 --> E[向邻居 SendMessage]
D -- 否 --> F[可以不发消息]
E --> G[VoteToHalt]
F --> G
G --> H[等待同步屏障]
伪代码:
Compute(msgs):
for msg in msgs:
根据 msg 更新当前顶点状态
if 状态发生变化:
for edge in outEdges:
SendMessageTo(edge.target, 新状态)
VoteToHalt()
4. BSP 图计算里的“图”是什么?
这里的“图”就是普通的图数据结构:
| 元素 | 含义 |
|---|---|
| 顶点 | 计算单元 |
| 边 | 通信关系 |
| 顶点值 | 当前状态,比如距离、排名 |
| 边值 | 权重,比如距离、相似度 |
| 消息 | 顶点之间传递的临时数据 |
| 活跃顶点 | 还需要继续计算的顶点 |
| Halt | 暂时停止,收到消息可复活 |
图会被切分到多个 Worker 上,每个 Worker 负责一部分顶点。
顶点之间通过消息通信,而不是直接共享内存。
5. BSP 图计算 vs Gossip
你之前问过 Pregel 和 Gossip 的区别。放在 BSP 图计算语境下,可以这样看:
flowchart LR
subgraph BSP[BSP 图计算:同步、按图边]
P1[超步 S] --> P2[所有顶点 Compute]
P2 --> P3[沿出边发消息]
P3 --> P4[同步屏障]
P4 --> P5[超步 S+1]
end
subgraph Gossip[Gossip:异步、随机对等]
G1[节点 A] -->|随机选 B| G2[交换状态]
G2 -->|随机选 C| G3[继续扩散]
G3 --> G4[最终一致]
end
| 维度 | BSP 图计算 / Pregel | Gossip |
|---|---|---|
| 同步性 | 同步,超步 + 全局屏障 | 异步,各自周期性通信 |
| 通信拓扑 | 输入图的边 | 随机 peer / 覆盖网络 |
| 通信模式 | 显式 SendMessage |
push / pull / 交换状态 |
| 全局协调 | 有 Master | 无中心,去中心化 |
| 一致性 | 每超步后全局一致快照 | 最终一致 |
| 终止条件 | 所有顶点 Halt 且无消息 | 通常靠阈值/超时 |
| 容错 | 检查点回滚重算 | 冗余传播,天然容忍丢失 |
| 确定性 | 较确定,可重复 | 概率性,随机选择 |
| 典型用途 | PageRank、最短路径 | 成员管理、故障检测、复制 |
生活化比喻:
| 模型 | 比喻 |
|---|---|
| BSP 图计算 | 全班按座位表传纸条,老师喊“停”才能进下一轮 |
| Gossip | 课间随机找人聊天,消息一传十、十传百,最后大家趋于一致 |
6. BSP 图计算的优缺点
| 优点 | 局限 |
|---|---|
| 编程抽象简单:只写顶点逻辑 | 只支持内存计算,图要装进集群内存 |
| 自动分区、消息传递、容错 | 同步屏障容易受最慢 Worker 拖累 |
| Combiner 减少网络传输 | 哈希分区对幂律图容易负载不均 |
| Aggregator 方便全局统计 | 消息量大时网络仍是瓶颈 |
| 大量图算法可复用同一框架 | 不适合低延迟、流式动态图 |
7. 总结
| 问题 | 回答 |
|---|---|
| BSP 是什么 | 整体同步并行计算模型,一轮一轮超步执行 |
| “BSP 图”是什么 | 不是标准术语,通常指用 BSP 模型跑图算法 |
| 核心机制 | 超步 + 本地计算 + 消息传递 + 同步屏障 |
| 典型系统 | Google Pregel、Apache Giraph、Spark GraphX |
| 和 Gossip 区别 | BSP 同步、按图边、有全局协调、精确终止;Gossip 异步、随机、去中心、最终一致 |
| 一句话记忆 | 图是数据,BSP 是节奏,Pregel 是写法,Gossip 是另一种传播 |
Pregel 真正的遗产不是某个 API,而是一种设计哲学:
把复杂分布式图计算的“并行逻辑”和“系统实现”拆开。
程序员专注于顶点逻辑,框架消化分区、消息、同步和容错。
这就是 BSP 图计算,也是“像顶点一样思考”的力量。

浙公网安备 33010602011771号