跳到主要内容

OPC UA 高可用 (HA)

OPC UA Part 4 §6.6 High Availability 服务器冗余 — 主备双机自动故障切换, 保证 SCADA / MES 连接不中断。


1. OPC UA HA 概述

1.1 什么是 OPC UA 高可用

OPC UA 高可用 (High Availability, HA) 指在主 OPC UA 服务器出现硬件故障、软件崩溃或网络中断时, 备用服务器自动接管客户端连接, 使上层 SCADA、MES 等系统感知不到服务中断。

Darra PLC 实现的 HA 严格遵循 OPC UA Part 4 §6.6 Redundancy 规范, 支持 6 种冗余模式, 与 Darra MultiHost 主备架构深度集成。

1.2 与控制器冗余的区别

层面对象切换粒度标准
OPC UA HA (本文)OPC UA 服务器连接客户端会话级OPC UA Part 4 §6.6
控制器冗余PLC Runtime 整体扫描周期级私有协议
EtherCAT 冗余从站网络链路帧周期级ETG.1500

三者可独立或组合使用。典型场景: 双 PLC 控制器冗余 + 每台控制器运行 OPC UA HA, 构成完整的高可用方案。

1.3 架构总览


2. 六种冗余模式

OPC UA Part 4 §6.6 定义了 6 种 RedundancySupport 模式。Darra PLC 当前支持 NoneColdWarmHot 四类, Transparent 与 HotAndMirrored 为预留。

2.1 模式对比

模式RedundancySupport 值数据同步切换时间客户端感知
None0无冗余
Cold1不同步10-30 s断连重连
Warm2周期性变量同步1-5 s短暂中断
Hot3实时变量同步<1 s轻微延迟
Transparent4完全同步<100 ms无感 (预留)
HotAndMirrored5镜像同步<50 ms完全无感 (预留)

2.2 None (无冗余)

单服务器运行, 无备用节点。适用于非关键场景:

  • 调试 / 开发环境
  • 非连续生产线的监控
  • 测试验证系统

配置: RedundancySupport = None, 不启用 HA 相关服务。

2.3 Cold (冷备)

备用服务器不运行 OPC UA 服务器, 仅监视主服务器心跳:

主运行 ────── 故障 ──→ 备启动 ──→ 客户端重连
↑ ↑
心跳正常 心跳超时 (30s)
  • 优点: 备机零资源消耗
  • 缺点: 切换慢, 客户端需手动或自动重连
  • 适用: 非关键监控, 允许分钟级中断

2.4 Warm (温备)

备用服务器运行 OPC UA 服务器但处于待命状态, 周期性从主服务器同步变量缓存:

2.5 Hot (热备)

备用服务器实时同步变量变化, 主备切换客户端几乎无感:

  • 变量变化通过 DarraLink 实时推送
  • 切换时间 < 1 s
  • 客户端只需重新订阅, 数据不丢失

2.6 Transparent (透明冗余 — 预留)

OPC UA Part 4 定义的透明冗余模式:

  • 多服务器共享同一 ServerUriServerId
  • 客户端连接虚拟地址, 底层透明切换
  • 需 DNS 负载均衡或虚拟 IP 支持
  • Darra 当前预留, 待 R282U+ 实现

2.7 HotAndMirrored (镜像冗余 — 预留)

最高级别的冗余:

  • 主备服务器内存完全镜像
  • 切换时间 < 50 ms
  • 客户端连接完全无感
  • 需专用镜像网络 (RDMA / Shared Memory)
  • Darra 当前预留

3. 配置 RedundancySupport

3.1 配置字段

OPC UA HA 配置通过 Darra.PLC.Serviceappsettings.json 中的 OpcUaHA 节控制:

{
"OpcUaHA": {
"Enabled": false,
"RedundancySupport": "Warm",
"ServerUri": "urn:darra:plc:redundancy-group-1",
"ServerId": "darra-plc-ha-01",

"PeerUris": [
"opc.tcp://192.168.1.10:4840",
"opc.tcp://192.168.1.11:4840"
],

"HealthCheck": {
"IntervalMs": 1000,
"TimeoutMs": 3000,
"MaxMissedHeartbeats": 3,
"HealthEndpoint": "/health/opcua"
},

"ServiceLevel": {
"Primary": 200,
"Standby": 150
},

"SyncConfig": {
"SyncIntervalMs": 1000,
"MaxSyncQueueSize": 10000,
"SyncTimeoutMs": 5000
},

"AutoFailover": true,
"FailbackMode": "Manual"
}
}

