基于 go-libp2p 的工业边缘配置同步通信规划方案(工业级完整版)


1. 方案概述

本方案基于 go-libp2p 构建一套面向工业局域网(LAN)的去中心化配置与控制权同步系统,专用于多台边缘网关之间的自动发现与配置一致性维护。

🔥 核心定位:Hybrid Sync Model(工业边缘推荐架构)

这是一个”分布式配置 + 控制权系统”,而不是”数据同步系统”

1️⃣ Config → CRDT-like(最终一致)
2️⃣ Ownership → Lease(强约束)  
3️⃣ Runtime → 单点主控(Owner Only)

为什么这是最优选择(针对工业场景)

方案 结论 原因
❌ Raft(强一致) 不推荐 太重 + leader瓶颈 + ARM跑不动
❌ 全CRDT 不推荐 实现复杂 + 不适合设备控制
❌ 文件同步(rsync) 不推荐 无语义,必炸
✅ Hybrid(本方案) 推荐 可控 + 轻量 + 工业适配

✅ 核心定位澄清

❌ 不是”文件镜像同步”(rsync式)
✅ 是”逻辑状态同步”(CRDT-like + Eventual Consistency)

关键区别

维度 文件镜像同步 逻辑状态同步(本方案)
同步单元 文件 ConfigSnapshot(结构化对象)
冲突处理 直接覆盖/失败 Vector Clock + Diff
一致性 强一致(阻塞) 最终一致(异步)
适用场景 备份/分发 分布式配置共享

conf 只是存储载体,真正同步的是”结构化配置状态”

conf/                → 文件存储
    ↓ parse
ConfigSnapshot       → 内存结构(核心同步单元)
    ↓ hash/version
SyncObject           → 网络传输单元

三层一致性模型

一致性类型 同步方式 特点
Config Eventual Consistency Announce + Pull 最终一致、允许延迟、可冲突、低频
Ownership Bounded Consistency Owner Announce + Lease 心跳 弱一致 + 强约束、不允许长期冲突
Runtime Single Writer Owner Only Write 去分布式、避免数据同步爆炸

核心特性:

  • 0配置启动(无 bootstrap / 无证书 / 无手动配置)
  • 局域网自动发现 + 自动组网
  • Hybrid Sync Model(三层模型)
  • 最终一致性(Eventual Consistency)
  • ARMv7 友好(轻量、限流、压缩)

适用于:

  • ARMv7 边缘网关(PLC / OPC-UA / BACnet / ModbusRTU 混合)
  • 工业 OT 网络环境(广播受限 / 丢包 / 延迟)
  • 分布式采集 + 配置共享 + 设备接管

2. 工业层级模型(核心架构)

✅ 唯一正确层级(强约束)

系统 UI 必须收敛为 单一主路径(避免认知混乱):

Gateway(节点)
  └── Channels(通道)
        └── Devices(设备)
              └── Points(点位列表)
                    └── Point Detail(点位详情)

工业语义路径对应关系

