新增中间件相关文档包括 RocketMQ、Nacos、PowerJob 的部署指南和故障分析文档,完善 Keepalived 和 MySQL 的文档内容。新增内部通讯技能模板和示例文件,包括 3P更新、公司通讯、FAQ回答等格式指南。优化服务文档结构,补充 FIX 引擎高可用架构说明。新增中间件综合指南,详细说明高可用部署方案和灾备转换原理。 新增 RocketMQ 5.3.2 集群部署文档,包含 Controller 模式详解和详细配置说明。新增 Nacos 和 PowerJob 部署文档,补充服务依赖和关键配置。更新 MySQL 故障分析文档,优化复制冲突解决流程。新增内部通讯技能模板文件,规范公司内部通讯格式。 docs: 补充服务文档和中间件 TODO 列表 新增 g3fo-exchange-fix-engine-service 服务文档,详细说明服务职责和关键配置。新增中间件 TODO 列表,跟踪待补充的文档内容。更新 Keepalived 部署文档,新增主库抢占前置检查脚本和配置说明。优化中间件文档结构,补充常见问题和性能优化建议。 style: 统一文档格式和代码块样式 统一所有文档的代码块格式和标题层级。优化表格显示样式,增强可读性。规范环境变量和配置项的显示方式。调整文档结构,确保逻辑清晰。修复部分拼写错误和格式问题。 chore: 新增 LICENSE 文件 新增内部通讯技能的 Apache 2.0 LICENSE 文件。补充文档版权信息。更新文件头部的元数据描述。规范文件命名和目录结构。
5.2 KiB
5.2 KiB
FIX Engine 高可用 (HA) 架构方案说明文档
1. 架构演进概述
1.1 原单实例架构
- 消息存储: 使用本地文件系统(FileStore),消息持久化在本地磁盘。
- 灾备能力: 无自动切换机制。若实例宕机,需手动启动备机,且由于文件存储不共享,消息序列号(Sequence Number)难以同步。
- 会话管理: 启动即连接,缺乏灵活性。
1.2 现高可用 (HA) 架构
- 消息存储: 迁移至 MySQL 数据库(JdbcStore)。多实例共享同一数据库,确保消息和序列号在节点切换后保持一致。
- 领导权选举: 引入 Redis 分布式锁(Redisson)。以 Session 为粒度进行选举,确保每个 FIX 会话在全网只有一个活动实例。
- 自动灾备: 备机定时检查锁状态,主节点宕机后锁释放,备机自动接管并恢复连接。
- 动态会话: 结合 DynamicSession 机制,仅在获得领导权后才创建并启动 FIX 连接。
2. 核心组件分析
2.1 MySQL 消息持久化 (JdbcStore)
通过 QuickFixJConfig 配置,系统支持将消息存储从文件切换到 MySQL。
- 核心类:
quickfix.JdbcStoreFactory - 配置触发: 当
StorageType=mysql时启用。 - 数据表要求: 需要在数据库中创建 QuickFIX/J 标准表(如
messages,sessions等)。 - 优势:
- 共享状态: 所有实例访问同一份数据,切换节点无需手动同步序列号。
- 可靠性: 数据库事务保障消息持久化。
2.2 Redis 分布式锁选举 (LeaderElectionService)
使用 Redisson 实现 Session 级别的分布式锁管理。
- 锁 Key 格式:
g3fo:fix-engine:session-lock:{SenderCompID}@{TargetCompID} - 看门狗机制: 租约时间设为 -1,Redisson 自动续期。只要进程存活,锁就不会过期。
- 检查机制: 定时线程(默认 10 秒)遍历所有配置的 Session。
- 宕机延迟 (Failover Delay): 检测到锁释放后,等待 5 秒再尝试抢占,防止因网络抖动引起的频繁切换。
2.3 动态会话控制 (Dynamic Session)
解决 QuickFIX/J 在 start() 时会自动连接所有会话的问题。
- 机制: 在配置文件中将 Session 标记为 Dynamic(不预先加载)。
- 流程:
LeaderElectionService获得 Redis 锁。- 调用
quickFixJConfig.startSession(sessionCode)。 - 内部通过
socketInitiator.createDynamicSession(sessionId)动态创建会话对象。 - 调用
session.logon()触发连接。
3. 完整业务流程
3.1 服务启动流程
flowchart TD
Start([服务启动]) --> InitInitiator[初始化 QuickFIX Initiator]
InitInitiator --> StartElection[启动 LeaderElectionService]
StartElection --> LoadSessions[加载 enabledSession 配置]
LoadSessions --> LoopCheck{遍历每个 Session}
LoopCheck --> TryLock[尝试获取 Redis 分布式锁]
TryLock -- 成功获得锁 --> StartComp[启动会话组件]
StartComp --> CreateDynamic[创建 DynamicSession 对象]
CreateDynamic --> FixLogon[发送 FIX Logon]
FixLogon --> StartMQ[启动对应的 RocketMQ Listener]
TryLock -- 失败 --> Standby[进入待命状态]
Standby --> Wait[等待下一个检查周期]
Wait --> LoopCheck
3.2 宕机自动切换流程 (Failover)
- 主节点 (Node A) 持有
A@OCG的 Redis 锁,正常运行。 - 主节点 (Node A) 宕机或网络断开。
- Redis 锁失效: 经过看门狗租约超时,Redis 中的锁 Key 消失。
- 备节点 (Node B) 定时任务检测到锁已释放。
- 进入延迟等待: 备节点等待
failoverDelay(如 5秒)。 - 抢占锁: 备节点尝试
tryLock,成功获得领导权。 - 恢复连接: 备节点动态创建 Session 并在 MySQL 中读取最新的序列号,发送 Logon。
- 流量接管: 启动 MQ Listener,开始处理业务消息。
4. 关键配置指南 (Nacos)
在 quick-fix-client.yml 中进行如下配置:
quickfixj:
client:
# 启用会话列表
enabledSession: A@OCG,A@OSL
# 选举参数
sessionElection:
checkInterval: 10 # 检查周期(秒)
failoverDelay: 5 # 接管延迟(秒)
# 存储配置(需配合数据源)
# 确保 SessionSettings 中的 StorageType=mysql
5. 日志监控与诊断
通过监控日志可以实时掌握 HA 状态:
| 日志内容 | 含义 | 级别 |
|---|---|---|
>>> 获得Session A@OCG 领导权 <<< |
当前实例成功竞争到主节点 | INFO |
!!! Session A@OCG 领导权锁意外丢失 !!! |
锁异常丢失,可能是 Redis 连接断开 | ERROR |
正在启动Session A@OCG 组件... |
获得锁后开始加载 FIX 和 MQ | INFO |
✅ Session A@OCG 组件启动完成 |
成功恢复服务 | INFO |
未获得领导权,作为备用实例运行中... |
当前为备份节点,正常待命 | DEBUG |
6. 总结
本方案通过 MySQL 共享存储 + Redis 分布式选举 + 动态会话加载 的组合,解决了 FIX 引擎单点故障问题。它不仅保证了消息的连续性(序列号一致),还实现了会话级别的细粒度高可用,能够灵活应对多种部署场景。