3.2 字段说明

字段类型默认值说明
Enabledboolfalse启用 OPC UA HA。默认关闭, 用户 opt-in 才启动心跳
RedundancySupportenumNone冗余模式: None/Cold/Warm/Hot/Transparent/HotAndMirrored
ServerUristring冗余组的统一 URI, 客户端通过此 URI 发现组内所有服务器
ServerIdstring本服务器在冗余组内的唯一标识
PeerUrisstring[]冗余组内所有对等服务器的端点 URL 列表
HealthCheck.IntervalMsint1000心跳发送间隔 (ms)
HealthCheck.TimeoutMsint3000等待对端心跳响应的超时时间 (ms)
HealthCheck.MaxMissedHeartbeatsint3连续丢失心跳次数阈值, 超过则判为故障
HealthCheck.HealthEndpointstring/health/opcua健康检查 HTTP 端点路径
ServiceLevel.Primaryint200本机作为主服务器时的 ServiceLevel 值
ServiceLevel.Standbyint150本机作为备服务器时的 ServiceLevel 值
SyncConfig.SyncIntervalMsint1000变量同步间隔 (ms), 仅 Warm/Hot 模式生效
SyncConfig.MaxSyncQueueSizeint10000同步队列最大长度, 超限丢弃最旧条目
SyncConfig.SyncTimeoutMsint5000单次同步操作超时 (ms)
AutoFailoverbooltrue自动故障切换。关闭时仅标记不切换
FailbackModeenumManual恢复模式: Manual(手动切回) / Automatic(自动回切)

3.3 ServiceLevel 设计

ServiceLevel (0-255) 是 OPC UA Part 4 定义的服务质量指标:

  • 255: 最高质量, 通常为主服务器
  • 200: 推荐的主服务器默认值
  • 150: 推荐的备服务器默认值
  • 100: 备服务器负载较高
  • 50: 备服务器降级运行
  • 0: 服务器不可用

客户端根据 ServiceLevel 选择连接服务器。当主服务器故障, ServiceLevel 降至 0, 客户端自动重连到当前 ServiceLevel 最高的可用服务器。


4. 健康检查与故障检测

4.1 心跳机制

OPC UA HA 通过周期心跳维护集群成员状态:

4.2 故障检测流程

[心跳丢失] → [超时计数] → [阈值判定] → [故障切换] → [恢复检测]
↓ ↓ ↓ ↓ ↓
连续 3 次 MaxMissed AutoFailover 备提升为主 FailbackMode
无响应 达到 3 = true ServiceLevel 决定策略
  1. 每个心跳周期检查对等服务器响应
  2. 连续丢失 MaxMissedHeartbeats 次心跳 → 判定故障
  3. AutoFailover = true → 自动触发切换
  4. 备服务器 ServiceLevel 提升至 Primary 值
  5. 客户端根据 ServiceLevel 变化自动迁移连接

4.3 防抖保护

单次心跳丢失不触发切换, 需连续 MaxMissedHeartbeats 次确认故障:

  • 网络抖动时避免误切换
  • 每次心跳丢失记录日志 (含时间戳、对端 URI)
  • 切换触发时记录事件到 AlarmManager

4.4 恢复与回切

// FailbackMode 枚举
public enum FailbackMode
{
/// <summary>手动回切 — 工程师确认后操作</summary>
Manual,

/// <summary>自动回切 — 主恢复后自动降备</summary>
Automatic
}

Manual (推荐): 主服务器恢复后不自动切换, 由工程师确认后手动执行 Failover 操作。防止反复切换导致客户端抖动。

Automatic: 主服务器恢复后自动切回, ServiceLevel 恢复至 Primary 值。适用于短暂故障场景。


5. 与 Darra MultiHost 的集成

5.1 架构关系

Darra MultiHost (控制器冗余)
├── 主 PLC Runtime (192.168.1.10)
│ └── OPC UA HA 主服务器 (ServiceLevel=200)
│ ├── 变量命名空间
│ ├── 报警管理
│ └── 历史数据

└── 备 PLC Runtime (192.168.1.11)
└── OPC UA HA 备服务器 (ServiceLevel=150)
├── 变量命名空间 (同步镜像)
├── 报警管理 (同步)
└── 历史数据 (独立)

