01 FinFlow 项目介绍
01 FinFlow 项目介绍
这是 FinFlow 系列的第一篇。先看懂这个项目「是什么」和「为什么」,再动手写代码。
1. 背景 —— 为什么做这个项目
1.1 一句话缘起
FinFlow 是一个面试作品级的金融微服务项目。它的目标不是上线赚钱,而是用一套完整的代码 + 文档,在面试中证明一件事:
我不仅能写 Java 代码,更能设计系统、做技术决策、并把决策讲清楚。
1.2 这个项目在回答什么问题
面向的 JD 是一份 Java 资深开发 / 架构工程师 岗位(30-35K,5 年+ 经验),要求覆盖:
- 微服务架构设计与落地
- 分库分表、分布式事务
- Redis、Kafka、MySQL 性能调优
- JVM 调优实战
- 高并发处理经验
传统面试中,候选人只能「口头描述」这些能力。FinFlow 的做法是:每一项 JD 要求都有对应的代码、压测数据、ADR 决策文档。
1.3 项目定位
打个比方:FinFlow 就像消防演练。
它不是真银行,但整套流程和真银行一样 —— 用户注册 → 借款申请 → 风控审核 → 放款 → 还款 → 对账,一个环节都不少。学员学完这套流程,进到真正的金融项目就不会懵。
1.4 设计哲学
整个项目有一条铁律:不拍脑袋选技术,每个决策都要写 ADR(架构决策记录)。
比如「为什么用 Kafka 而不是 RocketMQ」「为什么 MVP 不用 Dubbo」「分片键为什么选 user_id」—— 这些问题在项目中都有书面答案。
2. 核心功能
FinFlow 模拟了一套互联网消费信贷的完整业务流程。
2.1 一句话讲清业务
用户在 App 上看到一款借款产品 → 提交申请 → 系统自动风控审核 → 审核通过 → 钱打到用户账户 → 用户到期还款。
这中间涉及 5 个核心环节:
| 环节 | 对应服务 | 做什么 |
|---|---|---|
| 身份 | user-service | 注册、登录、实名认证 |
| 借款 | loan-service | 借款申请、审批状态、合同生命周期 |
| 风控 | risk-service | 准入规则检查、反欺诈、额度决策 |
| 放款/还款 | payment-service | 资金流水、还款处理、对账 |
| 搜索 | search-service | 借款产品目录搜索 |
2.2 端到端流程
用一句话走完「用户借一笔钱」的全链路:
用户登录 → 搜索借款产品 → 提交借款申请
→ 风控自动审核(查黑名单 + 算额度)
→ 审核通过 → 触发放款(调用支付渠道)
→ 放款成功 → 记资金流水
→ 到期自动还款(或主动还款)
→ T+1 日对账,确保流水和余额一致
2.3 哪些做了、哪些没做
为了在 4 周内完成 MVP,项目做了清晰的边界划分:
In Scope(做):
- 用户注册 / 登录 / 资料管理
- 借款产品目录搜索
- 借款申请 → 风控决策 → 放款 → 还款的完整编排
- 资金流水记录与对账
- Kafka 异步消息、Redis 缓存、ES 搜索
- 压测报告 + JVM 调优
Out of Scope(明确不做):
- 真实支付清结算(用 mock 支付网关替代)
- 真实征信数据(用本地种子数据替代)
- 运营后台 UI(只保留 API)
- 前端界面(用 HTTP Client 脚本 + 录屏演示)
3. 使用的技术
3.1 技术栈总表
| 层级 | 选型 | 选型理由 |
|---|---|---|
| 语言 | Java 21 | 虚拟线程、Record 类、Pattern Matching —— 21 才像现代 Java |
| 框架 | Spring Boot 3.2.5 | 业界标准,生态最全,面试最认 |
| 网关 | Spring Cloud Gateway | 基于 WebFlux,非阻塞,比 Zuul 性能好 |
| 构建 | Gradle 8 | 比 Maven 灵活,多模块项目管理更简洁 |
| 数据库 | MySQL 8.0 | 金融系统标配 InnoDB,事务 + 行锁成熟可靠 |
| 缓存 | Redis 7.2 | Lua 脚本原子操作,支持分布式锁和限流 |
| 消息队列 | Kafka 3.6 | 高吞吐、持久化、顺序保证,适合削峰和事件总线 |
| 搜索 | Elasticsearch 8.11 | 分词搜索 + 复合筛选,产品目录查询场景首选 |
| 容器 | Docker Compose | 一键起全套中间件,15 分钟从 clone 到跑通 |
| 观测 | Actuator + Micrometer | 健康检查 + Prometheus 指标预留 |
3.2 两个典型选型决策
为什么用 Gradle 而不是 Maven?
Maven 的 XML 在多模块项目中会迅速膨胀。Gradle 用 Groovy DSL,6 个子模块的构建脚本总共不到 30 行。且 Gradle 的增量编译和构建缓存比 Maven 快 2-3 倍 —— 对于需要频繁构建的微服务项目,这个差距很明显。
为什么 MVP 阶段不用 Dubbo?
Dubbo 是好东西,但 MVP 阶段的学习成本和调试成本太高。项目用 Spring Web(REST)做服务间调用,但有一个关键设计:每个服务的接口和 DTO 都放在独立的 *-api 模块里,物理上和 Spring 框架解耦。这意味着将来切 Dubbo Triple 时,只需要换通信层,业务代码一行不动。这个决策也写在了 ADR 里。
4. 系统架构图
4.1 C4 上下文图
从外部视角看 FinFlow 的全貌:
┌────────────────┐
│ 终端用户 │
│ (APP / H5) │
└────────┬───────┘
│ HTTPS (REST / JSON)
▼
┌────────────────┐
│ Gateway │
│ (8080) │ ── 统一路由 / 鉴权 / 限流
└────────┬───────┘
│
┌───────┬─────────┼─────────┬─────────┬─────────┐
▼ ▼ ▼ ▼ ▼ ▼
┌────────┐┌──────┐┌─────────┐┌───────┐┌──────────┐
│ user ││ loan ││ risk ││payment││ search │
│(8081) ││(8082)││(8083) ││(8084) ││ (8085) │
└────────┘└──────┘└─────────┘└───────┘└──────────┘
│ │ │ │ │
└────┬───┴────┬───┴─────┬────┴────┬────┘
▼ ▼ ▼ ▼
┌───────┐ ┌───────┐ ┌──────┐ ┌──────────┐
│ MySQL │ │ Redis │ │Kafka │ │Elasticsearch│
└───────┘ └───────┘ └──────┘ └──────────┘
│
▼
┌───────────────┐
│ 外部系统(Mock)│
│ · 支付渠道 │
│ · 征信数据 │
└───────────────┘
4.2 六个服务一句话职责
| 服务 | 端口 | 一句话职责 | 数据所有权 |
|---|---|---|---|
| gateway-service | 8080 | 统一入口,负责鉴权、路由、限流 | 无(无状态) |
| user-service | 8081 | 用户注册登录、实名认证 | user 表 |
| loan-service | 8082 | 借款申请的编排者,管理借款生命周期 | loan_order 表 |
| risk-service | 8083 | 风控规则引擎,决定「借不借、借多少」 | risk_decision 表 |
| payment-service | 8084 | 管钱 —— 放款、还款、资金流水、对账 | payment_order、fund_flow 表 |
| search-service | 8085 | 借款产品搜索 | ES 索引 product_catalog |
关键原则:一张表只由一个服务写。其他服务要读数据,只能通过 API 或 Kafka 事件。
5. 技术架构图
5.1 分层架构
┌─────────────────────────────────────────────────┐
│ 表示层 │
│ HTTP Client / Swagger UI │
└─────────────────────┬───────────────────────────┘
│
┌─────────────────────▼───────────────────────────┐
│ 网关层 (gateway-service) │
│ 鉴权 · 限流 · 路由 · TraceId 生成 │
└─────────────────────┬───────────────────────────┘
│
┌─────────────────────▼───────────────────────────┐
│ 业务服务层 (5 个微服务) │
│ user · loan · risk · payment · search │
│ ┌─────────────────────────────────────────┐ │
│ │ 同步通信:REST (Spring Web) │ │
│ │ 异步通信:Kafka (事件驱动) │ │
│ └─────────────────────────────────────────┘ │
└─────────────────────┬───────────────────────────┘
│
┌─────────────────────▼───────────────────────────┐
│ 中间件层 (4 个中间件) │
│ ┌──────────┐ ┌──────────┐ ┌──────┐ ┌──────┐ │
│ │ MySQL │ │ Redis │ │Kafka │ │ ES │ │
│ │ 事务/索引│ │缓存/锁 │ │削峰 │ │搜索 │ │
│ └──────────┘ └──────────┘ └──────┘ └──────┘ │
└─────────────────────────────────────────────────┘
5.2 同步 vs 异步的分工
| 场景 | 方式 | 为什么 |
|---|---|---|
| 风控决策 | 同步 REST | 必须拿到结果才能继续,不能异步 |
| 查询用户信息 | 同步 REST | 强读一致,调用链短 |
| 放款结果通知 | 异步 Kafka | 支付渠道可能有秒级延迟,不阻塞前端 |
| 产品变更通知 | 异步 Kafka | 搜索索引更新不要求实时 |
5.3 一笔借款的完整调用链
[用户] ──申请借款──▶ [gateway] ──JWT 鉴权──▶ [loan-service]
│
┌───────────────────────────┤
│ 同步调用 │ 同步调用
▼ ▼
[user-service] [risk-service]
查用户身份 + 状态 跑风控规则 → 返回额度
│ │
└───────────┬───────────────┘
│ 风控通过
▼
[loan-service]
更新借款单为 APPROVED
发事件 loan.approved → Kafka
│
▼ (异步消费)
[payment-service]
调用 mock 支付渠道放款
记 fund_flow 流水
发事件 payment.disbursed → Kafka
│
▼ (异步消费)
[loan-service]
更新借款单为 DISBURSED
│
▼
[用户收到钱]
6. 项目亮点
亮点 1:业务导向的微服务拆分
服务命名直接反映业务,不是技术词。6 个服务按「数据所有权」拆分 —— 每张表只有一个写入者,天然避免分布式写冲突。比如 payment-service 管资金流水,loan-service 要查流水只能调 API 或消费 Kafka 事件,绝不直接读对方的数据库。
亮点 2:每个技术选择都有 ADR
不是「我觉得 Kafka 好」而是「对比了 Kafka vs RocketMQ vs RabbitMQ,在吞吐量、运维成本、生态成熟度三个维度评估后选 Kafka,详见 ADR」。项目计划产出 5 篇以上 ADR 文档,面试时可以直接打开给面试官看。
亮点 3:JVM 内存优化实战
6 个 Spring Boot 服务 + 4 个中间件,全栈 Docker Compose 跑起来 RSS 只有 1522 MB。通过 JVM MaxRAMPercentage=50、SerialGC、虚拟线程等手段,单服务堆内存控制在 93-115 MB 之间。这不是理论 —— 每一版都跑了实际的内存基线测试,数据在 docs/05-memory-baseline.md。
亮点 4:为高并发留了后手
MVP 不搞分库分表,但 fund_flow 表已预留分片键 user_id,ShardingSphere 接入成本低。抢购接口设计了 Redis Lua 原子扣减 + Kafka 削峰 + Sentinel 限流的三段式方案,5000 并发抢 1000 份不超卖。这些都在文档里有完整的演进路径。
亮点 5:面试讲稿完备
docs/00-jd.md 是一份逐条拆解 JD 要求的证据映射表,每项能力都配有 STAR 话术(场景 → 动作 → 难点 → 结果),面试时直接调用。另有 7 条高频追问的 30 秒速查卡,覆盖「为什么 Seata AT 不是 TCC」「缓存一致性怎么保证」「10 倍流量怎么扩」等经典问题。
亮点 6:15 分钟可跑通全链路
从 git clone 到跑通「注册 → 登录 → 借款申请 → 风控 → 放款 → 查询流水」全流程,只需 15 分钟:
cp .env.example .env
./scripts/up.sh # 一键起 MySQL + Redis + Kafka + ES
./gradlew build -x test # 构建 6 个服务
# 逐一启动服务,或 IDE 里直接跑
curl http://localhost:8081/actuator/health # 验证所有服务
接下来读什么
这一篇是「看懂全貌」。下一篇开始动手 —— 03 Spring Boot 多模块项目搭建 会带你从零创建 6 个 Gradle 子模块,跑通第一个健康检查接口。
本模块三篇文章的学习顺序: