跳到主要内容

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 当前支持 None、Cold、Warm、Hot 四类, 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 定义的透明冗余模式:

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

2.7 HotAndMirrored (镜像冗余 — 预留)​

最高级别的冗余:

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

3. 配置 RedundancySupport​

3.1 配置字段​

OPC UA HA 配置通过 Darra.PLC.Service 的 appsettings.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 §二十六。