5.2 变量同步

MultiHost 通过 DarraLink 18821 通道周期同步变量变化到备机:

主 PLC 变量变化
→ PLC 扫描周期结束
→ MultiHost 检测变量 diff
→ 通过 DarraLink 推送增量到备机
→ 备机更新本地变量缓存
→ 备机 OPC UA 服务器可读取最新值
  • 同步粒度: 仅同步变化变量 (增量), 非全量
  • 同步频率: SyncIntervalMs 配置, 默认 1000 ms
  • 同步队列上限: MaxSyncQueueSize, 超限丢弃最旧

5.3 切换协调

当 MultiHost 检测到主 PLC Runtime 故障时:

  1. MultiHost 触发控制器切换
  2. 备 PLC Runtime 提升为主
  3. 备 OPC UA HA 服务器 ServiceLevel → 200
  4. 客户端通过 ServiceLevel 变化感知切换
  5. 新主服务器接受客户端连接

6. 配置示例

6.1 双机温备 (推荐)

{
"OpcUaHA": {
"Enabled": true,
"RedundancySupport": "Warm",
"ServerUri": "urn:darra:plc:ha-group-production",
"ServerId": "darra-plc-line1-pri",
"PeerUris": [
"opc.tcp://192.168.1.10:4840",
"opc.tcp://192.168.1.11:4840"
],
"HealthCheck": {
"IntervalMs": 1000,
"TimeoutMs": 3000,
"MaxMissedHeartbeats": 3,
"HealthEndpoint": "/health/opcua"
},
"ServiceLevel": {
"Primary": 200,
"Standby": 150
},
"SyncConfig": {
"SyncIntervalMs": 1000,
"MaxSyncQueueSize": 10000,
"SyncTimeoutMs": 5000
},
"AutoFailover": true,
"FailbackMode": "Manual"
}
}

6.2 单机无冗余 (默认)

{
"OpcUaHA": {
"Enabled": false,
"RedundancySupport": "None",
"ServerUri": "urn:darra:plc:standalone",
"ServerId": "darra-plc-line1-single",
"PeerUris": [],
"AutoFailover": false,
"FailbackMode": "Manual"
}
}

6.3 三机热备集群

{
"OpcUaHA": {
"Enabled": true,
"RedundancySupport": "Hot",
"ServerUri": "urn:darra:plc:ha-cluster-3node",
"ServerId": "darra-plc-node-01",
"PeerUris": [
"opc.tcp://192.168.1.10:4840",
"opc.tcp://192.168.1.11:4840",
"opc.tcp://192.168.1.12:4840"
],
"HealthCheck": {
"IntervalMs": 500,
"TimeoutMs": 1500,
"MaxMissedHeartbeats": 5,
"HealthEndpoint": "/health/opcua"
},
"ServiceLevel": {
"Primary": 255,
"Standby": 200
},
"SyncConfig": {
"SyncIntervalMs": 200,
"MaxSyncQueueSize": 50000,
"SyncTimeoutMs": 2000
},
"AutoFailover": true,
"FailbackMode": "Automatic"
}
}

7. 监控与诊断

7.1 关键指标

指标获取方式正常范围说明
当前角色IOpcUaHAService.RolePrimary / Standby本机当前角色
ServiceLevelIOpcUaHAService.ServiceLevel0-255服务质量等级
对端心跳IOpcUaHAService.PeerStatesConnected每个对等服务器的连接状态
同步延迟IOpcUaHAService.SyncLagMs< 1000 ms变量同步延迟
切换次数IOpcUaHAService.FailoverCount累计故障切换次数
最后切换时间IOpcUaHAService.LastFailoverTime最后一次切换时间戳
同步队列深度IOpcUaHAService.SyncQueueDepth< 5000待同步变量数量

7.2 日志诊断

HA 相关日志输出到 %AppData%/DarraPLC/logs/service_*.log, 模块名 OpcUaHA:

