Files
ken.li 3525aee49e feat: 新增中间件文档和内部通讯技能
新增中间件相关文档包括 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 文件。补充文档版权信息。更新文件头部的元数据描述。规范文件命名和目录结构。
2026-01-23 17:15:16 +08:00

5.2 KiB
Raw Permalink Blame History

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(不预先加载)。
  • 流程:
    1. LeaderElectionService 获得 Redis 锁。
    2. 调用 quickFixJConfig.startSession(sessionCode)。
    3. 内部通过 socketInitiator.createDynamicSession(sessionId) 动态创建会话对象。
    4. 调用 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)

  1. 主节点 (Node A) 持有 A@OCG 的 Redis 锁,正常运行。
  2. 主节点 (Node A) 宕机或网络断开。
  3. Redis 锁失效: 经过看门狗租约超时,Redis 中的锁 Key 消失。
  4. 备节点 (Node B) 定时任务检测到锁已释放。
  5. 进入延迟等待: 备节点等待 failoverDelay (如 5秒)。
  6. 抢占锁: 备节点尝试 tryLock,成功获得领导权。
  7. 恢复连接: 备节点动态创建 Session 并在 MySQL 中读取最新的序列号,发送 Logon。
  8. 流量接管: 启动 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 引擎单点故障问题。它不仅保证了消息的连续性(序列号一致),还实现了会话级别的细粒度高可用,能够灵活应对多种部署场景。