层级 对应 conf 文件 同步 Key 格式
Gateway 节点 全量
Channels channels.yaml channel.{id}
Devices devices/*.yaml device.{id}
Points models/*.yaml / 点位定义 point.{id}
PointDetail 单点配置 point.{device}.{id}

✅ UI整体结构

[顶部导航]
  集群总览 | 节点管理 | 配置中心 | 接管 | 事件

[主体布局]
  ├── 左侧:节点选择 + 配置树(核心)
  └── 右侧:详情面板(动态)

✅ 配置树结构(必须严格遵循)

📁 Gateway-A
   └── 📂 channels
         ├── Modbus-1
         │     └── 📂 devices
         │           ├── PLC-01
         │           │     └── 📂 points
         │           │           ├── temp
         │           │           └── pressure
         │           │
         │           └── PLC-02
         │
         └── OPCUA-1
               └── devices

关键约束

  • ❌ 不允许 “设备平铺”
  • ❌ 不允许 “点位独立列表”
  • ✅ 必须走 Channel → Device → Points

3. 核心交互流程

✅ 节点选择(入口)

已发现节点:

🟢 Gateway-A
🟢 Gateway-B  
🟡 Gateway-C

点击 Gateway-A 进入配置树浏览。

✅ 加载配置树(关键API)

GET /api/sync/node/{id}/tree

返回结构:

{
  "channels": [
    {
      "id": "modbus-1",
      "name": "Modbus-1",
      "protocol": "modbus",
      "status": "online",
      "deviceCount": 2,
      "hasDiff": false
    }
  ],
  "northbound": [...]
}

✅ 设备懒加载

GET /api/sync/node/{id}/channel/{channelId}/devices

✅ 点位懒加载

GET /api/sync/node/{id}/device/{deviceId}/points

✅ 点位详情(最终目标)

点击路径:Gateway-A → Modbus-1 → PLC-01 → temp

右侧展示:

{
  "name": "temp",
  "address": "40001",
  "type": "float",
  "scale": 0.1,
  "unit": "°C"
}

4. 右侧详情面板(分层动态切换)

✅ Gateway层

NodeID: xxx
IP: 192.168.1.100
状态: 🟢
版本: v1.2.3

操作: [同步全部] [拉取配置] [查看差异]

✅ Channel层

协议: Modbus TCP
端口: 502
设备数: 5

操作: [同步该通道] [禁用]

✅ Device层

设备: PLC-01
IP: 192.168.1.10
状态: 🟢
点位数: 128

操作: [同步设备] [查看差异] [锁定配置]

✅ Points列表层

点位列表:
temp        float   40001
pressure    float   40002

操作: [批量同步] [对比差异]

✅ Point详情层(最细粒度)

Point: temp
地址: 40001
类型: float
倍率: 0.1
单位: °C

操作: [同步此点] [推送] [回滚]

5. 配置来源映射(conf → UI)

conf/
├── channels.yaml        → Channels
├── devices/*.yaml       → Devices  
├── models/*.yaml        → Points
├── northbound.yaml      → 挂在 Gateway 层
├── edge_rules.yaml      → 全局规则

✅ 关键设计:Points引用模型

必须支持:

Device → 引用 Model → Model定义Points

否则扩展TSL会崩溃。


6. 配置同步粒度

UI层级 Sync Key 格式 说明
Gateway 全量同步 同步所有配置
Channel channel.{id} 同步指定通道
Device device.{id} 同步指定设备
Point point.{device}.{id} 同步单个点位

✅ Sync Record 示例

{
  "key": "device.PLC-01.point.temp",
  "version": 12,
  "hash": "abc123..."
}

6.1 ConfigSnapshot 中间抽象层(核心)

✅ 设计原则

❌ 不同步文件
✅ 同步 Snapshot(结构 + hash)

✅ 映射规则

conf/                → 文件存储
    ↓ parse
ConfigSnapshot       → 内存结构
    ↓ hash/version
SyncObject           → 网络传输单元

✅ Go 数据结构

type ConfigSnapshot struct {
    GatewayID string
    Timestamp int64

    Channels map[string]*Channel
    Devices  map[string]*Device
    Points   map[string]*Point

    // 版本控制
    Version  int64
    Hash     string  // 全量Hash

    // 分层Hash(用于局部更新)
    ChannelHashes map[string]string
    DeviceHashes  map[string]string
    PointHashes   map[string]string
}

✅ conf → Snapshot 映射

conf 文件 → Snapshot 字段
channels.yaml Channels
devices/*.yaml Devices
models/*.yaml Points

6.2 Vector Clock 版本控制(关键)

❗ 问题场景

如果只有简单 version:

A节点:temp.scale = 0.1(version: 12)
B节点:temp.scale = 1.0(version: 12)

→ 谁覆盖谁?(不可控)

✅ 解决方案:向量时钟

type VersionVector map[string]int64  // nodeID → counter
{
  "nodeA": 12,
  "nodeB": 9
}

✅ 合并规则

情况 结果
A > B(所有维度) 接受 A
B > A(所有维度) 接受 B
A 和 B 冲突 标记 CONFLICT

✅ UI 必须显示冲突状态

temp ⚠️ CONFLICT

6.3 两阶段同步(Announce + Pull)

❗ 问题:全量广播不可行

100节点 × 全量广播 = 网络炸

✅ 解决方案:两阶段同步

阶段1:Announce(广播 Hash)

{
  "type": "announce",
  "key": "device.PLC-01",
  "hash": "abc123",
  "versionVector": {"nodeA": 12, "nodeB": 9}
}

阶段2:Pull(按需拉取)

如果 hash 不同 → 请求完整数据

✅ 流程图

节点A 修改配置
    ↓
计算新 Hash
    ↓
广播 Announce(只发 hash)
    ↓
节点B 发现 hash 不同
    ↓
发送 Pull 请求
    ↓
节点A 返回完整 Snapshot
    ↓
节点B 合并/冲突检测

6.4 Diff 引擎升级(三层)

✅ Diff 分层

层级 类型 说明
结构 Diff add/remove 新增设备/删除点位
属性 Diff update 字段值变化
语义 Diff conflict 类型变更(破坏性)

✅ 示例

结构 Diff

+ 新设备 PLC-03
- 删除点位 temp

属性 Diff

scale: 0.1 → 1.0

语义 Diff(危险)

40001(float) → 40001(int)

⚠️ 类型变更(破坏性)

✅ Diff 数据结构

type Diff struct {
    Type   string        // add/remove/update/conflict
    Path   string        // e.g. "device.PLC-01.point.temp.scale"
    Before interface{}
    After  interface{}
    Level  string        // info/warn/critical
}

6.5 AccessMode 工业级接管能力模型(核心)

❗ 现有描述的问题

RTU直连 → 不可接管
TCP/UDP网络 → 可接管

维度不对! 正确维度应该是:

设备访问路径是否可被多节点重入(Re-entrant Access)

✅ AccessMode 定义

type AccessMode string

const (
    AccessExclusive AccessMode = "exclusive" // 独占(不可接管)
    AccessShared    AccessMode = "shared"   // 共享(可接管)
    AccessLease     AccessMode = "lease"    // 租约(可接管但需锁)
)

✅ 设备分类表

设备类型 AccessMode 是否可接管 典型协议
串口直连 exclusive Modbus RTU / IO / DIDO
单连接TCP lease ⚠️(需抢占) PLC / 私有TCP
多客户端协议 shared OPC UA / BACnet / MQTT

✅ 协议级细化(关键!)

协议 AccessMode 原因
Modbus RTU exclusive 串口独占,无法多连接
Modbus TCP lease 通常只允许 1~2 个连接
OPC UA shared 天然支持多客户端
BACnet/IP shared 支持多客户端 + 广播(需限流)
私有TCP协议 lease 单连接,后连踢前连
MQTT shared 发布订阅模式天然共享

❗ 反例警示

Modbus TCP(很多PLC)
只能允许 1~2 个连接

→ 不是 shared,而是 lease
→ 如果多节点同时接入会直接冲突

✅ 设备访问模式推断(建议实现)

func InferAccessMode(protocol string) AccessMode {
    switch protocol {
    case "modbus-rtu", "io", "dido":
        return AccessExclusive
    case "modbus-tcp":
        return AccessLease
    case "opcua", "bacnet", "mqtt":
        return AccessShared
    case "tcp", "私有协议":
        return AccessLease
    default:
        return AccessLease  // 保守默认值
    }
}

6.6 Takeover Lease 租约机制

❗ 问题:多节点同时接管

A 接管 PLC-01
B 也接管 PLC-01
→ 冲突

✅ 解决方案:Lease 租约(仅用于 AccessLease 设备)

type Lease struct {
    DeviceID string
    Owner    string    // GatewayID
    ExpireAt time.Time
    Version  int64
}

✅ 状态机升级(按 AccessMode 区分)

Exclusive 设备

OFFLINE → DETECTED → (禁止接管) → OFFLINE

Shared 设备

OFFLINE → DETECTED → TAKEOVER → RUNNING

Lease 设备

OFFLINE
    → DETECTED
    → TRY_LEASE        ⭐ 尝试获取租约
    → LEASE_GRANTED    ⭐ 租约获批
    → TAKEOVER
    → CONFIG_APPLIED
    → RUNNING

✅ Lease 续约

持有者必须在 LeaseTTL 内续约
否则其他节点可以抢占到 Lease

7. Diff UI(嵌入右侧)

✅ 点位级差异示例

temp

本地:
scale: 0.1

远程:
scale: 1.0 ⚠️

操作: [同步到本地] [推送远程]

8. 设备接管 UI(嵌入 Device层)

✅ 设备信息展示(含 AccessMode)

设备: PLC-01
IP: 192.168.1.10
协议: Modbus TCP

访问模式: 🔁 租约(Lease)

当前控制:
  Gateway-A

状态:
  Lease 剩余 18s

✅ 三种 AccessMode 的 UI 展示

Exclusive 设备

设备: IO-Module-1
协议: Modbus RTU

访问模式: 🔒 独占(Exclusive)

状态: 本地独占设备

[不可接管](按钮禁用)

Shared 设备

设备: OPC-UA-Server-1
协议: OPC UA

访问模式: 🌐 共享(Shared)

当前控制: Gateway-A(逻辑归属)

[直接接管](无确认弹窗)

Lease 设备

设备: PLC-01
协议: Modbus TCP

访问模式: 🔁 租约(Lease)

当前控制: Gateway-B
Lease 剩余: 45s

[接管](弹确认:会踢掉对方)

✅ 接管按钮行为(按 AccessMode 区分)

设备类型 按钮状态 行为
exclusive ❌ 禁用 不允许接管
shared ✅ 直接接管 无确认弹窗
lease ⚠️ 弹确认 显示”会踢掉对方”警告

✅ 接管状态流程

Exclusive:
OFFLINE → DETECTED → (禁止接管)

Shared:
OFFLINE → DETECTED → TAKEOVER → RUNNING

Lease:
OFFLINE → DETECTED → TRY_LEASE → LEASE_GRANTED → TAKEOVER → RUNNING

✅ 设备详情数据结构

type DeviceDetail struct {
    ID          string
    Name        string
    Protocol    string
    AccessMode  AccessMode  // exclusive / shared / lease
    Owner       string      // 当前控制者
    LeaseTTL    int         // Lease 剩余秒数(仅 lease 设备)
}

8.1 设备配置层(devices/*.yaml)

✅ 必须增加的 access 配置

# devices/plc-01.yaml
name: PLC-01
protocol: modbus-tcp
address: 192.168.1.10
port: 502

access:
  mode: lease        # exclusive / shared / lease
  timeout: 30s       # lease 专用租约超时

✅ 按协议自动推断

系统可以根据协议类型自动填入默认 access 配置:

var defaultAccessModes = map[string]AccessMode{
    "modbus-rtu": AccessExclusive,
    "io":         AccessExclusive,
    "dido":       AccessExclusive,
    "modbus-tcp": AccessLease,
    "opcua":      AccessShared,
    "bacnet":     AccessShared,
    "mqtt":       AccessShared,
}

✅ 配置示例

Exclusive 设备

access:
  mode: exclusive

Shared 设备

access:
  mode: shared

Lease 设备

access:
  mode: lease
  timeout: 30s  # 租约超时,建议 30s~60s

8.2 调度器感知

❗ 问题场景

A 节点正在采集 PLC-01
B 节点接管了 PLC-01
→ 双采集冲突

✅ 采集调度必须检查 Owner

func (s *Scheduler) ScheduleCollect(deviceID string) {
    // 如果不是当前节点 owner,暂停采集
    if !s.IsOwner(deviceID) {
        s.pauseCollect(deviceID)
        return
    }

    // 是 owner,开始采集
    s.startCollect(deviceID)
}

✅ Lease 续约期间

func (s *Scheduler) OnLeaseRenewed(deviceID string) {
    // Lease 续约成功,继续采集
    s.resumeCollect(deviceID)
}

func (s *Scheduler) OnLeaseExpired(deviceID string) {
    // Lease 过期,暂停采集
    s.pauseCollect(deviceID)
}

8.3 同步系统过滤规则

❗ 问题场景

节点同步配置
→ 错误接管 RTU 设备
→ 导致本地采集中断

✅ Sync Takeover 过滤

func (sm *SyncManager) CanTakeover(deviceID string) (bool, string) {
    device := sm.getDevice(deviceID)

    switch device.AccessMode {
    case AccessExclusive:
        return false, "独占设备不允许接管"

    case AccessShared:
        return true, "共享设备可直接接管"

    case AccessLease:
        // 检查当前 Lease 状态
        if sm.HasActiveLease(deviceID) {
            owner := sm.GetLeaseOwner(deviceID)
            if owner == sm.localNodeID {
                return false, "当前节点已持有租约"
            }
            return true, "需要抢占租约"
        }
        return true, "可获取租约"
    }

    return false, "未知访问模式"
}

✅ 配置同步时的设备过滤

func (sm *SyncManager) SyncDeviceConfig(deviceID string) error {
    // Exclusive 设备不参与 takeover sync
    if device.AccessMode == AccessExclusive {
        return nil  // 跳过
    }

    // Shared / Lease 设备正常处理
    return sm.doSyncDevice(deviceID)
}

9. 事件流(联动层级)

✅ 事件展示示例

点击某个点位时:

10:01 temp 被修改
10:02 同步到 Gateway-B
10:03 生效

10. 前端实现(Vue结构)

✅ 目录结构

views/
└── sync/
    ├── Cluster.vue          # 集群总览
    ├── NodeTree.vue         # ⭐核心配置树组件
    ├── NodeDetail.vue       # 节点详情
    ├── ChannelDetail.vue    # 通道详情
    ├── DeviceDetail.vue     # 设备详情
    ├── PointList.vue        # 点位列表
    ├── PointDetail.vue      # 点位详情
    └── ConfigDiff.vue       # 配置差异

✅ Pinia Store 拆分

clusterStore   // 节点列表
treeStore      // 树结构(核心)
configStore    // 配置内容
diffStore      // 差异对比
eventStore     // 事件流

✅ TreeNode 接口定义

interface TreeNode {
  type: 'gateway' | 'channel' | 'device' | 'point'
  id: string
  label: string
  status: 'online' | 'offline' | 'degraded' | 'warning'
  hasDiff?: boolean
  children?: TreeNode[]
}

✅ 侧边栏底部版本信息展示(关键)

版本信息通过 goreleaser ldflags 注入二进制,由后端 API 暴露,前端在侧边栏底部实时展示:

后端注入机制

// internal/model/buildinfo.go
var (
    Version   = "dev"      // goreleaser: 
    BuildTime = "unknown"  // goreleaser: 
    CommitID  = "unknown"  // goreleaser: 
)

API 暴露

GET /api/auth/system-info
{
  "code": "0",
  "data": {
    "name": "NODE-LAPTOP-5E3D21EG",
    "softVer": "0.0.4",
    "buildTime": "2026-06-05T14:23:00Z",
    "commitID": "efa219a"
  }
}

UI 侧边栏底部展示

┌──────────────────────────┐
│ ● v0.0.4                │  ← 运行状态指示 + 版本号
│                          │
│ Build  2026-06-05 14:23 │  ← 构建时间
│ Commit efa219a           │  ← Git 短哈希
│                          │
│ [◀ 收起]                 │
└──────────────────────────┘

goreleaser 构建指令

goreleaser release --snapshot --clean --config .goreleaser.yml

ldflags 配置(.goreleaser.yml):

ldflags: >
  -s -w
  -X github.com/anviod/edgex/internal/model.Version=
  -X 'github.com/anviod/edgex/internal/model.BuildTime='
  -X github.com/anviod/edgex/internal/model.CommitID=

输出产物(自动多平台)

dist/
├── edgex-v0.0.4-arm64.deb          # 远程 ARM64 节点安装包
├── edgex-v0.0.4-amd64.deb          # AMD64 安装包
├── edgex-0.0.4-windows-amd64.tar.gz # Windows x64
├── edgex-0.0.4-linux-arm64.tar.gz   # Linux ARM64
└── SHA256SUMS

✅ 远程部署流程(goreleaser + deploy-remote.sh)

一键远程部署

# 1. 构建所有平台安装包
goreleaser release --snapshot --clean --config .goreleaser.yml

# 2. 一键部署到 ARM64 远程节点(root@192.168.3.230)
bash scripts/deploy-remote.sh root@192.168.3.230 NODE-HNE_GATEWAY

# 3. 验证远程节点服务
ssh root@192.168.3.230 "systemctl status edgex --no-pager"
ssh root@192.168.3.230 "curl -s http://localhost:8082/api/auth/system-info"

deploy-remote.sh 自动化流程

1. SSH连接验证 ──► 架构自动检测(aarch64→arm64)
2. 自动查找匹配的 .deb 包
3. scp 传输 ──► 配置备份 ──► 停止旧服务
4. dpkg安装 ──► 配置节点名 ──► systemctl 启动
5. 验证服务状态

本机 - 远程双节点测试架构

┌──────────────────────┐         ┌──────────────────────┐
│ 本机 (Windows/Linux) │  libp2p │ 远程 (root@192.168.3.230) │
│                      │◄───────►│ ARM64 Linux           │
│ goreleaser 构建      │  :4001  │ systemctl edgex       │
│ 本地 run/debug       │         │ .deb 安装部署          │
└──────────────────────┘         └──────────────────────┘

10.1 联机测试方案对齐

本文档所有设计必须与 联机测试方案 中的 35 个测试用例严格对齐。

方案文档 vs 测试用例映射

方案章节 对应测试用例 验证内容
§3 核心交互流程 (NodeTree + 懒加载) TC-27~TC-29, TC-32, TC-33 UI 四级树结构、懒加载、Diff UI
§4 右侧详情面板 TC-31 接管按钮按 AccessMode 分叉
§6 配置同步粒度 TC-04~TC-06 全量/增量/点位级同步
§6.2 Vector Clock TC-14, TC-15 版本比较、冲突检测
§6.3 两阶段同步 (Announce+Pull) TC-04~TC-06 Announce 广播+Pull 拉取
§6.4 Diff 引擎 TC-18~TC-20 结构/属性/语义三层 Diff
§6.5 AccessMode TC-07~TC-09 exclusive/shared/lease 三态接管
§6.6 Takeover Lease TC-09, TC-10 租约抢占、续约、过期
§7 Diff UI TC-29 Diff 对比展示
§8 设备接管 UI TC-31 AccessMode 分叉按钮行为
§8.2 调度器感知 TC-09, TC-10 采集暂停/恢复
§8.3 同步系统过滤 TC-07 Exclusive 设备跳过
§10 版本信息展示 TC-30 sidebar-footer 版本号/构建时间/Commit
§10 远程部署 第4节部署流程 goreleaser 构建 + .deb 部署
§12 后端 API TC-25, TC-26 所有权/租约 API
§18.1 libp2p 优化 TC-01, TC-02 节点发现 (mDNS/静态)
§18.4 最终定位修正 TC-17 一致性检查

测试覆盖完整性

  • P0 测试用例:15 项(节点发现/同步/控制权/设备迁移/一致性)
  • P1 测试用例:20 项(版本管理/Diff/错误处理/UI/并发)
  • 异常测试:8 项(断电/网络分区/崩溃/磁盘满等)
  • 边界测试:6 项(空配置/极长名称等)
  • 性能测试:6 项基准 + 3 项压力

双节点测试拓扑

本机 (NODE-1):  go run cmd/main.go        ← API: localhost:8082
远程 (NODE-REMOTE): systemctl edgex        ← API: 192.168.3.230:8082
              ↕ libp2p:4001 (mDNS + 静态种子)

11. 关键优化(工业级)

✅ 懒加载(必须)

点击 Channel 才加载 Devices
点击 Device 才加载 Points

防止:300设备 × 100点 = 性能问题

✅ 状态叠加(必须)

PLC-01   🟢
PLC-02   🔴

点位警告:

temp   ⚠️

✅ 一致性标记

PLC-01   🟢一致
PLC-02   ⚠️差异

12. 后端 API 设计

✅ 核心接口

API 路径 方法 说明
/api/sync/node/{id}/tree GET 获取配置树结构
/api/sync/node/{id}/devices GET 获取设备列表(懒加载)
/api/sync/node/{id}/points GET 获取点位列表(懒加载)
/api/sync/node/{id}/diff GET 获取差异列表
/api/sync/node/{id}/sync POST 触发同步
/api/sync/node/{id}/takeover POST 触发设备接管

✅ 响应格式规范

{
  "code": 0,
  "message": "success",
  "data": {},
  "timestamp": 1710000000
}

13. 本质总结

✅ 系统定位

这套 UI 最终不是:

❌ “文件浏览器” ❌ “配置管理工具”

而是:

🔥 工业边缘配置控制平面(Config Control Plane)

✅ 核心能力

1️⃣ 可视化配置拓扑(树)
2️⃣ 精确到点位的控制
3️⃣ 跨节点同步
4️⃣ 可解释(事件流)
5️⃣ 可控(接管 + diff)

14. 落地优先级

优先级 任务 说明 对应测试
P0 AccessMode 定义与数据结构 exclusive/shared/lease 三态 TC-07~TC-09
P0 devices/*.yaml access 配置 mode + timeout 字段 TC-11, TC-12
P0 Takeover 状态机升级 按 AccessMode 分支 TC-08~TC-10
P0 Sync Takeover 过滤规则 Exclusive 设备跳过 TC-07
P0 Scheduler Owner 检查 IsOwner + 采集暂停 TC-09, TC-10
P0 全量/增量/点位同步 两阶段 Announce+Pull TC-04~TC-06
P0 节点发现 (mDNS + 静态) Discovery 多级 Fallback TC-01, TC-02
P0 goreleaser 构建 + 远程部署 多平台 .deb + deploy-remote.sh [联机测试 §3-4]
P0 UI 版本信息展示 sidebar-footer Build/Commit TC-30
P1 UI 按 AccessMode 分叉 禁用/直接/弹确认 TC-31
P1 Lease 续约机制 定时续约 + 过期检测 TC-10
P1 Protocol → AccessMode 推断 自动填充默认值 TC-11
P1 Vector Clock 版本控制 版本比较 + 冲突检测 TC-14, TC-15
P1 三层 Diff 引擎 结构/属性/语义 Diff TC-18~TC-20
P1 配置树 UI + 懒加载 GATEWAY→Channel→Device→Point TC-27/28/32/33
P1 错误处理与故障恢复 离线检测/断点续传/重试 TC-21~TC-24
P2 Event Log 集成 事件流展示
P2 并发安全测试 多节点并发修改/接管 TC-34, TC-35

15. 技术栈要求

✅ 前端

  • Vue 3 + Composition API
  • Pinia 状态管理
  • Vue Router 路由
  • Ant Design Vue 组件库

✅ 后端

  • Go 1.21+
  • go-libp2p
  • YAML 解析(gopkg.in/yaml.v3)
  • BadgerDB 持久化(可选)

16. 安全保障

✅ 安全模型

层级 实现 说明
节点认证 PSK 局域网轻量安全
加密 Noise 端到端加密
完整性 Hash 内容校验
网络隔离 局域网 物理隔离

✅ 配置示例

security:
  mode: lan
  psk: auto-generate

17. 部署与运维(0配置 + goreleaser)

✅ 配置示例(极简)

sync:
  enable: true
  mode: lan

无需:bootstrap、peer配置、证书

✅ 完整编译部署流程

详见 联机测试方案 §3-4,摘要:

# 本地开发
go run cmd/main.go

# 生产构建(多平台)
goreleaser release --snapshot --clean --config .goreleaser.yml

# 一键远程部署(ARM64)
bash scripts/deploy-remote.sh root@192.168.3.230 NODE-REMOTE

部署架构

┌──────────────────────┐    goreleaser 构建    ┌────────────────────────┐
│ 本机 (开发机)         │ ──────────────────► │ 远程 root@192.168.3.230 │
│                      │     .deb + scp       │ ARM64 Linux            │
│ go run cmd/main.go   │                      │ systemctl edgex        │
│ goreleaser build     │ ◄──── libp2p ──────► │ .deb 安装部署          │
│ API: :8082           │       :4001          │ API: :8082             │
└──────────────────────┘                      └────────────────────────┘

✅ 运维命令

gateway-cli sync peers      # 查看节点列表
gateway-cli sync status     # 查看同步状态
gateway-cli sync diff       # 查看配置差异

✅ 远程服务管理

# 远程状态
ssh root@192.168.3.230 "systemctl status edgex --no-pager"

# 远程日志
ssh root@192.168.3.230 "journalctl -u edgex -n 100 --no-pager"

# 远程重启
ssh root@192.168.3.230 "systemctl restart edgex"

18. 代码安全性

✅ 风险缓解

风险 措施
广播风暴 限流 + Gossip控制
配置错误传播 版本控制 + 灰度发布
非授权节点 PSK认证 + 角色控制

18.1 libp2p 层工业级优化

❗ 问题清单

问题 影响
mDNS 在工厂被禁 节点发现失败
UDP 广播受限 组网不稳定
Gossip 风暴 网络阻塞

✅ Discovery 多级 Fallback

Discovery 优先级:
1. mDNS(优先,局域网内)
2. UDP Broadcast(可选,企业网)
3. 静态种子节点(最后兜底)

✅ Topic 必须拆分(禁止全量混用)

/config/announce    → 配置变更通知(只发 Hash)
/config/request     → 拉取请求
/config/fullsync   → 全量同步响应
/config/diff        → 差异推送
/takeover          → 设备接管相关
/hello             → 节点心跳/握手

✅ Gossip 限流配置

pubsub.WithPeerOutboundQueueSize(32)    // 出队缓冲
pubsub.WithValidateQueueSize(64)         // 验证队列
pubsub.WithMaxMessageSize(64 * 1024)    // 消息大小限制
pubsub.WithStrictSignatureVerification(true)  // 签名校验

✅ 心跳保活

// 节点超时配置
connectionManager.WithPeerTimeout(30 * time.Second)
keepalive.WithPeriod(15 * time.Second)

18.2 性能优化(大规模节点)

❗ 规模问题

100网关 × 200设备 × 200点位 = 4,000,000 点

✅ 分层 Hash(局部更新)

Gateway Hash
├── Channel Hash
│   ├── Device Hash
│   │   ├── Point Hash

当 only device.PLC-01 变化时:

  • 重新计算 Device Hash
  • 重新计算 Channel Hash
  • 重新计算 Gateway Hash
  • 只广播 Announce(hash 变化)

✅ Debounce 防抖

// 500ms 内多次修改合并一次同步
debounceInterval := 500 * time.Millisecond

✅ Snapshot 分片(可选,大规模时启用)

按 Channel 分片同步
避免全量 Gateway Snapshot 过大

✅ 压缩(可选)

// Snappy 压缩(网络传输时)
snappy.Encode(snapshot)

18.3 conf 镜像目录结构

✅ 正确结构

data/
└── edgex/
    ├── local/              # 本地节点配置(可写)
    │   └── conf/
    ├── peers/             # 远端节点配置镜像(只读)
    │   ├── NODE-A/
    │   │   └── conf/
    │   └── NODE-B/
    │       └── conf/
    └── wal/               # Write-Ahead Log

⚠️ 关键约束

peers 目录必须只读,否则会污染远端配置


✅ 最终架构图(v4.0 工业级完整版)

┌─────────────────────────────────────────────────────────────────────────────────┐
│                    Distributed OT Config Sync System (v4.0)                    │
│         分布式 OT 配置状态同步系统(CRDT-like + AccessMode + Eventual)        │
├─────────────────────────────────────────────────────────────────────────────────┤
│  UI Layer                                                                         │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐           │
│  │ NodeTree    │  │ ConfigDiff │  │ Takeover   │  │ EventLog    │           │
│  │ (懒加载树)   │  │ (三层Diff)  │  │(AccessMode)│  │ (事件流)    │           │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘           │
├─────────┼────────────────┼────────────────┼────────────────┼───────────────────┤
│  Store Layer                                                                      │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐           │
│  │ treeStore   │  │ configStore │  │ diffStore   │  │ leaseStore  │           │
│  │             │  │ (Snapshot)  │  │ (三层Diff)  │  │ (租约管理)   │           │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘           │
├─────────┼────────────────┼────────────────┼────────────────┼───────────────────┤
│  API Layer                                                                        │
│  ┌─────────────────────────────────────────────────────────────────────────┐     │
│  │ /api/sync/node/{id}/tree  /diff  /sync  /takeover                    │     │
│  └──────┬───────────────────────────────────────────────────────────────┘     │
├─────────┼─────────────────────────────────────────────────────────────────────┤
│  Sync Engine (go-libp2p)                                                       │
│                                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────────┐     │
│  │ AccessMode Filter                                                        │     │
│  │ exclusive → skip | shared → direct | lease → try_lease                 │     │
│  └──────┬───────────────────────────────────────────────────────────────┘     │
│                                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────────┐     │
│  │ Discovery(多级 Fallback)                                               │     │
│  │ 1. mDNS → 2. UDP Broadcast → 3. 静态种子                              │     │
│  └──────┬───────────────────────────────────────────────────────────────┘     │
│                                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────────┐     │
│  │ PubSub Topics(严格拆分)                                               │     │
│  │ /config/announce | /config/request | /config/fullsync                  │     │
│  │ /config/diff | /takeover | /hello                                      │     │
│  └──────┬───────────────────────────────────────────────────────────────┘     │
│                                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────────┐     │
│  │ Two-Phase Sync                                                          │     │
│  │ Phase1: Announce(Hash only)→ Phase2: Pull(按需拉取)                 │     │
│  └──────┬───────────────────────────────────────────────────────────────┘     │
│                                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────────┐     │
│  │ Version Control                                                         │     │
│  │ Vector Clock + Diff 三层(结构/属性/语义)                               │     │
│  └─────────────────────────────────────────────────────────────────────────┘     │
├─────────────────────────────────────────────────────────────────────────────────┤
│  Scheduler Layer                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────────┐     │
│  │ Owner-aware Scheduler                                                   │     │
│  │ IsOwner() → pause/resume collect | Lease renewal → collect control     │     │
│  └─────────────────────────────────────────────────────────────────────────┘     │
├─────────────────────────────────────────────────────────────────────────────────┤
│  Storage Layer                                                                   │
│  ┌───────────────────────────────────────────────────────────────────────┐       │
│  │ ConfigStore                                                             │       │
│  │  ├── ConfigSnapshot(内存结构)                                          │       │
│  │  ├── WAL(Write-Ahead Log)                                             │       │
│  │  └── BadgerDB(持久化)                                                 │       │
│  │                                                                          │       │
│  │ peers/(只读镜像)                                                       │       │
│  └───────────────────────────────────────────────────────────────────────┘       │
└─────────────────────────────────────────────────────────────────────────────────┘

18.4 最终定位修正

❌ 之前定位

Config Control Plane(配置控制平面)

✅ 正确工业级定位

分布式 OT 配置状态同步系统(Hybrid Sync Model + CRDT-like + Eventual Consistency + Edge Gossip Bus)


18.5 设备接管工业级定义

设备接管(Takeover)并非简单的”连接切换”,而是基于设备访问模式(AccessMode)的控制权转移机制。

系统将设备划分为三类:

类别 AccessMode 接管行为 典型协议
独占设备 exclusive ❌ 不允许接管 Modbus RTU / IO / DIDO
共享设备 shared ✅ 直接接管(逻辑归属) OPC UA / BACnet / MQTT
租约设备 lease ⚠️ 抢占租约 Modbus TCP / 私有TCP

18.6 ARMv7 优化专题(工业级关键)

✅ 针对 ARMv7 的核心优化

优化项 实现方式 目的
分层 Hash Gateway → Channel → Device → Point 增量同步,减少数据量
二阶段同步 Announce(hash) → Pull(data) 避免全量广播
消息压缩 Snappy(优先)> Gzip 减少网络传输,ARM友好
流量限流 100 msg/sec 保护弱网络
Debounce 500ms 合并多次修改 减少同步频率

✅ 分层 Hash 结构

GatewayHash
    ├── ChannelHash (channel.modbus-1)
    │   ├── DeviceHash (device.PLC-01)
    │   │   ├── PointHash (point.temp)
    │   │   └── PointHash (point.pressure)
    │   └── DeviceHash (device.PLC-02)
    └── ChannelHash (channel.opcua-1)
        └── DeviceHash (device.OPC-Server-01)

✅ 二阶段同步流程

节点A 修改配置
    ↓
计算新的 PointHash → DeviceHash → ChannelHash → GatewayHash
    ↓
广播 Announce(只发 hash,几十字节)
    ↓
节点B 比对本地 Hash
    ↓
如果不同 → 发送 Pull 请求(按需)
    ↓
节点A 返回变化部分的完整数据
    ↓
节点B 合并更新

✅ 明确不建议的方案

方案 问题
❌ 全 Raft Leader 挂了影响全局,网络抖动触发选举风暴,ARM 跑不动
❌ 全量文件同步 无语义,冲突不可控
❌ 全量广播同步 网络炸,CPU 炸

18.7 最终推荐架构

Sync Engine(最终形态)

1. Discovery(mDNS + UDP Broadcast + 静态种子)
2. Gossip(轻量广播,限流)
3. Snapshot Sync(配置层,Announce + Pull)
4. Ownership Sync(控制权,Owner Announce)
5. Lease Manager(租约管理,TTL + 心跳)
6. Runtime Isolation(运行隔离,Owner Only Write)

18.8 P0 实现顺序(强建议)

顺序 任务 说明 验证方式
1 Snapshot + Hash 配置层核心 TC-04 全量同步
2 Gossip Announce 轻量广播 TC-01 节点发现
3 Pull Sync 按需拉取 TC-05 增量同步
4 Ownership + Lease 控制权管理 TC-07~TC-10
5 Scheduler 接入 停止非 Owner 采集 TC-09, TC-10
6 goreleaser + 远程部署 构建 + .deb 部署 [联机测试 §3-4]

联机测试入口:完成每个步骤后,执行 联机测试方案 中对应 Phase 的测试用例进行验证。


版本: v3.0(工业级完整版 + 版本注入 + 远程部署 + 联机测试方案)
日期: 2026-06-05
状态: ✅ 工业级可运行模型完成,版本信息已实现 UI 底部展示,配套完整的 35 项联机测试方案
核心特性: Hybrid Sync Model + ARMv7 优化 + 三层一致性 + goreleaser 多平台构建 + 一键远程部署 + 联机测试全覆盖
配套文档: 联机测试方案 — 编译部署 + 功能测试覆盖 + 35个测试用例