


























┌─────────────────────────────────────────────────────────────┐
│ Gun.js 去中心化架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 用户 A (浏览器/Node) 用户 B (浏览器/Node) │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ 应用层 │ │ 应用层 │ │
│ │ gun.get('key') │ │ gun.get('key') │ │
│ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │
│ ┌────────▼────────┐ ┌────────▼────────┐ │
│ │ Gun.js 内核 │◄────────►│ Gun.js 内核 │ │
│ │ - CRDT 冲突 │ P2P直连 │ - CRDT 冲突 │ │
│ │ - HAM 图 │ │ - HAM 图 │ │
│ │ - 数据图结构 │ │ - 数据图结构 │ │
│ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │
│ ┌────────▼────────┐ ┌────────▼────────┐ │
│ │ 本地存储 │ │ 本地存储 │ │
│ │ IndexedDB / │ │ IndexedDB / │ │
│ │ localStorage │ │ localStorage │ │
│ └─────────────────┘ └─────────────────┘ │
│ │
│ ┌─────────────────┐ │
│ │ 中继节点 │ (可选,非必须) │
│ │ (Relay Peer) │ │
│ │ 仅帮忙转发 │ │
│ │ 不存储数据 │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
| 层级 | 作用 | 关键点 |
|---|---|---|
| 应用层 | 你用 gun.get() / gun.put() 读写数据 |
和普通 API 一样简单 |
| Gun.js 内核 | 把所有数据组织成一个巨大的图 (Graph),用 HAM 算法 做 CRDT 冲突解决 | 任何人离线改了数据,重新连接后自动合并,不会丢 |
| 传输层 | 默认走 WebSocket 连中继节点;也可切换 WebRTC 做真 P2P | 连接建立后,数据直接端到端,不经过服务器 |
| 本地持久化 | Radisk 引擎自动把数据存进 IndexedDB | 刷新页面、断网,数据都在,重连后自动同步 |
你可以把下面这段代码复制到 Mermaid Live Editor 里,立刻生成一张架构流程图:
graph TD A[用户 A] --> GUN_A[Gun.js 实例] B[用户 B] --> GUN_B[Gun.js 实例] GUN_A --> STORE_A[本地存储 IndexedDB] GUN_B --> STORE_B[本地存储 IndexedDB] GUN_A <-->|WebRTC / WebSocket| GUN_B RELAY[可选中继节点 Relay] -.->|辅助穿透 NAT| GUN_A RELAY -.->|辅助穿透 NAT| GUN_B GUN_A --> GRAPH[(全局有向图 HAM Graph)] GUN_B --> GRAPH
一句话总结 Gun.js 的原理:
每个客户端都是一个完整节点,数据以图结构存本地,通过 CRDT 算法实现无冲突多主写入,网络恢复后自动同步最新状态,中继节点只转发不存储,真正去掉中心数据库。
CRDT 全称是 Conflict-free Replicated Data Type(无冲突复制数据类型)。
这是一种数据结构设计的“指导思想”,专门用来解决一个核心问题:当多个人同时离线编辑一份数据,而且没有中央服务器来当裁判时,大家重新联网后怎么做到自动合并、不打架、最终所有人手里的数据都能一模一样。
你可以把它想象成一块“魔法白板”:
在你之前设想的场景里(北京和洛杉矶两人实时看到彼此状态,没有后端数据库),最大的挑战就是:
传统的做法需要一把“锁”或一个中心服务器来排队处理请求,而 CRDT 允许无锁、无中心的自由修改,只要数据结构本身设计得足够“聪明”,无论并发操作以什么顺序到达,最终结果都能自动收敛成一致。
关键在于它要求所有的修改操作必须满足三个数学性质:
满足这三条,即便消息在不同人之间乱序到达,最终数据也能自动收敛到同一个结果。
基于状态的
基于操作的
Gun.js 内部用的是 HAM(Hypothetical Amnesia Machine,假设性遗忘机器),可以理解为 CRDT 的一种具体实现算法,基于状态合并,专门针对“图数据”做冲突解决。
假设我们两人维护一个只有添加、没有删除的集合:
{A}{B}{A} ∪ {B} = {A, B}显然:
{A, B}(交换律){A} 做多次并集依然是 {A, B}(幂等性)这个“只增不删的集”就是一种最经典的 CRDT,叫 G-Counter 或 Grow-Only Set。
当然,现实里更复杂——要支持删除、数值加减、文本编辑,所以会有 PN-Counter、RGA、WOOT 等高级算法,但核心精神都一样:用数学性质保证最终一致,不用锁和中心协调器。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。