12 KiB
12 KiB
蔬菜价格指数平台 — 架构设计
版本:1.2
范围:多源价格采集、数据清洗、指数计算、MySQL 存储、接口服务、ECharts 可视化。
目标:轻量落地、成本可控、模块解耦、可迭代扩容。
语言与职责(已定稿):
- Python:仅负责采集层(多源适配器、调度、反爬、raw/队列表落库),不承担管理后台、对外 API、治理批处理、指计算。
- Java:全栈后台(Spring Boot 为主):治理与标准化、指数字典与批算、REST API、鉴权/审计、管理端后端、数据库迁移(Flyway / Liquibase 等,推荐与 Java 工程同仓)。
- 集成面:MySQL 为事实源;Python 写 raw(及约定内字段),Java 服务消费 raw 后写 clean、指标与维表。跨语言不共享运行时,只共享表结构契约与(可选)OpenAPI/内部 HTTP。
1. 设计目标与原则
| 目标 | 说明 |
|---|---|
| 轻量优先 | 单机或少量节点即可闭环 MVP,避免过早引入重中间件 |
| 可演进 | 原始层、治理规则、指算法、接口契约版本化,支持重算与追溯 |
| 解耦 | 按数据源隔离适配器,采集/治理/计算/服务异步与边界清晰 |
| 风险可控 | 反爬、去重、异常、合规与审计可落实在流程与表结构上 |
原则:原始数据以追加为主;指数计算与抓取失败解耦;对外服务读「指标/维表」而非直扫原始大表(必要时走缓存/汇总表)。
2. 总体分层架构
| 层级 | 职责 | 轻量实现形态 |
|---|---|---|
| 采集层 | 多源页面/API 抓取、任务调度、反爬与频控 | Python 爬虫 + APScheduler 或 Cron |
| 接入/缓冲层 | 削峰、解耦、失败重试 | Redis List/Stream,或队列表 + 多 Worker |
| 治理层 | 去重、单位/品种归一、异常与质量打标 | Java 定时任务(如 Spring @Scheduled / XXL-Job 等)+ 可配置规则/维表 |
| 计算层 | 指数据模型、基期、权重、链式/环比等 | Java 批算,输入输出可幂等、可版本化 |
| 存储层 | 原始明细、清洗数据、指数结果、元数据 | MySQL 8.0+(主库,推荐 InnoDB + utf8mb4) |
| 服务层 | REST API、鉴权、限流、健康检查、管理后台 API | Spring Boot(可 Undertow/Tomcat;网关按组织规范) |
| 展示层 | 图表、看板、运营侧配置界面 | 前端 + ECharts,与 Java API 联调 |
存储说明:优先复用现成 MySQL 实例;大对象/审计快照可接 MinIO/对象存储。热查询与去重可叠加 Redis(可选)。
3. 技术选型
| 领域 | 建议 | 备注 |
|---|---|---|
| 爬虫 | Python:httpx / aiohttp + selectolax / parsel;强渲染页用 Playwright |
仅 ingest + adapters/,禁止在爬虫工程实现指算法/管理端 |
| 爬虫调度 | Cron 或 Python 内 APScheduler、独立 worker 进程 | 与 Java 治理/指计算 在时间上解耦(可 raw 落库后由 Java 轮询或消息触发) |
| 主库 | MySQL 8.0+ | Java 与 Python 共用(凭 DSN/账号分离读写权限更佳);InnoDB、utf8mb4、分区同前 |
| 后台与批算 | Java 17+,Spring Boot 3.x | 治理/指数/REST/管理端一体;批处理可用 Spring 自带任务或接调度平台 |
| 表结构迁移 | Flyway 或 Liquibase(放在 server/ 工程) |
Python 不持有权威 DDL,按迁移脚本对齐 |
| 缓存/去重 | Redis | Java 与(可选)Python 爬虫共用时,键命名空间须约定,避免互踩 |
| API 契约 | 对外/前后端以 OpenAPI 为单一描述(可 server 生成 spec) |
Python 侧不暴露业务 API 时,可不建 OpenAPI |
| 前端 | Vue 或 React + ECharts | 请求 Java 后端 |
| 可观测 | 统一标准:双栈结构化日志 + trace id(可 OpenTelemetry) | Java/Python 用不同 app name 区分 |
| 部署 | Docker Compose:java 服务 + crawl-worker 镜像分离;扩容再上编排 |
4. 模块解耦
各数据源适配器 (Source A/B/…N)
│
▼
统一采集契约:RawRecord + 来源元数据 (source_id、抓取时间、指纹等)
│
▼
原始层(raw,只增不改或软删策略)
│
▼
治理与标准化(品种/市场/单位/别名映射、质量 flag)
│
▼
指数计算引擎 ←── 基期/权重/算法版本配置
│
▼
指标结果表 + 维表
│
▼
对外/管理 API(Java)/ ECharts
- 源适配器(Python):一源一包;仅 输出统一 raw 契约;选择器、登录、限频不混入 Java 代码。
- 治理/指数/服务(Java):消费 raw 表,写 clean 与
index_series等,对外提供 REST 与运营配置能力。 - 指数字典与算法版本:
index_code、config_version等字段在 Java 域模型与 Flyway 中一以贯之。 - 计算幂等:由 Java 批任务保证,按「业务日期 + 指数版本」可重算。
5. 数据流(端到端)
- 调度触发各源任务,拉取列表/详情。
- 写入 raw(可含
LONGTEXT/JSON与关键检索列),记录 HTTP 状态与内容指纹。 - 去重(Java 治理):DB 唯一约束在 Flyway 中统一定义;Redis 去重与 Java/爬虫约定 key 前缀。
- 标准化(Java):单位、市场、品种别名 → 维表由 管理端/导入 维护。
- 异常与质量(Java):写 clean 与
quality_flag。 - 指数批算(Java):读清洗 + 当版本配置 → 写
index_series。 - API(Java):读指标与维表;管理端 对规则、维表、重算任务 发令;缓存键与索引策略在 Java 侧实现。
6. MySQL 实践要点
- 版本与字符集:MySQL 8.0+,
utf8mb4,InnoDB。 - 半结构化:JSON 存扩展字段,高筛选字段尽量落普通列+索引;8.0 可配合生成列建索引。
- 大表:按交易日期/入库日期 RANGE 分区,便于归档与冷数据迁出。
- 多 Worker 队列表:使用
SELECT … FOR UPDATE SKIP LOCKED(8.0)实现任务抢占。 - 备份:定期全量/增量,raw 与指标层策略与 RPO 对齐业务要求。
与 PostgreSQL 相比:若未来有极重 JSON 分析或强 GIS 需求,可再评估从库/分析库;当前以结构化为主的指数平台,单 MySQL 可覆盖 MVP 至中期。
7. 反爬、质量与合规
| 主题 | 建议 |
|---|---|
| 反爬 | 频控、退避、UA/协议合法范围内轮换;优先对接官方或开放 API。 |
| 去重 | DB 唯一约束 + 指纹/哈希;同日多价按产品规则(如中位、最新)在治理层定稿。 |
| 异常 | 硬规则(负值、超阈)→ 统计(分位/IQR)→ 业务产季/地域规则。 |
| 指算法 | 固定文档:公式、基期=100、缺权/缺价处理、品种替代;多版本可并存。 |
| 合规 | robots/条款与用途评估;最小化存个人类信息;对公示指数附方法论与免责声明。 |
生产环境长期自动化采集:除上表原则外,须满足《数据源上线清单》中的 授权归档、SLA、观测告警、降级与对外话术 等上线门禁;与《产品设计-蔬菜价格指数平台》中 source_code、来源透传约定一致。
8. 主要风险与缓解
| 风险 | 缓解 |
|---|---|
| 源站改版 | 监控解析失败率;适配器独立;原始 HTML/快照 可选入对象存储 |
| 数据损坏/误删 | raw 追加策略、备份、指数可重算 |
| 单库压力 | 分区、读写分离(从库只读 API)、热数据 Redis |
| 指争议与口径变更 | 配置版本化、可重放历史计算、对账报表 |
9. 分阶段迭代
| 阶段 | 内容 | 验收参考 |
|---|---|---|
| 阶段 1(MVP) | 1~2 个稳定源、Python 写 raw、Java 最小治理 + 1 套指数、Spring Boot + ECharts | 日任务成功率、指口径可说明、API P95 |
| 阶段 2 | 多源、Java 管理维表/规则、多指数、Redis、监控、指数重算入口 | 维表覆盖率、重算耗时、跨语言可观测 |
| 阶段 3 | 消息驱动、抓取/计算水平扩展、复杂地理层级、SLA | 扩展与容灾指标 |
10. 扩展预留
- 表设计早期包含:
source_id、config_version、时间维度 便于分区。 - 表结构以 Java 侧迁移为权威;若 Python 需 Pydantic 模型,由 DDL/OpenAPI/手动同步,避免两真相。
- Java API 无状态,配置与密钥走 Spring Profile / 环境变量/中心配置。
- Python 爬虫无状态、可水平扩展,仅依赖 DSN 与
PYTHONPATH/pip install -e .。
11. 文档维护
- 表结构、指数口径与对外方法论文档应与本文件同步更新(可拆子文档:
docs/指数字典与口径.md等)。 - 生产采集门禁与运维基线见《数据源上线清单》;变更授权或 SLA 时同步评审本文件第 7 节是否需修订。
- 重大架构变更时递增本文「版本」并记录变更摘要。
版本摘要(1.2):增补对《数据源上线清单》的引用,明确上线环境持续采集的文档门禁。
12. 项目目录结构(与实现对齐)
双栈单仓(Python 仅爬取,Java 为后台主工程):
fao/
├── docs/ # 架构、口径、运维说明
├── server/ # **Java 主工程**(Spring Boot 3 + Maven;`pom.xml` 在根下)
│ # `mvn -f server/pom.xml spring-boot:run`;迁移:`src/main/resources/db/migration/`
├── src/
│ └── fao/ # **仅** Python 采集包(pyproject 可 `pip install -e .`)
│ ├── common/ # 爬虫子进程:配置、日志
│ ├── db/ # 仅向 raw/队列写入所需的最小数据访问
│ └── ingest/
│ └── adapters/ # 各数据源一模块
├── scripts/ # 爬虫/批抓入口(`python -m` 等),**不含**指计算
├── config/ # 爬虫用 `.env.example` 等
├── db/
│ └── migrations/ # **可选**:与 `server` 中 Flyway **二选一为权威**;建议以 `server/.../db/migration` 为准后此处留空或删
├── tests/
│ ├── unit/ # 建议拆:server 内 surefire + Python pytest 各管各
│ └── integration/
├── web/ # 前端,对接 **Java API**
├── deploy/ # 含 `docker-compose`:服务 `app`(Java) + `crawl`(Python) 等
├── pyproject.toml # 仅 fao 爬虫包
├── setup.py
└── .gitignore
| 路径 | 放什么、不放什么 |
|---|---|
server/ |
全部 HTTP、安全、域模型、批治理、指计算、迁移;不 写爬虫。 |
src/fao/ingest |
抓取、限频、仅 raw/队列 模型与写入;禁止 指算法与维表管理。 |
src/fao/db |
爬虫用 DAO;表结构消费 Java Flyway 产出。 |
scripts |
只调度 Python 爬取;指数重算/治理 入口放在 Java 或企业调度调 Java 接口。 |
config |
以爬虫侧为主;Java 用 server 内 application-*.yml。 |
web |
管理端/大屏,BFF 为 Java。 |
可选:e2e/ 联调;ops/ 运维脚本。前端可拆独立仓库,server 为后台边界。
13. 语言边界与数据所有权
| 项目 | 约定 |
|---|---|
| 表结构 | Java 工程迁移脚本 为唯一权威;Python 升级前 拉取最新 DDL 或从文档生成模型。 |
| raw 写入 | 仅 Python(或经审查的 ETL)写到约定列;不 写 clean/指数字段,除非团队明确开例外并文档化。 |
| clean / 指标 | 仅 Java(及经同一鉴权的运维脚本)。 |
| 同一 Redis | key 加前缀:crawl: / app: 等。 |
| 重算指数 | 管理端/定时器调 Java 内部服务或 POST /internal/...(内网 + 鉴权)。 |
| 故障 | 爬虫挂 → raw 空;Java 报表仍可展示历史指数据;治理/批算在 Java 侧可告警「无新 raw」。 |
本文档为蔬菜价格指数平台的技术架构说明,实现细节以各模块设计与数据库 DDL 为准。