Architecture Audit · 性能优先 · 模块化高复用

FinDataHub 应用功能设计与模块结构方案

以性能优先为核心前提,重构模块边界、收敛重复分叉、下沉公共能力。目标:单一职责、单向依赖、可复用底座,杜绝功能零散分布与重复开发。

审计日期 2026-10-17 源码版本 v1.5.2 Python 3.12(全项目锁定) Swift 19,616 行 Python 服务 6 个 / 30,320 行 运维脚本 39 个
① 审计结论 ② 核心功能清单与边界 ③ 模块职责与层级 ④ 依赖与交互 ⑤ 公共能力抽象 ⑥ 性能优先落实 ⑦ 收敛落地路径
01

审计结论

核心结论:功能已完整,但结构存在三类系统性重复分叉,且性能关键路径未收敛到统一底座

本项目「能跑、数据在库」,但低层代码缺陷清理之后暴露出的问题已从「写错代码」转为「写对代码但零散分布、重复开发、关键能力未在生产生效」。方案目标不是重写功能,而是收敛结构——把散落在三个入口、两套后端、三份副本里的能力归位到唯一归属模块。

分叉 1 快讯双后端双采集器

newsflash_backend.py(Scripts/bin)↔ kuaixun-service/app
newsflash_collect.py(3 源)↔ extend/fetchers(12 源)

快讯功能存在两套后端实现(`newsflash_backend.py` 注释自陈「来自 finance-terminal/kuaixun-service」,是历史分叉)与两套采集器(3 源直抓 vs 12 源管线)。同一域内双实现,修复必须双份、演进必然漂移。

分叉 2 同步三入口

sync_bridge.py ↔ pipeline_runner.py ↔ daily_update.sh

生产实际走 launchd 的 `daily_update.sh` 直写 raw 库、不过门控;`sync_bridge.py` 是 App 手动同步入口;`pipeline_runner.py`(号称替代前两者、带四级门控)从未接入 launchd。三条链路并存,治理能力在唯一带门控的入口上却不在生产路径。

分叉 3 公共能力三处重复

cache / validator / reporter

历史上 `cache.py`/`validator.py`/`reporter.py` 在 core、tushare、akshare 三处各存一份。tushare 侧已收敛(574→66 行),akshare 侧是有差异的分支版本,待甄别后统一。`db.py` 下沉 core 已成正确范式,需推广到全部公共模块。

方案主线(五条):① 建立五层单向依赖架构;② 快讯域收敛到 kuaixun-service 单一实现;③ 同步域收敛到 pipeline_runner 单一入口;④ 公共能力全部下沉 findatahub-core;⑤ 性能关键路径(连接复用 / 批处理 / 心跳 / 缓存 / 索引)在架构层固化为契约。
02

核心功能清单与边界说明

按业务域划分 7 个功能域。每域明确「做什么」与「不做什么」——边界即契约,越界即为缺陷。

