金融级复式记账引擎 — 架构设计文档
金融级复式记账引擎 — 架构设计文档
文档版本: v1.0
作者: MomoFinance
日期: 2026-04-13
状态: Draft → Review
关联ADR: ADR-001 记账模型选择 / ADR-002 热点账户方案 / ADR-003 日终批处理架构
一、需求分析
1.1 面试场景还原
面试官: "请设计一个金融级复式记账引擎,支持多币种、多账户类型,日终结算,日均千万笔记账请求。"
1.2 需求澄清——10个关键问题
在动手设计之前,必须先通过需求澄清来收敛范围。以下是我会向面试官确认的10个问题:
| # | 问题 | 预设回答 | 对设计的影响 |
|---|---|---|---|
| 1 | 记账模式是复式还是单式? | 复式(Double-Entry) | 必须保证每笔凭证"借贷必相等",数据模型需要 Journal + Posting 两层 |
| 2 | 需要支持哪些账户类型? | 资产/负债/所有者权益/收入/费用 五大类 | 科目表需要层级设计,借贷方向规则不同 |
| 3 | 多币种的范围? | 10+币种,需要本位币折算 | 每笔分录需记录原币+本位币金额+汇率,汇兑损益自动处理 |
| 4 | 日均交易量级别? | 千万笔/天,峰值约1万TPS | 必须考虑热点账户、分库分表、异步批量写入 |
| 5 | 是否需要实时余额? | 是,但可接受最终一致性(秒级延迟) | 余额可用"缓存+异步刷新",不必每笔同步更新 |
| 6 | 日终处理窗口? | 不超过2小时 | 需要并行日终处理,按账户分片 |
| 7 | 是否需要冲正/红冲? | 是 | 冲正不能物理删除,必须生成反向分录 |
| 8 | 审计合规要求? | 数据保留7年+,不可篡改 | Append-only设计,Hash链,归档策略 |
| 9 | 是否多法人/多账簿? | 初期单法人,后续扩展多法人 | 预留 legal_entity_id 字段,科目表按法人隔离 |
| 10 | 与上游系统的交互模式? | 同步接口+异步消息 | 支付系统同步调用记账,记账完成后异步通知报表系统 |
1.3 功能需求
| 模块 | 功能 | 优先级 |
|---|---|---|
| 科目管理 | 科目树CRUD、启用/停用、层级管理 | P0 |
| 开户 | 创建账户、关联科目、设定币种 | P0 |
| 记账 | 创建凭证、生成分录、过账、余额更新 | P0 |
| 冲正 | 红冲(生成反向分录)、部分冲正 | P0 |
| 余额查询 | 实时余额、可用余额、冻结余额、历史余额 | P0 |
| 日终结算 | 结息计算、损益结转、余额快照、试算平衡 | P0 |
| 报表 | 试算平衡表、科目余额表、明细账、总账 | P1 |
| 审计追溯 | 操作日志、凭证链路、数据变更追踪 | P0 |
1.4 非功能需求
| 维度 | 要求 | 量化指标 |
|---|---|---|
| 一致性 | 借贷必须严格平衡,余额不允许出错 | 0容错 |
| 不可篡改 | 已过账凭证不可修改,只能冲正 | Append-only |
| 吞吐量 | 支撑千万级日交易 | 峰值 ≥ 10,000 TPS |
| 时延 | 单笔记账响应 | P99 < 50ms |
| 日终窗口 | 全量日终处理 | < 2小时 |
| 可用性 | 核心记账服务 | 99.99%(年停机 < 52min) |
| 数据保留 | 审计合规 | ≥ 7年 |
| 可审计 | 每笔操作可追溯 | 完整操作链路 |
1.5 会计准则约束
记账引擎不是纯技术系统,必须遵循会计准则:
- 复式记账法(Double-Entry Bookkeeping): 每笔经济业务至少涉及两个账户,一借一贷
- 有借必有贷: 每笔凭证必须同时包含借方和贷方分录
- 借贷必相等: 同一凭证下
SUM(借方金额) = SUM(贷方金额) - 会计恒等式:
资产 = 负债 + 所有者权益(任意时刻成立) - 权责发生制: 收入和费用按实际发生时间入账
- 历史成本原则: 初始入账按交易时的实际金额
二、高层架构设计
2.1 C4 Context — 系统上下文
记账引擎是金融系统的"账本心脏",与以下外部系统交互:
| 外部系统 | 交互方式 | 数据流向 | 说明 |
|---|---|---|---|
| 支付系统 | 同步API | 支付→记账 | 支付完成后触发记账,记账结果同步返回 |
| 信贷系统 | 同步API | 信贷→记账 | 放款/还款/结息触发记账 |
| 风控系统 | 事件订阅 | 记账→风控 | 异常交易通知风控 |
| 财务报表系统 | 异步消息+批量 | 记账→报表 | 日终推送余额快照和汇总数据 |
| 监管报送系统 | 批量文件 | 记账→监管 | 按监管要求定时生成报送文件 |
| 审计系统 | 查询API | 审计→记账 | 审计人员查询凭证链路和操作日志 |
详见
diagrams/c4-context.mmd
2.2 C4 Container — 容器视图
记账引擎内部拆分为以下容器:
| Container | 职责 | 技术选型 | 说明 |
|---|---|---|---|
| API Gateway | 统一入口、鉴权、限流 | Nginx + Kong | 保护后端服务 |
| Account Service | 账户生命周期管理 | Java/Spring Boot | 开户、冻结、销户 |
| Chart of Accounts Service | 科目表管理 | Java/Spring Boot | 科目树CRUD,低频操作 |
| Ledger Core | 核心记账引擎 | Java/Spring Boot | 凭证创建→分录→过账→余额更新 |
| Journal Service | 凭证和分录存储 | Java/Spring Boot | 分录写入、查询 |
| Balance Service | 余额计算与查询 | Java/Spring Boot + Redis | 实时余额、余额快照 |
| Batch Engine | 日终批处理 | Spring Batch | 结息、损益结转、报表生成 |
| Report Service | 报表生成与查询 | Java/Spring Boot | 试算平衡表、科目余额表 |
| Audit Service | 审计日志记录与查询 | Java/Spring Boot + ES | 全操作链路追溯 |
| Primary DB | 核心数据存储 | PostgreSQL (主) | 凭证、分录、余额 |
| Cache | 热数据缓存 | Redis Cluster | 余额缓存、幂等键 |
| Message Queue | 异步消息 | Apache Kafka | 记账事件、日终任务分发 |
详见
diagrams/c4-container.mmd
2.3 核心记账流程
调用方 → API Gateway → Ledger Core
├── 1. 幂等检查(Redis:idempotency_key 是否已存在)
├── 2. 科目校验(Chart of Accounts:科目是否有效、方向是否正确)
├── 3. 分录生成(根据记账模板生成借贷分录)
├── 4. 试算平衡(校验 SUM(DR) = SUM(CR))
├── 5. 过账(写入 journal_entry + posting 表,单库本地事务)
├── 6. 余额更新(同步更新 Redis 缓存,异步落库 balance_snapshot)
├── 7. 审计日志(异步写入 Kafka → Audit Service → ES)
└── 8. 返回结果
详见
diagrams/sequence.mmd
关键设计点:
- 步骤5的"过账"使用单库本地事务,journal_entry 和 posting 在同一个数据库实例中,保证原子性
- 步骤6的余额更新使用 Redis INCRBY 原子操作,保证并发安全
- 步骤7的审计日志通过 Kafka 异步写入,不影响主流程性能
三、数据模型设计
3.1 核心表结构
chart_of_accounts(科目表)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | BIGINT PK | 主键 |
| code | VARCHAR(16) | 科目编码,如 1001.01.001 |
| name | VARCHAR(128) | 科目名称 |
| account_type | ENUM | ASSET / LIABILITY / EQUITY / REVENUE / EXPENSE |
| level | INT | 层级 1-4 |
| parent_code | VARCHAR(16) | 上级科目编码 |
| normal_balance | ENUM | DEBIT / CREDIT(自然方向) |
| currency | VARCHAR(3) | 币种,NULL 表示不限 |
| status | ENUM | ACTIVE / DISABLED |
| created_at | TIMESTAMP | 创建时间 |
| updated_at | TIMESTAMP | 更新时间 |
account(账户)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | BIGINT PK | 主键 |
| account_no | VARCHAR(32) UK | 账户号(业务唯一键) |
| account_name | VARCHAR(128) | 账户名称 |
| chart_code | VARCHAR(16) FK | 所属科目编码 |
| account_type | ENUM | ASSET / LIABILITY / EQUITY / REVENUE / EXPENSE |
| currency | VARCHAR(3) | 账户币种 |
| status | ENUM | ACTIVE / FROZEN / CLOSED |
| legal_entity_id | VARCHAR(16) | 法人实体ID(预留多法人) |
| opened_at | TIMESTAMP | 开户时间 |
| closed_at | TIMESTAMP | 销户时间 |
| metadata | JSONB | 扩展属性 |
journal_entry(记账凭证)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | BIGINT PK | 主键 |
| entry_no | VARCHAR(32) UK | 凭证编号(业务唯一键) |
| idempotency_key | VARCHAR(64) UK | 幂等键 |
| business_type | VARCHAR(32) | 业务类型(PAYMENT / LOAN / INTEREST / REVERSAL) |
| description | VARCHAR(256) | 摘要 |
| status | ENUM | PENDING / VALIDATING / POSTED / REVERSED / FAILED |
| accounting_date | DATE | 会计日期(可能与交易日期不同) |
| transaction_time | TIMESTAMP | 交易时间 |
| posted_at | TIMESTAMP | 过账时间 |
| operator | VARCHAR(64) | 操作人 |
| source_system | VARCHAR(32) | 来源系统 |
| source_ref | VARCHAR(64) | 来源单号 |
| reversal_of | BIGINT FK | 被冲正的凭证ID(冲正时填写) |
| hash | VARCHAR(64) | 凭证Hash(用于防篡改) |
| prev_hash | VARCHAR(64) | 前一笔凭证Hash(Hash链) |
posting(分录明细)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | BIGINT PK | 主键 |
| journal_entry_id | BIGINT FK | 所属凭证ID |
| account_id | BIGINT FK | 账户ID |
| direction | ENUM | DEBIT / CREDIT |
| amount | DECIMAL(20,4) | 原币金额 |
| currency | VARCHAR(3) | 原币币种 |
| base_amount | DECIMAL(20,4) | 本位币金额 |
| base_currency | VARCHAR(3) | 本位币(如 CNY) |
| exchange_rate | DECIMAL(16,8) | 汇率 |
| posting_seq | INT | 分录序号 |
核心约束: 对同一个 journal_entry_id 下的所有 posting,必须满足:
SUM(CASE WHEN direction='DEBIT' THEN base_amount ELSE 0 END)
= SUM(CASE WHEN direction='CREDIT' THEN base_amount ELSE 0 END)
balance_snapshot(余额快照)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | BIGINT PK | 主键 |
| account_id | BIGINT FK | 账户ID |
| balance_type | ENUM | AVAILABLE / FROZEN / IN_TRANSIT / TOTAL |
| amount | DECIMAL(20,4) | 余额金额 |
| currency | VARCHAR(3) | 币种 |
| snapshot_date | DATE | 快照日期 |
| snapshot_time | TIMESTAMP | 快照时间 |
| last_posting_id | BIGINT | 最后一笔过账的posting ID |
audit_log(审计日志)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | BIGINT PK | 主键 |
| event_type | VARCHAR(32) | 事件类型(ACCOUNT_OPEN / POSTING / REVERSAL / BALANCE_QUERY) |
| entity_type | VARCHAR(32) | 实体类型(JOURNAL / ACCOUNT / BALANCE) |
| entity_id | VARCHAR(64) | 实体ID |
| action | VARCHAR(16) | CREATE / UPDATE / QUERY |
| before_state | JSONB | 变更前状态 |
| after_state | JSONB | 变更后状态 |
| operator | VARCHAR(64) | 操作人 |
| ip_address | VARCHAR(45) | 操作IP |
| timestamp | TIMESTAMP | 操作时间 |
| trace_id | VARCHAR(64) | 链路追踪ID |
3.2 分库分表策略
| 表 | 分片键 | 分片策略 | 说明 |
|---|---|---|---|
| journal_entry | accounting_date | 按月分表 | journal_entry_202604 |
| posting | journal_entry_id (同库同表) | 随 journal_entry 分片 | 保证凭证和分录在同一分片 |
| balance_snapshot | account_id | Hash取模(16片) | 按账户均匀分布 |
| audit_log | timestamp | 按月分表 | 冷数据定期归档到对象存储 |
关键原则:journal_entry 和 posting 必须在同一个数据库分片中,确保本地事务的原子性。
四、核心组件详细设计
4.1 科目体系管理
科目编码规则(四级):
大类(1位) - 中类(2位) - 小类(2位) - 明细(3位)
示例:
1 资产
1.01 流动资产
1.01.01 银行存款
1.01.01.001 工商银行人民币账户
2 负债
2.01 流动负债
2.01.01 应付账款
4 收入
4.01 利息收入
科目自然方向:
| 类型 | 自然方向 | 增加记 | 减少记 |
|---|---|---|---|
| 资产 | 借方(DEBIT) | 借方 | 贷方 |
| 费用 | 借方(DEBIT) | 借方 | 贷方 |
| 负债 | 贷方(CREDIT) | 贷方 | 借方 |
| 权益 | 贷方(CREDIT) | 贷方 | 借方 |
| 收入 | 贷方(CREDIT) | 贷方 | 借方 |
4.2 复式记账核心
记账模板机制:
为了减少上游系统的复杂度,Ledger Core 内置记账模板。上游只需传入业务类型和金额,引擎自动生成分录。
业务类型: PAYMENT_IN(收款入账)
模板:
DR 1.01.01.XXX(银行存款) 金额
CR 2.01.02.XXX(客户备付金) 金额
业务类型: LOAN_DISBURSEMENT(放款)
模板:
DR 1.02.01.XXX(贷款资产) 金额
CR 1.01.01.XXX(银行存款) 金额
业务类型: INTEREST_ACCRUAL(计提利息)
模板:
DR 1.02.02.XXX(应收利息) 金额
CR 4.01.01.XXX(利息收入) 金额
过账流程:
- 接收记账请求(含 idempotency_key)
- 幂等检查:Redis
SETNXidempotency_key - 解析业务类型,匹配记账模板
- 生成凭证(journal_entry)和分录(posting[])
- 试算平衡校验:
SUM(DR) == SUM(CR) - 开启数据库事务:
INSERT journal_entry + INSERT posting[] - 更新凭证状态为 POSTED
- 更新 Redis 中的实时余额
- 发送 Kafka 消息通知下游
- 返回凭证编号
4.3 余额计算引擎
三类余额:
| 类型 | 计算公式 | 用途 |
|---|---|---|
| 总余额 | 所有已过账分录的净值 | 账务查询、报表 |
| 可用余额 | 总余额 - 冻结金额 - 在途金额 | 业务判断(是否可支付) |
| 冻结余额 | 被风控/业务冻结的金额 | 风控hold |
实时余额 vs 快照余额:
- 实时余额:存储在 Redis 中,每次过账通过
INCRBY/DECRBY原子更新 - 快照余额:每日日终持久化到 balance_snapshot 表,用于历史查询和对账
- 恢复机制:Redis 故障后,从最近快照 + 增量 posting 重算
4.4 热点账户解决方案
详见 ADR-002
问题:某些账户(如备付金户、过渡户)被所有交易共同操作,单一行锁成为瓶颈。
方案:缓冲记账(Buffer Posting) + 影子账户
缓冲记账:
- 热点账户的分录不直接写入 posting 表
- 先写入
posting_buffer缓冲表(无锁竞争) - 定时任务(每5秒)将缓冲表中的分录按账户汇总,生成一笔汇总分录写入 posting 表
- 余额通过 Redis 实时更新(不受数据库锁影响)
影子账户:
- 将热点账户拆分为 N 个影子子账户(如 10 个)
- 写入时 Hash 路由到不同子账户
- 查询余额时 SUM 所有子账户
- 日终合并到主账户
4.5 日终批处理
详见 ADR-003
日终任务链:
Step 1: 切日(设定会计日期,停止当日新交易)
Step 2: 结息计算(按账户并行计算应计利息,生成计息凭证)
Step 3: 汇兑损益(多币种账户按日终汇率重估,生成损益凭证)
Step 4: 损益结转(将收入/费用类科目余额结转至本年利润)
Step 5: 试算平衡(全量校验 SUM(DR) = SUM(CR))
Step 6: 余额快照(持久化当日所有账户余额)
Step 7: 报表生成(科目余额表、试算平衡表)
Step 8: 数据归档(将 N 天前的明细数据归档到冷存储)
并行策略(MapReduce方式):
- 按 account_id Hash 分为 M 个分片
- 每个分片由独立 Worker 处理
- 步骤 2/3/6 可按分片并行
- 步骤 4/5/7 需要汇总结果,使用 Reduce 阶段
检查点与失败恢复:
- 每个 Step 完成后写入检查点(checkpoint 表)
- 失败后从最后一个成功的检查点恢复重跑
- 每个 Step 设计为幂等的,重复执行不会产生重复数据
4.6 多币种处理
原则:原币记账 + 本位币折算
例:收到 1000 USD,汇率 7.25
DR 银行存款-USD 1000 USD (base: 7250 CNY, rate: 7.25)
CR 客户备付金-USD 1000 USD (base: 7250 CNY, rate: 7.25)
汇率管理:
- 汇率表(exchange_rate)存储每日各币种对本位币汇率
- 记账时使用交易时刻的汇率
- 日终重估使用日终汇率
汇兑损益处理:
- 日终重估:比较原入账汇率和日终汇率,差额记入"汇兑损益"科目
- 实现损益:实际兑换时,差额记入"已实现汇兑损益"
- 未实现损益:持有外币资产的浮动盈亏,记入"未实现汇兑损益"
五、深度问题
5.1 性能优化
热点账户(已在4.4详述):缓冲记账 + 影子账户
批量记账优化:
- 支持 Batch API,一次提交多笔凭证
- 内部使用
COPY批量写入代替单条 INSERT - Pipeline Redis 操作,减少网络往返
读写分离:
- 写操作走主库
- 余额查询、报表查询走只读副本
- Redis 作为实时余额的第一层缓存
5.2 一致性保证
记账内部一致性:
- 凭证和分录在同一数据库分片,使用本地事务保证原子性
- 试算平衡检查在事务提交前执行,不平衡则回滚
跨系统一致性:
- 采用"本地事务 + 消息队列"模式(Transactional Outbox)
- 支付系统记账:支付服务写入本地事务表 → 发送记账请求 → 记账引擎过账 → 返回结果 → 支付服务更新状态
- 如果记账失败,支付系统触发补偿(冲正/重试)
- 引擎保证幂等性,相同 idempotency_key 不会重复记账
5.3 不可篡改设计
Append-Only:
- 所有表设计为只插入,不允许 UPDATE 或 DELETE
- 已过账凭证状态只能变为 REVERSED(通过生成新的冲正凭证)
- 数据库层面:使用 PostgreSQL Rule/Trigger 禁止 UPDATE/DELETE
Hash链:
- 每笔凭证计算 Hash = SHA256(entry_no + amount + prev_hash)
- 前一笔凭证的 Hash 存入 prev_hash 字段
- 形成类似区块链的链式结构,任何篡改会导致 Hash 链断裂
- 定期校验 Hash 链完整性
数据归档:
- 超过 1 年的明细数据归档到对象存储(如 S3/OSS)
- 归档数据保留 7 年以上
- 归档前生成 Merkle Tree Root,存入归档索引表
5.4 日终处理优化
时间窗口优化:
- 增量计算:只处理当日有变动的账户(通过 Kafka 记录当日活跃账户列表)
- 并行分片:按 account_id 分为 16-64 个分片并行处理
- 预计算:结息公式在记账时预计算存入中间表,日终只做汇总
失败恢复:
- 每个 Step 结束写检查点,记录 Step 编号 + 处理进度 + 中间结果
- 失败后自动从检查点恢复
- 关键 Step 设计幂等性:使用
INSERT ... ON CONFLICT DO NOTHING
5.5 审计合规
完整操作链路:
- 每个操作生成 trace_id,贯穿从上游请求到最终过账的全链路
- audit_log 记录操作前后状态(before_state / after_state)
- 支持按 entity_id / operator / time_range 多维查询
数据保留:
- 热数据(1年内):主库 PostgreSQL
- 温数据(1-3年):只读副本 / 分析库
- 冷数据(3-7年+):对象存储,按需加载
监管报送:
- 日终生成监管报送文件(固定格式)
- 支持按监管要求的时间粒度聚合数据
- 保留完整的报送记录和回执
5.6 架构演进路径
阶段1(MVP): 单库、单法人、单币种
→ 验证核心记账逻辑正确性
阶段2: 多币种支持
→ 增加汇率管理、汇兑损益处理
阶段3: 分库分表
→ journal/posting 按月分表,balance 按账户分片
阶段4: 多法人
→ 科目表按法人隔离,支持合并报表
阶段5: 集团合并报表
→ 多法人余额汇总,内部交易抵消
六、架构决策摘要
| ADR | 决策 | 理由 |
|---|---|---|
| ADR-001 | 采用 Journal/Posting + Balance 模型 | 符合复式记账原理,读写性能平衡 |
| ADR-002 | 缓冲记账 + 影子账户 | 解决热点账户并发,不牺牲一致性 |
| ADR-003 | MapReduce 并行日终处理 | 可控复杂度,满足2小时窗口要求 |
| - | PostgreSQL 作为主存储 | ACID 事务强,JSONB 灵活,分区表成熟 |
| - | Redis 作为余额缓存 | 原子操作保证并发安全,亚毫秒延迟 |
| - | Kafka 作为消息队列 | 高吞吐、持久化、支持事件溯源 |
| - | Append-Only + Hash链 | 满足审计不可篡改要求 |
七、面试口述版
2分钟版本
"这是一个金融级复式记账引擎。核心设计思路是三层分离:上层是API和业务适配层,中间是Ledger Core记账核心,底层是数据存储和缓存。
数据模型上采用经典的Journal-Posting-Balance三表结构:Journal是凭证头,Posting是分录明细,Balance是余额快照。每笔凭证必须满足借贷相等。
性能方面有三个关键设计:第一是热点账户用缓冲记账解决——先写缓冲表再汇总,避免单行锁竞争;第二是余额用Redis原子操作实时更新,不依赖数据库锁;第三是日终处理用MapReduce按账户分片并行处理,控制在2小时内。
一致性方面,凭证和分录用本地事务保证原子性,跨系统用Transactional Outbox模式。全链路设计为Append-Only加Hash链保证不可篡改。"
5分钟版本
在2分钟版本基础上补充:
"科目体系采用四级编码,区分资产/负债/权益/收入/费用五大类,每类有自然借贷方向。引擎内置记账模板,上游系统只需传业务类型和金额,引擎自动生成分录。
多币种处理采用原币记账加本位币折算,每条分录同时记录原币金额和按当时汇率折算的本位币金额。日终对外币账户做汇率重估,差额记入汇兑损益科目。
冲正采用红冲方式,不物理删除,而是生成一笔等额反向凭证。每笔凭证通过Hash链与前一笔关联,形成不可篡改的链式结构。
日终处理分8个Step执行:切日→结息→汇兑损益→损益结转→试算平衡→余额快照→报表→归档。每个Step有检查点,失败可从断点恢复。所有Step设计为幂等。
分库分表策略:journal和posting按会计月分表,balance按account_id Hash分片。关键约束是凭证和分录必须在同一分片保证本地事务。"
15分钟版本
在5分钟版本基础上展开每个组件的实现细节、异常处理、监控告警、容量规划,以及演进路径的每个阶段详细说明。具体参考本文档的第四、五章节。
八、自评与反思
设计优势
- 严格遵循会计准则:复式记账、借贷平衡、Append-Only,符合金融合规要求
- 性能与一致性平衡:缓冲记账解决热点问题,Redis保证实时性,本地事务保证原子性
- 可演进架构:从单库单法人到多法人合并报表,每个阶段边界清晰
- 运维友好:检查点恢复、幂等设计、Hash链校验、完整监控
设计取舍
- 没有使用Event Sourcing:虽然ES天然不可篡改,但实现复杂度高,余额查询需要重放事件,不适合高频余额查询场景
- 缓冲记账引入最终一致性:热点账户的余额在缓冲窗口内可能有秒级延迟,但通过Redis实时余额弥补
- 分库分表增加运维成本:但千万级TPS必须分片,这是必要的代价
可改进方向
- 引入 CQRS 模式分离读写模型,进一步优化查询性能
- 考虑 TiDB 等分布式数据库替代手动分库分表
- 引入 AI 异常检测,自动识别异常记账模式
- 添加实时风控集成,记账前检查账户风险状态