深色模式
系统架构与数据流
本页说明
讲什么:系统边界与技术栈、32 个微服务的分层关系、数据库架构与同步管线、服务间通信协议与延迟分析、一笔入金/出金从发起到完成经过哪些服务和数据表、银行流水采集频率、请求链路追踪示例、监控与告警体系,以及常见延迟瓶颈与排查思路 适合谁:需要理解系统技术全貌的产品经理和运营人员 前置阅读:新人导读预计阅读:12 分钟 负责人:出入金产品团队
核心要点:系统由 32 个微服务组成,按 PHP 业务逻辑层、Go/Python 银行对接层、Python SBA 编排层三级分工——理解分层关系是定位问题和评估变更影响的关键。
技术栈概览
| 层级 | 技术 | 组件 | PM 关注点 |
|---|---|---|---|
| 业务逻辑 | PHP/Lumen 5.5 | 入金(deposit/)、出金(withdraw/)、银行卡(bankcard_service/)、现金(cash/) | 核心业务 API,延迟敏感——直接影响 App 响应速度 |
| 银行接入 | Go + Python 混合 | Go:中银流水、广发FPS、渣打、黑白名单、天星网关;Python:SBA编排、汇丰、工银、招行、民生 | 银行通道多语言异构——排查时需找对语言栈的日志 |
| 通信协议 | Protobuf RPC + HTTP REST | SRPC(内部同步)、HTTP(CRM/外部)、SM2 Socket(招行/民生) | SRPC 超时 → 单笔入金/出金卡住;HTTP 超时 → CRM 操作失败 |
| 银行协议 | B2E XML / MT910 / SFTP+GPG / SM2 加密 / REST API | 每家银行一种协议 | 不同协议决定了流水获取速度和自动化程度 |
| 存储 | MySQL(分表)+ Elasticsearch(Canal 同步)+ Redis | 主库分 100 表、ES 全文搜索、Redis 缓存+锁 | CRM 搜索走 ES(秒级延迟),不直接查数据库 |
| 消息 | Redis 事件队列 + RabbitMQ | 内部异步事件 + 跨服务解耦 | 队列积压 → 批量入金/出金延迟 |
32 个微服务分类
完整服务清单
核心业务(4 个)
| 服务 | 语言 | 端口 | 职责 | 对外接口 |
|---|---|---|---|---|
deposit/ | PHP | 20001 | 入金申请、银行流水、匹配、审批、在途资金、对账 | SRPC + HTTP REST |
withdraw/ | PHP | 20002 | 出金申请、三步审批(Audit→Confirm→Remittance)、银行通道 | SRPC + HTTP REST |
cash/ | PHP | 20003 | 现金服务 API 和批处理 | HTTP REST |
bankcard_service/ | PHP | 20005 | 银行卡全生命周期管理(绑定/验证/解绑) | HTTP REST |
银行接入层(13 个)
| 服务 | 语言 | 银行 | 职责 | 通信方式 | 调用方向 |
|---|---|---|---|---|---|
bochk_flow_go/ | Go | 中银 | B2E 协议解析、流水转换 | B2E XML | moomoo → 银行(主动拉取) |
bochk_deposit_mgr/ | Python | 中银 | 入金编排管理 | SRPC | 内部调用 |
bochk_fts_mgr/ | Python | 中银 | FTS(汇款)管理 | SRPC | 内部调用 |
bochk_relay/ | Python | 中银 | 请求转发代理 | HTTP | 内部转发 |
hsbc_bank_flow_service/ | Python | 汇丰 | MT910 流水解析、SFTP 拉取、GPG 加密 | SFTP+GPG | 银行 → moomoo(推送+拉取) |
hsbc_edda_report/ | Python | 汇丰 | eDDA 报表下载 | SFTP | moomoo → 银行(定时拉取) |
sba_hsbc_eddi/ | Python | 汇丰 | eDDA/eDDI 入金代扣集成 | REST API | moomoo → 银行(发起+轮询) |
sba_hase_eddi/ | Python | 恒生 | eDDA/eDDI 入金代扣集成 | REST API | moomoo → 银行(发起+轮询) |
scb_service/ | Go | 渣打 | FPS RPC 接口 | SRPC | moomoo → 银行 |
cgb_fps_service/ | Go | 广发 | FPS 实时转账 | SM2 加密 | moomoo → 银行 |
icbc_be_relay/ | Python | 工银 | 银企互联中继 | RSA 验签 | moomoo → 银行 |
cmb_stock_trans/ | Python | 招行 | 银证转账(Socket 二进制双向链路) | SM2 Socket | 双向实时 |
ms_stock_bank_transaction/ | Python | 民生 | 银证转账 | SM2 Socket | 双向实时 |
SBA 编排层(3 个)
| 服务 | 语言 | 职责 | 状态数 |
|---|---|---|---|
sba_deposit_system/ | Python | 入金编排:创建→审核→风控变更→入账,支持 6 种入金模式 | 6 |
sba_cash_withdraw_system/ | Python | 出金编排:冻结→扣款→转账→释放,支持 4 阶段 17 种状态 | 17 |
sba_fund_withdraw/ | Python | 基金出金:货币基金赎回→出金一键编排 | — |
风控(3 个)
| 服务 | 语言 | 职责 | 运营关联 |
|---|---|---|---|
hk-deposit-blacklist-go/ | Go | 入金黑名单(批量增删查) | 命中时入金被拦截,Procedure → manual_confirm |
hk-deposit-whitelist-go/ | Go | 入金白名单 | 白名单内用户走快速通道,跳过人工审核 |
hk-withdraw-blacklist-go/ | Go | 出金黑名单 | 命中时出金进入人工审核队列 |
其他(9 个)
| 服务 | 语言 | 职责 | 状态 |
|---|---|---|---|
bank-card/ | PHP | 银行卡基础 API | 遗留服务,逐步迁移到 bankcard_service |
cash_service/ | PHP | 现金服务扩展 | 活跃 |
refund/ | PHP | 退款处理 | 活跃 |
airstar_service/ | Go | 天星银行支付网关(Mandate 授权/入金/出金) | 活跃——天星 BST 的核心 |
sync_bst_data_helper/ | Python | 招行异常流水恢复 | 补偿服务——招行 Socket 断连时使用 |
tools-pic-upload/ | Go | 凭证图片上传 | 活跃 |
bank_conn_doc/ | - | 银行对接规范文档(汇丰/中银/恒生/工银/EWB/浦发) | 文档仓库 |
procedure_system/ | Python | 流程编排系统(SBA 核心框架) | 活跃——SBA 的底层引擎 |
数据库架构
三个核心数据库
| 数据库 | 归属服务 | 核心表 | 分表策略 | 预计数据量 |
|---|---|---|---|---|
| 主库(cash_deposit / cash_withdraw) | deposit/、withdraw/、cash/、refund/ | applys、flows、matches、tasks、queue | applys 按 uid 取模分 100 表;flows 按银行类型+月份分表 | 百万级/月 |
| web_account | bankcard_service/ | bank_card、bank_info、bank_card_certificate、bank_card_asb_bst、bank_card_edda | 不分表 | 十万级 |
| SBA Procedure 库 | procedure_system/、sba_*_system/ | proc_info、proc_cash_deposit、proc_cash_withdraw、flow | 不分表 | 百万级/月 |
三个库物理隔离,服务之间通过 RPC 调用而非直接跨库查询。
分表对运营的影响
入金申请表 applys 按用户 ID 分了 100 张表(applys_00 到 applys_99)。CRM 搜索不受影响(走 ES),但如果需要直接查库排查,需要先算出用户 ID 对应的表后缀:uid % 100。
银行流水表 flows 按银行+月份分表(如 flows_bochk_202604),跨月查询需要指定正确的月份。
出金任务表 tasks 不分表,但数据量大时按 created_at + status 建索引查询。
SBA Procedure 表 proc_info 不分表,通过 id 或 nn_uid + biz_type 查询。
数据同步管线(Canal CDC → Elasticsearch)
CRM 运营后台支持按卡号、用户名、银行流水号等做模糊搜索——这不是直接查数据库,而是查 Elasticsearch。数据通过 Canal(阿里开源的 MySQL Binlog 订阅工具)实时同步:
PM 视角:CRM 搜索结果几乎实时(秒级延迟)。如果搜索结果"找不到",不一定是数据不存在——可能是 Canal 同步延迟,等几秒再搜通常就有了。
Canal 同步的实体
| 实体 | 源表 | ES 索引用途 | 支持的搜索字段 | CRM 搜索入口 |
|---|---|---|---|---|
ApplySync | 入金申请 applys | CRM 入金列表搜索 | uid, 银行卡号, 金额, 状态, 创建时间 | 入金管理 → 搜索框 |
FlowSync | 银行流水 flows | CRM 流水搜索、匹配排查 | 流水号, 金额, 银行, 币种, 入账时间 | 流水管理 → 搜索框 |
TaskSync | 出金任务 tasks | CRM 出金列表搜索 | uid, 目标卡号, 金额, 状态, 创建时间 | 出金管理 → 搜索框 |
FileSync | 凭证文件 | CRM 凭证搜索 | 文件名, 上传时间, 关联 uid | 凭证管理 |
DepositSbaListSync | 入金 SBA 关联 | 入金-Procedure 关联查询 | apply_id, procedure_id | 入金详情 → SBA 关联 |
ApplyAdditionSync | 入金附加信息 | 补充搜索字段 | 备注, 附加标记 | 入金详情 → 附加信息 |
搜索不到记录时的排查顺序:
- 等 5-10 秒重新搜索(Canal 同步延迟)
- 换搜索条件试(如用 uid 代替卡号)
- 检查 Canal Consumer 日志是否有报错
- 直接查数据库确认数据是否存在
服务间通信方式
| 协议 | 使用场景 | 典型调用 | 特点 | PM 意义 |
|---|---|---|---|---|
| SRPC(Protobuf RPC) | 核心服务 ↔ SBA / 风控 | deposit/ 调用 CashDepositCreate | 同步、强类型、毫秒级 | 超时直接影响用户等待时间 |
| HTTP REST | 银行卡服务 / 天星网关 / CRM | CRM 调用 /bank_card/get_list | 标准 Web API | 易于监控和调试 |
| SM2 Socket | 招行/民生银证 | 二进制双向链路 | 长连接、实时推送 | 银行侧结果秒级到达 |
| REST API(轮询) | 天星银证 / 汇丰恒生 eDDA | AsbBstCreateResultJob 轮询 | 需主动查询 | 用户等待时间更长 |
| RabbitMQ | 交易通知→风控;跨服务异步 | RmqReportMsg 触发风控更新 | 异步解耦 | 队列积压影响批量处理 |
通信方式对延迟的影响
| 场景 | 通信链路 | 典型延迟 | 延迟原因 | 影响范围 |
|---|---|---|---|---|
| BST 入金(招行/民生) | SM2 Socket 实时推送 | 秒级 | 银行主动推送结果 | 单笔 |
| BST 入金(天星) | REST API + 轮询 | 秒~分钟级 | 需轮询最多 60 次 | 单笔 |
| BST 出金(天星) | REST API + 轮询 | 秒~分钟级 | 需轮询最多 10 次 | 单笔 |
| eDDA 代扣入金 | REST API + 轮询 | T+0~T+1 | 银行异步处理 | 单笔 |
| 普通入金匹配 | 定时任务 | 3 分钟一轮 | 匹配引擎定时扫描 | 批量 |
| 网银出金 | 人工操作 | 小时~天级 | 依赖运营在银行网银转账 | 单笔 |
| CRM 搜索 | Canal CDC → ES | 秒级 | Binlog 同步延迟 | CRM |
PM 视角:如果一笔入金延迟异常,瓶颈可能在 SRPC 同步调用(如 SBA 创建 Procedure 超时)或 Canal 异步队列积压。SRPC 问题影响单笔,队列积压影响批量。
入金数据流:一笔钱如何到账
普通入金(用户视角)
| 步骤 | 用户操作 | 用户感知 | 预计耗时 |
|---|---|---|---|
| 1 | 在 App 选择银行卡,获取入金账户信息 | 看到 moomoo 收款账号 | 即时 |
| 2 | 在银行 App/网银转账到 moomoo 账户 | 银行显示转账成功 | 1-5 分钟 |
| 3 | 等待系统匹配入账 | App 显示"入金处理中" | 3 分钟~数小时 |
| 4 | 入金完成 | App 余额增加,收到通知 | — |
系统视角
入金数据经过的核心表
| 阶段 | 表名 | 分表规则 | 说明 | 运营查看位置 |
|---|---|---|---|---|
| 1. 用户申请 | applys_{00-99} | uid % 100 | 一条 = 一笔入金申请 | CRM → 入金管理 |
| 2. 银行流水 | flows_{bankType}_{YYYYMM} | 银行类型 + 月份 | 一条 = 一笔银行流水 | CRM → 流水管理 |
| 3. 匹配 | matches_{shard} | — | Flow 与 Apply 的关联记录 | CRM → 匹配记录 |
| 4. 入金任务 | deposits_{shard} | — | 已匹配的入金任务 | CRM → 入金列表 |
| 5. 异常 | abnormal_deposits | 不分表 | 异常流水单独跟踪 | CRM → 异常入金 |
| 6. SBA | proc_info + proc_cash_deposit | 不分表 | Procedure 追踪记录 | CRM → SBA 管理 |
入金 Procedure 的完整状态机和字段说明 → SBA 资金编排 § 入金 Procedure 状态机
出金数据流:一笔钱如何汇出
出金(用户视角)
| 步骤 | 用户操作 | 用户感知 | 预计耗时 |
|---|---|---|---|
| 1 | 在 App 选择出金银行卡和金额 | — | 即时 |
| 2 | 确认出金 | 可用余额减少(冻结) | 即时 |
| 3 | 等待系统处理 | App 显示"出金处理中" | BST 秒级 / 网银 小时级 |
| 4 | 出金完成 | 收到出金成功通知 | — |
| 5 | 银行到账 | 银行卡收到资金 | 1-3 个工作日 |
系统视角
出金数据经过的核心表
| 阶段 | 表名 | 说明 | 运营查看位置 |
|---|---|---|---|
| 1. 创建任务 | tasks | 出金任务核心记录 | CRM → 出金管理 |
| 2. 操作流水 | flows | 每步审批的操作日志(staff_id, action, step) | CRM → 操作记录 |
| 3. 事件队列 | queue | 异步事件(银证同步、高风险检查等) | 系统内部 |
| 4. SBA 跟踪 | sba_list | 出金 Task ↔ SBA Procedure 关联 | CRM → SBA 状态 |
| 5. 银证设置 | auto_settings | 按银行×币种的自动审批余额/上限配置 | CRM → 银证设置 |
| 6. 银行流水 | cmb_list / ms_list | 招行/民生银行侧发起的出金记录 | CRM → 银证出金 |
出金 Procedure 的完整状态机(17 个状态)和冻结-转账-释放模式 → SBA 资金编排 § 出金 Procedure 状态机
银行流水采集频率
不同银行的流水数据获取方式和频率差异很大——这直接影响入金到账速度:
| 银行 | 采集方式 | 频率 | 说明 | 入金到账预期 | 自动化程度 |
|---|---|---|---|---|---|
| 中银 BOCHK | B2E 主动拉取 | 每日 3 次(06:00/07:00/08:00)+ 2 小时转换 | TodayActivity→AcctStatement→AcctActivity | T+0(当日) | 半自动 |
| 汇丰 HSBC | MT910 实时推送 + SFTP 拉取 | 实时 + 批量兜底 | Transaction Reference Number 去重 | 分钟级 | 全自动 |
| 工银 ICBC | 银企互联主动拉取 | 每日实时拉取 | 按日期区间查询,RSA 验签 | T+0 | 半自动 |
| 招行 CMB | 双向链路被动接收 | 事件驱动(实时) | 银行发起时实时接收 | 秒级 | 全自动 |
| 民生 MS | 双向链路被动接收 | 事件驱动(实时) | 银行发起时实时接收 | 秒级 | 全自动 |
| 天星 ASB | REST API 轮询 | 轮询(最多 60 次) | 入金创建后轮询结果 | 秒~分钟级 | 全自动 |
| 恒生 HASE | eDDA 代扣 + REST API | 代扣发起后轮询 | 通过 sba_hase_eddi 处理 | T+0~T+1 | 全自动 |
| EWB | CSV + BAI2 文件 | 按需上传 | CSV 去重 + BAI2 补充名称 | 人工处理 | 手动 |
| 其他银行 | 入金匹配任务扫描 | 每 3 分钟 | CCB Asia、DBS、众安等 | 3 分钟~小时级 | 半自动 |
流水获取延迟 ≠ 到账延迟
流水获取只是入金流程的第一步。之后还需要匹配引擎比对(每 3 分钟一轮)、SBA 创建 Procedure、风控变更等步骤。BST 银证通道跳过了匹配步骤(直接创建 Procedure),所以到账最快。
各环节延迟叠加估算:
| 入金通道 | 流水获取 | 匹配 | SBA + 风控 | 总计 |
|---|---|---|---|---|
| BST(招行/民生) | 秒级 | 跳过 | 毫秒级 | 秒级 |
| BST(天星) | 秒~3 分钟 | 跳过 | 毫秒级 | 秒~3 分钟 |
| eDDA(恒生/汇丰) | T+0~T+1 | 跳过 | 毫秒级 | T+0~T+1 |
| 普通入金(汇丰) | 分钟级 | 3 分钟 | 毫秒级 | 3~10 分钟 |
| 普通入金(中银) | 当日 3 次 | 3 分钟 | 毫秒级 | 小时级 |
| 普通入金(其他) | 3 分钟 | 3 分钟 | 毫秒级 | 6~30 分钟 |
请求链路追踪
入金链路示例:一笔招行 BST 入金
用户在招行App发起银证入金 10,000 HKD
↓
① cmb_stock_trans 收到 SM2 Socket 推送(< 1秒)
→ 解密报文,提取:卡号、金额、币种、市场
↓
② deposit/ 收到入金通知(SRPC,< 100ms)
→ 创建 Apply 记录(applys_xx 表)
→ 黑名单/白名单检查(并行 RPC)
↓
③ sba_deposit_system/ 创建 Procedure(SRPC,< 100ms)
→ proc_info + proc_cash_deposit 写入
→ 自动审核(deposit_type = TRANS_AUTO)
↓
④ 风控系统 资产变更(SRPC,< 200ms)
→ 余额增加 10,000 HKD
↓
⑤ Procedure → end_ok(deposit_ok)(< 50ms)
→ 回写 Apply 状态 → DONE
→ Canal 同步到 ES(< 3秒)
↓
⑥ 用户在 App 看到余额增加
总耗时:约 1-3 秒出金链路示例:一笔网银出金
用户在 moomoo App 发起出金 50,000 HKD 到恒生银行
↓
① withdraw/ 创建 Task(< 100ms)
→ 黑名单检查
→ 银行卡验证(bankcard_service/ HTTP)
→ Step 1 Audit: 自动通过(普通模板)
→ Step 2 Confirm: 参数确认
→ Step 3 Remittance: 创建 SBA Procedure
↓
② sba_cash_withdraw_system/ 冻结资金(< 200ms)
→ 风控系统冻结 50,000 HKD
→ Procedure: new(freeze) → new(waiting) → new(blank)
↓
③ 扣款(< 200ms)
→ 风控系统正式扣减 50,000 HKD
→ Procedure: pending(deduct_done)
↓
④ 进入人工转账(恒生走企业网银)
→ Procedure: pending(transfer_manual)
→ **等待运营在恒生企业网银完成转账**
↓
⑤ 运营在银行网银转账完成后(小时~天级)
→ CRM 点击"确认转账完成"
→ SetManualTransferDone
→ Procedure: end_ok(transfer_done)
↓
⑥ 用户 1-3 个工作日后收到资金
总耗时:数小时~1 个工作日(取决于运营处理速度)监控与告警体系
核心监控指标
| 指标 | 监控方式 | 告警阈值 | 影响 |
|---|---|---|---|
| 入金到账时间 | SBA Procedure 创建到 end_ok 的时间差 | BST > 5 分钟 / 普通 > 1 小时 | 用户体验 |
| 出金处理时间 | Task 创建到 end_ok 的时间差 | BST > 10 分钟 / 网银 > 24 小时 | 用户体验 |
| 匹配引擎执行 | 定时任务执行日志 | 超过 6 分钟未执行 | 批量入金延迟 |
| Canal 同步延迟 | ES 最新记录时间 vs MySQL 最新记录时间 | 延迟 > 30 秒 | CRM 搜索不到最新数据 |
| SM2 Socket 连接 | 心跳检测(招行/民生) | 心跳超时 > 60 秒 | 银证通道不可用 |
| 轮询任务超时 | Job retry_count | 入金 > 60 / 出金 > 10 | 天星 BST 交易卡住 |
| 冻结未释放 | Procedure 在 pending(unfreeze) 停留时间 | > 5 分钟 | 用户资金卡住 |
| 补回失败 | Procedure 在 pending(return) 停留时间 | > 5 分钟 | 用户资金"消失" |
告警通知方式
| 级别 | 告警方式 | 响应时效 | 典型场景 |
|---|---|---|---|
| P0 严重 | 飞书群 + 电话 | 15 分钟内 | 冻结未释放、补回失败、SM2 Socket 断连 |
| P1 重要 | 飞书群 | 30 分钟内 | 轮询超时、匹配引擎停止、Canal 同步长时间延迟 |
| P2 一般 | 飞书群 | 2 小时内 | 单笔入金/出金延迟超预期 |
详细告警规则配置、定时任务清单和 Dashboard 地址 → 定时任务与监控
常见延迟瓶颈与排查
当入金或出金出现延迟时,问题通常出在以下环节:
| # | 瓶颈环节 | 表现 | 排查方式 | 影响范围 | 严重程度 |
|---|---|---|---|---|---|
| 1 | 银行流水未到 | Apply 已创建但无匹配流水 | 检查对应银行接入服务日志;确认银行侧是否已完成转账 | 单笔 | P2 |
| 2 | 匹配引擎延迟 | 流水已入库但未匹配到 Apply | 检查匹配定时任务是否正常运行(每 3 分钟) | 批量 | P1 |
| 3 | SBA Procedure 创建超时 | 匹配成功但 Procedure 未创建 | 检查 SBA 服务是否正常、SRPC 是否超时 | 单笔 | P1 |
| 4 | 风控变更失败 | Procedure 创建成功但状态为 end_reject | 查看 Procedure 的 reason 字段 | 单笔 | P2 |
| 5 | Canal 同步延迟 | CRM 搜索不到已存在的记录 | 等几秒重新搜索;检查 Canal Consumer 是否正常 | CRM | P2 |
| 6 | 银证轮询超时 | 天星 BST 入金/出金长时间处理中 | 检查轮询任务重试次数(入金 60 / 出金 10) | 单笔 | P1 |
| 7 | 定时脚本未运行 | 出金 Procedure 卡在 new(waiting) | 检查出金定时脚本是否正常执行 | 批量 | P0 |
| 8 | 人工转账未确认 | 出金 Procedure 卡在 pending(transfer_manual) | 提醒运营在银行网银完成转账后确认 | 单笔 | P2 |
| 9 | SM2 Socket 断连 | 招行/民生银证通道完全不可用 | 检查 cmb_stock_trans / ms_stock_bank_transaction 服务状态 | 通道级 | P0 |
| 10 | RabbitMQ 积压 | 多笔入金/出金批量延迟 | 检查队列深度和消费者状态 | 批量 | P1 |
快速排查决策树
系统间调用关系
读完之后
| 我想... | 去看 |
|---|---|
| 了解系统管什么不管什么 | 新人导读 § 30 秒全景 |
| 深入了解 SBA 编排 | SBA 资金编排 |
| 深入了解银行卡体系 | 银行卡与授权 |
| 看各银行接入方式 | 银行能力矩阵 |
| 看告警和定时任务 | 定时任务与监控 |
这个页面有帮助吗?