功能域核心功能职责(做)边界(不做)
数据采集
L1 Ingestion
结构化行情采集
tushare_fetcher / akshare_fetcher
拉取日/周/月线、财务、资金流、股东、分红等 84+ 张表,落 raw 库(tushare_data / akshare_data) 不做清洗、不做门控、不做对外服务、不做推送
快讯采集
L1 Ingestion
12 源快讯抓取
extend/fetchers/*
抓取 cls/新浪/财联社/华尔街见闻/格隆汇/金十等 12 源,进入去重管线 不做行情数据、不直接对外、不负责推送路由
数据治理
L2 Governance
Pipeline DAG + 四级门控
pipeline / gate / cleaner
七步流水线编排;gate1 采集/gate2 清洗/gate3 入库/gate4 后置四级质量门控;清洗、插补、离群检测、双源交叉验证;产出 fin_data_clean 不做采集、不做对外服务;门控是 raw→clean 的唯一闸口
数据存储
L0 Infra
三库分层 + 连接池
db / db_pool
raw(tushare/akshare)→ clean 三级库;连接池、幂等 upsert、日期/排序规则护栏 不含业务规则、不含字段语义,只提供读写基础设施
数据访问
L3 Access
SDK 统一查询
findatahub-client
统一查询/导出入口(client / api / mcp_server),隔离底层库细节,SQL 注入防护 不做采集、不做治理;是查询的唯一对外出口
快讯服务
L4 Service
去重 + AI 增强 + 推送
kuaixun-service/app
四层去重、翻译/摘要/标签/评分、多渠道推送(Bark/钉钉/飞书/Telegram/企微)、REST(:8100) + WebSocket 不做行情、不做治理;是快讯全生命周期的唯一后端
应用客户端
L5 UI
macOS 客户端 + Vue 前端
App (SwiftUI) / kuaixun-frontend
进程编排、同步触发、快讯展示、数据库管理、调度、监控、节能;对外呈现 不做采集/清洗逻辑本身,只编排子进程与展示数据
运维可观测
横切
审计/迁移/监控
Scripts/bin + health/retry
调度覆盖审计、数据迁移、性能快照、健康监控、自动恢复、告警 横切能力,不参与业务数据流
边界即护栏:历史上「写对代码但越界」是主要事故源——`db.replace()` 被采集层误用导致增量清全表、清洗器判据命中 akshare 的 `vol==amount` 假数据、门控 reroute 不收敛整批丢弃。方案将「边界」作为一等公民写入模块契约,越界即测试失败。
03

模块职责划分与层级关系

五层单向依赖架构,上层依赖下层、下层不感知上层;findatahub-core 是横切公共底座,被 L1/L2/L3 共同依赖。

L5 表现层 Presentation 编排 + 展示,不含业务逻辑
App (SwiftUI)macOS 客户端 · 进程编排 · 同步触发 · 监控 · 节能 kuaixun-frontendVue3 快讯 Web 前端
▲ 依赖向下 ──────────── ▲
L4 应用服务层 Service 快讯全生命周期唯一后端
kuaixun-service/appFastAPI · REST(:8100) · WebSocket · 鉴权 kuaixun-service/extend采集管线 · 去重 · AI 增强 · 推送 kuaixun-service/common配置 · 安全栈
▲ 依赖向下 ──────────── ▲
L3 数据访问层 Access 统一查询出口
findatahub-clientSDK · client · api · mcp_server · SQL 注入防护 dal / dal_unified快讯查询数据访问层
▲ 依赖向下 ──────────── ▲
L2 数据治理层 Governance raw → clean 唯一闸口
pipeline七步 DAG 编排 · 并行调度 gate四级质量门控 gate1-4 cleaner / imputer / outlier清洗 · 插补 · 离群 cross_validator双源交叉验证
▲ 依赖向下 ──────────── ▲
L1 数据采集层 Ingestion 只拉取 + 落 raw 库
tushare_fetcher结构化行情采集(84+ 表) akshare_fetcher结构化行情 + 北交所 + THS extend/fetchers12 源快讯抓取
▲ 依赖向下 ──────────── ▲
L0 基础设施层 Infra 读写 + 可靠性底座
db / db_pool连接池 · upsert · 日期/排序护栏 cacheSyncCache · TradeDateCache retry / health重试 · 健康监控 security鉴权 · SQL/SSRF 防护 MySQLtushare_data / akshare_data / fin_data_clean
CROSS 横切公共能力层(findatahub-core) 被 L1/L2/L3 共同依赖的唯一底座
db / cache / validator / reporter唯一实现,禁止各 fetcher 自持副本 pipeline / gate / cleaner / cross_validator治理引擎(L2 的运行时) retry / health / stats / correlation横切可靠性 + 分析 context / imputer / outlier / pca / profile流水线上下文 + 特征工程
层级铁律:① 依赖只允许指向更低的层或横切底座,禁止反向、禁止跨层跳跃、禁止同级横向依赖;② findatahub-core 不依赖任何业务包(零业务 import);③ 每个 fetcher 对 core 的依赖收敛为「薄封装 + 源专属适配」,不复制逻辑。
04

模块间依赖与交互方式

依赖分两种:代码依赖(import 关系,单向向下)与运行时交互(进程/网络/协议)。

L5 表现层 App (SwiftUI) · kuaixun-frontend (Vue3) L4 服务层 kuaixun-service (app/extend/common) — FastAPI :8100 + WebSocket L3 访问层 findatahub-client (SDK/MCP) · dal L2 治理层 pipeline · gate · cleaner · cross_validator(raw → clean 唯一闸口) L1 采集层 tushare_fetcher · akshare_fetcher · extend/fetchers (12 源) L0 基础设施 db/db_pool · cache · retry/health · MySQL(三库) import import import import import 运行时交互(非 import) ■ App ↔ Python 子进程 PythonProcessManager spawn,stdout JSON 协议 + PID 文件 ■ launchd → pipeline_runner 日更定时任务,经 L2 门控写 clean(收敛后) ■ 前端 ↔ 服务 HTTP/WS REST :8100 + WebSocket 实时推送 ■ SDK ↔ 服务 / 直连 DB client 经 API 或直连 MySQL(统一出口) ■ 采集器 ↔ 上游 API tushare/akshare/各快讯源,限流 + 重试 ■ 所有写库经 db 护栏 日期规范化 / 排序规则 / 幂等 upsert ■ 收敛前禁止的交互(红线) daily_update.sh 直写 raw 不过门控 newsflash_backend.py 与 kuaixun-service 双活 sync_bridge.py 与 pipeline_runner 双入口 —— 这三条是本次收敛目标 ——
三条红色交互(收敛目标):① 生产日更绕过门控直写 raw;② 快讯双后端并存;③ 同步双入口。方案落地后,运行时交互唯一合法形态为:launchd → pipeline_runner → 门控 → clean,快讯唯一后端 kuaixun-service。
05

可复用公共能力与组件抽象

findatahub-core 是唯一公共底座。所有被 2 个以上消费者使用的模块必须下沉 core,各 fetcher 只保留源专属适配层。

公共能力组件职责当前状态
数据库访问BaseDatabaseManager · safe_identifier连接池、幂等 upsert/replace、日期规范化护栏、排序规则、表结构迁移已下沉 akshare/tushare 薄封装
数据校验DataValidator · ValidationReport字段完整性、类型、OHLC 规则校验已下沉 tushare 收敛,akshare 待甄别
报告生成ReportGenerator · SyncReport同步结果报告、表级统计已下沉 同上
缓存SyncCache · TradeDateCache同步状态缓存、交易日历缓存(减少重复同步与 DB 查询)已下沉
流水线编排Pipeline · Step · FetchStepProtocolDAG 编排、并行调度、上下文传递在 core,未接入生产
质量门控gate1-4 · execute_gate采集/清洗/入库/后置四级门控在 core,未接入生产
清洗特征DataCleaner · DataImputer · OutlierDetector清洗、缺失插补、离群检测在 core
交叉验证CrossValidator双源数据一致性校验在 core
重试/健康RetryManager · HealthMonitor分类重试、限流、健康监控在 core
分析统计StatsAnalyzer · CorrelationAnalyzer · PCA统计、相关性、降维在 core

下沉范式(db.py 已验证)

tushare_fetcher/core/db.py = 42 行薄封装
akshare_fetcher/core/db.py = 31 行薄封装

fetcher 侧只做:继承 + 源专属表结构适配。逻辑全部在 core,改一处全仓生效。

组件抽象四原则

  • 单一实现:一个能力只存在 core 一处,消费者 import 不复制
  • 薄封装:fetcher 侧仅适配源差异,不重写逻辑
  • 契约先行:公共组件带接口契约测试(如 ensure_market_table)
  • 别名收敛:历史同名文件用 sys.modules 别名归位,非 from-import 转发(防 monkeypatch 失效)
06

性能优先在架构层面的落实要点

性能不是事后调优,而是架构契约。以下要点逐一映射到层与组件,越界即回归失败。

P1 连接复用(L0)

去重写入、批量同步全部复用一个连接,禁止每条新建 4~5 次 TCP 握手(历史 500 条≈2000 次握手)。连接池统一超时 + rollback 归还。

P2 幂等 upsert(L0/L1)

增量路径强制 upsert,replace 仅限全量快照表。杜绝「增量 DELETE 全表」的 I/O 风暴与数据损毁。

P3 批处理 + 事务边界(L2)

Pipeline 整批写、单事务提交,避免逐行 commit;并行步骤产物按步骤名隔离,防串源重算。

P4 心跳替代 DB 轮询(L5)

进程健康用心跳文件判定,不用「最后写库时间」(历史 300s 阈值误判 193 次/日)。交易/非交易时段差异化节能退避(30s→3600s)。

P5 缓存层(L0)

TradeDateCache 缓存交易日历、SyncCache 缓存同步状态,避免重复拉取与重复同步;MySQL 缓冲池 2GB 命中优先。

P6 索引与查询策略(L3/L4)

搜索保留 LIKE 连续子串语义(正确优先),拒绝 ngram 全文索引静默丢结果;total 单独 COUNT,不扫全表。

P7 异步 I/O(L4)

快讯采集、内容增强、推送走 asyncio 并发;限流 + 分类重试(限频/网络/业务分类退避),避免串行阻塞。

P8 资源按需启停(L5)

MySQLOnDemandManager / PowerSaver:非交易时段降频、按需拉起 mysqld,主进程 UNIX 调用从 5092/s 降至 0.2/s。

性能基线非交易时段交易时段(优化前)交易时段(优化后)
主进程 UNIX 调用/s0.2–335092.50.2
采集器 UNIX 调用/s0.2658.11.6
MySQL UNIX 调用/s42893248.2
MySQL RSS470 MB1870 MB2959 MB(缓冲池 2GB + 数据增长,非泄漏)

数据来源:`Scripts/bin/perf_snapshot.py`(libproc 采样)。交易/非交易时段必须分别验证,不可直接比较——交易时段高负载是常态非泄漏。

07

收敛落地路径(结构重构)

批次动作内容优先级
第 1 批 快讯域收敛 废弃 Scripts/bin/newsflash_backend.py(历史分叉),统一到 kuaixun-service;废弃 3 源 newsflash_collect.py,统一到 extend/fetchers 12 源管线 P0 结构
第 2 批 同步域收敛 pipeline_runner.py 装入 launchd,成为 fin_data_clean 唯一写入方;daily_update.sh 降级为 raw 采集(本就该是 raw);sync_bridge.py 收敛为 pipeline 的 App 触发入口 P0 结构
第 3 批 公共能力收敛 甄别 akshare 侧 cache/validator/reporter 分支版本,合并到 core;治理引擎(pipeline/gate)确认唯一运行时位置 P1
第 4 批 超大文件拆分 akshare fetcher.py(1035)、newsflash_collect.py(962)、PythonProcessManager.swift(842)、DatabaseSetupGuideView.swift(807) 按职责拆 extension P1
第 5 批 契约测试补全 为公共组件(db/validator/gate/pipeline)补接口契约测试,锁定「边界即护栏」,越界即失败 P2
落地原则:结构收敛与既有缺陷修复并行,不改功能语义、只改归属。每批先补能证伪的回归用例(确认旧结构下用例失败、新结构下通过),再执行收敛,最后跑全量测试(当前基线 1147 passed)。Swift 侧改动须经 swift build --disable-sandbox 编译验证后打包部署。
本方案基于 2026-10-17 对 FinDataHub 全仓(App Swift 19,616 行 / 6 个 Python 服务 30,320 行 / 39 个运维脚本)的静态结构取证与历史审计结论(v1.5.2)生成。所引性能数据来自 `perf_snapshot.py`(libproc 采样)与历史审计记录,交易/非交易时段已分别标注。本方案为架构设计与模块结构建议,不涉及任何投资标的判断。

仅供参考,不构成投资建议。