[2026-06-10 08:00:00.123] [Info] [OpcUaHA] 心跳发送: peer=opc.tcp://192.168.1.11:4840 seq=1024
[2026-06-10 08:00:00.456] [Info] [OpcUaHA] 心跳接收: peer=opc.tcp://192.168.1.11:4840 ServiceLevel=150 rtt=2ms
[2026-06-10 08:01:05.789] [Warn] [OpcUaHA] 心跳超时: peer=opc.tcp://192.168.1.10:4840 missed=1/3
[2026-06-10 08:01:07.012] [Warn] [OpcUaHA] 心跳超时: peer=opc.tcp://192.168.1.10:4840 missed=2/3
[2026-06-10 08:01:08.345] [Error] [OpcUaHA] 心跳超时: peer=opc.tcp://192.168.1.10:4840 missed=3/3 → 触发故障切换
[2026-06-10 08:01:08.400] [Info] [OpcUaHA] 故障切换: newRole=Primary oldRole=Standby reason=HeartbeatTimeout
[2026-06-10 08:01:08.500] [Info] [OpcUaHA] ServiceLevel 更新: 150 → 200

8. 限制与注意事项

8.1 当前限制

限制项说明计划解除
最大冗余节点数当前支持 2-3 节点R282U+
Transparent 模式未实现R282U+
HotAndMirrored 模式未实现待定
OPC Foundation CTT未完成一致性测试R282U+

8.2 部署建议

  1. 默认关闭: Enabled = false, 用户确认网络拓扑后手动启用
  2. 双网隔离: 心跳网络与业务网络物理隔离, 防心跳风暴
  3. 时钟同步: 所有节点启用 NTP, 确保时间戳一致性
  4. ServiceLevel 阶梯: 主备 ServiceLevel 保持差距 (如 200 vs 150), 防选主冲突
  5. Manual 回切: 生产环境推荐 Manual 模式, 工程师确认后再切回
  6. 日志持久化: HA 日志独立文件, 便于故障复盘

9. API 参考

9.1 IOpcUaHAService 接口

public interface IOpcUaHAService : IDisposable
{
/// <summary>当前冗余模式</summary>
RedundancySupport RedundancySupport { get; }

/// <summary>本机当前角色</summary>
ServerRole Role { get; }

/// <summary>当前 ServiceLevel (0-255)</summary>
byte ServiceLevel { get; }

/// <summary>注册对等服务器</summary>
void RegisterPeer(string serverUri, byte serviceLevel);

/// <summary>手动触发故障切换</summary>
Task<FailoverResult> FailoverAsync(string targetServerUri);

/// <summary>查询对等服务器状态</summary>
PeerState QueryPeerState(string serverUri);

/// <summary>冗余状态变化事件</summary>
event EventHandler<RedundancyEventArgs> RedundancyChanged;
}

public enum RedundancySupport
{
None = 0,
Cold = 1,
Warm = 2,
Hot = 3,
Transparent = 4,
HotAndMirrored = 5
}

public enum ServerRole
{
Unknown,
Primary,
Standby
}

public enum FailoverReason
{
Manual,
HeartbeatTimeout,
ServiceLevelDegraded,
AdminRequest
}

9.2 健康检查端点

备服务器通过 HTTP GET 对等服务器的 /health/opcua 端点获取健康状态:

GET /health/opcua HTTP/1.1
Host: 192.168.1.10:4840

HTTP/1.1 200 OK
Content-Type: application/json

{
"serverId": "darra-plc-line1-pri",
"role": "Primary",
"serviceLevel": 200,
"uptimeMs": 86400000,
"syncLagMs": 12,
"peerCount": 1,
"timestamp": "2026-06-10T08:00:00Z"
}

10. 常见问题

Q: 客户端如何感知服务器切换?

A: 客户端通过 ServiceLevel 变化感知。当主服务器故障, 其 ServiceLevel 降至 0; 客户端定期查询服务器 ServiceLevel, 发现当前连接服务器 ServiceLevel = 0 时自动重连到 ServiceLevel 最高的可用服务器。

Q: 切换过程中数据会丢失吗?

A: Warm 模式下, 同步周期内的变量变化可能丢失 (最多丢失 SyncIntervalMs 窗口数据)。Hot 模式通过实时推送减少丢失窗口。

Q: 如何手动触发切换?

A: 调用 IOpcUaHAService.FailoverAsync(targetServerUri), 或在 IDE 远程诊断面板中操作。

Q: 是否可以超过 3 个节点?

A: 当前限制 2-3 节点。R282U+ 计划扩展至 N 节点集群。


本节内容对应 R276U-R280U OPC UA HA Part 4 实现, 详见 PRODUCT.md §二十六。