Arch Day 112
Arch Day 112: 系统设计面试(3) — 设计核心银行系统
Arch Day 112: 系统设计面试(3) — 设计核心银行系统
2026-03-29
第四阶段 - 高阶融合系统设计核心银行ACID日切多产品监管高可用
日期: 2026-03-29 (Day 112) 阶段: 第四阶段 - 高阶融合 标签: #系统设计 #核心银行 #ACID #日切 #多产品 #监管 #高可用
面试模拟 — 45分钟
面试场景
面试官: "请设计一个核心银行系统(Core Banking System)。需要支持存款、贷款、支付等基本银行业务。这是一个中型银行,有500万客户,日均交易量200万笔。"
第一步:需求澄清(5分钟)
我的提问
功能需求确认:
Q1: 支持哪些产品?
A: 活期存款、定期存款、个人贷款、信用贷款。
Q2: 需要支持多币种吗?
A: 是的,人民币为主,也支持美元和港币。
Q3: 日切(Day-End Processing)的截止时间?
A: 当天23:00开始日切,次日06:00前完成。
Q4: 是否需要对接监管报送?
A: 是,需要向央行/银保监报送大额交易、存贷款统计等。
Q5: 实时性要求?
A: 账户余额实时更新,利息可以日终批量计算。
非功能需求确认:
Q6: 客户规模?
A: 500万个人客户,5万企业客户。
Q7: 日均交易量?
A: 200万笔/天,峰值(工资日/月末)500万笔。
Q8: 延迟要求?
A: 转账类交易<2秒,查询<500ms。
Q9: 可用性和合规?
A: 99.99%可用性。满足银保监会的信息系统等级保护要求。
Q10: 是替换遗留系统还是新建?
A: 新建,但需要考虑数据迁移和并行运行期。
需求总结
核心挑战:
├── 强ACID: 金融交易零容忍错误(1分钱都不能差)
├── 日切处理: 日终批处理(计息/结息/报表)必须在窗口期内完成
├── 多产品: 存/贷/汇不同产品有不同的业务规则
├── 监管合规: 实时大额报送、定期统计报表、审计追踪
├── 7×24不间断: 客户随时操作,日切期间也要支持部分交易
└── 数据迁移: 从旧系统迁移500万客户的历史数据
第二步:高层设计(10分钟)
2.1 领域模型
核心银行领域模型:
┌──────────────────────────────────────────────────────────┐
│ Core Banking Domain Model │
├──────────────────────────────────────────────────────────┤
│ │
│ ┌────────────┐ ┌────────────────┐ │
│ │ Customer │─────→│ Account │ │
│ │ (客户) │ 1:N │ (账户) │ │
│ │ │ │ ├─活期账户 │ │
│ │ ├─个人客户 │ │ ├─定期账户 │ │
│ │ └─企业客户 │ │ ├─贷款账户 │ │
│ └────────────┘ │ └─内部账户 │ │
│ └───────┬────────┘ │
│ │ │
│ ┌──────┴──────┐ │
│ │ Transaction │ │
│ │ (交易) │ │
│ │ ├─转账 │ │
│ │ ├─存取款 │ │
│ │ ├─计息 │ │
│ │ └─费用 │ │
│ └──────┬──────┘ │
│ │ │
│ ┌──────┴──────┐ │
│ │ Ledger │ │
│ │ (账本) │ │
│ │ 复式记账 │ │
│ │ 借方=贷方 │ │
│ └─────────────┘ │
│ │
│ 辅助域: │
│ ├── Product (产品) → 定义产品参数(利率/期限/规则) │
│ ├── Interest (计息) → 利息计算引擎 │
│ ├── Fee (费用) → 手续费计算规则 │
│ ├── Limit (限额) → 单笔/日累计/客户级限额 │
│ ├── Compliance (合规) → 大额/可疑交易监控 │
│ └── Report (报表) → 监管报送/内部报表 │
│ │
└──────────────────────────────────────────────────────────┘
2.2 系统架构
核心银行系统架构:
┌──────────────────────────────────────────────────────────────┐
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │手机银行 │ │网银 │ │柜面系统 │ ... (渠道层) │
│ └─────┬────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ ┌─────┴────────────┴──────────────┴──────────────────────┐ │
│ │ API Gateway (统一接入) │ │
│ │ ├── 认证/鉴权 │ │
│ │ ├── 限流/熔断 │ │
│ │ ├── 协议转换(REST/gRPC/MQ) │ │
│ │ └── 审计日志 │ │
│ └──────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────┴───────────────────────────────┐ │
│ │ Service Layer │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ │ │
│ │ │ Customer │ │ Account │ │ Deposit │ │ Loan │ │ │
│ │ │ Service │ │ Service │ │ Service │ │ Service│ │ │
│ │ │ (客户) │ │ (账户) │ │ (存款) │ │ (贷款) │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └────────┘ │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ │ │
│ │ │ Payment │ │ Interest │ │ Fee │ │ Limit │ │ │
│ │ │ Service │ │ Engine │ │ Engine │ │ Service│ │ │
│ │ │ (支付) │ │ (计息) │ │ (费用) │ │ (限额) │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └────────┘ │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────────────────┐ │ │
│ │ │ Ledger │ │ Batch │ │ Compliance/Report │ │ │
│ │ │ (账本) │ │ (批处理) │ │ (合规/报表) │ │ │
│ │ └──────────┘ └──────────┘ └──────────────────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────┴───────────────────────────────┐ │
│ │ Data Layer │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ 主库 │ │ 读库 │ │ 分析库 │ │ │
│ │ │(PostgreSQL)│ │(只读副本)│ │(ClickHouse)│ │ │
│ │ │ ACID保证 │ │ 查询优化 │ │ 报表/分析│ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
第三步:核心组件设计(15分钟)
3.1 账户与账本模型 ★ 核心
复式记账模型(Double-Entry Bookkeeping):
核心原则: 每笔交易必须同时记录借方和贷方,借方总额=贷方总额
示例: 客户A转账100元给客户B
借方(Debit): 客户A账户 -100
贷方(Credit): 客户B账户 +100
会计分录:
DR(借) 客户A活期存款 100.00
CR(贷) 客户B活期存款 100.00
验证: DR总额(100) = CR总额(100) ✓
-- 账户表
CREATE TABLE account (
id BIGINT PRIMARY KEY,
account_no VARCHAR(32) UNIQUE NOT NULL, -- 账号
customer_id BIGINT NOT NULL,
product_code VARCHAR(20) NOT NULL, -- 产品代码
account_type VARCHAR(20) NOT NULL, -- DEMAND/FIXED/LOAN/INTERNAL
currency VARCHAR(3) DEFAULT 'CNY',
status VARCHAR(10) NOT NULL, -- ACTIVE/FROZEN/CLOSED
balance BIGINT NOT NULL DEFAULT 0, -- 余额(分) ★
available BIGINT NOT NULL DEFAULT 0, -- 可用余额(分)
frozen_amount BIGINT NOT NULL DEFAULT 0, -- 冻结金额(分)
open_date DATE NOT NULL,
close_date DATE,
last_txn_date DATE,
interest_rate DECIMAL(10,6), -- 利率(活期/贷款)
version INT DEFAULT 0, -- 乐观锁
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- 核心约束: balance = available + frozen_amount (永远成立)
-- 账本表(分录)
CREATE TABLE ledger_entry (
id BIGINT PRIMARY KEY,
txn_id BIGINT NOT NULL, -- 交易ID
txn_no VARCHAR(64) NOT NULL, -- 交易流水号
account_no VARCHAR(32) NOT NULL,
direction CHAR(1) NOT NULL, -- D=借方/C=贷方
amount BIGINT NOT NULL, -- 金额(分,正数)
balance_before BIGINT NOT NULL, -- 记账前余额
balance_after BIGINT NOT NULL, -- 记账后余额
txn_type VARCHAR(20) NOT NULL, -- TRANSFER/DEPOSIT/INTEREST/FEE
value_date DATE NOT NULL, -- 起息日
book_date DATE NOT NULL, -- 记账日
memo VARCHAR(200),
created_at TIMESTAMP DEFAULT NOW()
);
-- 核心约束: 同一txn_id的所有借方金额之和 = 所有贷方金额之和
-- 交易表
CREATE TABLE transaction (
id BIGINT PRIMARY KEY,
txn_no VARCHAR(64) UNIQUE NOT NULL,
txn_type VARCHAR(20) NOT NULL,
from_account VARCHAR(32),
to_account VARCHAR(32),
amount BIGINT NOT NULL,
currency VARCHAR(3),
status VARCHAR(20) NOT NULL, -- PENDING/SUCCESS/FAILED/REVERSED
channel VARCHAR(20), -- MOBILE/WEB/COUNTER/BATCH
initiated_by BIGINT, -- 操作员/客户ID
idempotency_key VARCHAR(128) UNIQUE,
created_at TIMESTAMP DEFAULT NOW(),
completed_at TIMESTAMP
);
-- 产品参数表
CREATE TABLE product (
id BIGINT PRIMARY KEY,
product_code VARCHAR(20) UNIQUE NOT NULL,
product_name VARCHAR(100),
product_type VARCHAR(20) NOT NULL, -- DEMAND_DEPOSIT/FIXED_DEPOSIT/LOAN
currency VARCHAR(3),
base_rate DECIMAL(10,6), -- 基准利率
min_amount BIGINT, -- 最低金额
max_amount BIGINT, -- 最高金额
interest_method VARCHAR(20), -- SIMPLE/COMPOUND/...
interest_cycle VARCHAR(10), -- DAILY/MONTHLY/QUARTERLY
status VARCHAR(10),
effective_date DATE,
expiry_date DATE
);
3.2 转账流程(核心交易流程)
转账流程(同行实时转账):
┌──────────────────────────────────────────────────────────┐
│ Transfer Transaction │
├──────────────────────────────────────────────────────────┤
│ │
│ Step 1: 请求验证 │
│ ├── 幂等检查(idempotency_key) │
│ ├── 参数验证(金额>0, 账户格式, 币种) │
│ ├── 付款方身份验证(密码/指纹/人脸) │
│ └── 收款方账户验证(是否存在/是否正常) │
│ │
│ Step 2: 业务规则检查 │
│ ├── 账户状态检查(是否冻结/关闭) │
│ ├── 限额检查(单笔/日累计/月累计) │
│ ├── 余额检查(available >= amount) │
│ ├── 产品规则检查(定期存款不能直接转出) │
│ └── 合规检查(大额交易/可疑交易) │
│ │
│ Step 3: 记账(单一数据库事务) ★核心 │
│ BEGIN TRANSACTION │
│ │ │
│ │ -- 扣款方账户 │
│ │ UPDATE account SET │
│ │ balance = balance - 10000, │
│ │ available = available - 10000, │
│ │ version = version + 1 │
│ │ WHERE account_no = 'A001' │
│ │ AND available >= 10000 │
│ │ AND version = {current_version} │
│ │ -- 影响行数=0 → 余额不足或并发冲突 → ROLLBACK │
│ │ │
│ │ -- 收款方账户 │
│ │ UPDATE account SET │
│ │ balance = balance + 10000, │
│ │ available = available + 10000, │
│ │ version = version + 1 │
│ │ WHERE account_no = 'B001' │
│ │ │
│ │ -- 记录分录(借方) │
│ │ INSERT INTO ledger_entry (direction='D', │
│ │ account='A001', amount=10000, ...) │
│ │ │
│ │ -- 记录分录(贷方) │
│ │ INSERT INTO ledger_entry (direction='C', │
│ │ account='B001', amount=10000, ...) │
│ │ │
│ │ -- 记录交易 │
│ │ INSERT INTO transaction (...) │
│ │ │
│ COMMIT │
│ │
│ Step 4: 后续处理(异步) │
│ ├── 通知客户(短信/APP推送) │
│ ├── 大额交易报送(>5万自动报送) │
│ ├── 风控异步检查 │
│ └── 更新统计数据 │
│ │
└──────────────────────────────────────────────────────────┘
3.3 日切处理(Day-End Processing) ★ 银行特有
日切流程(每日23:00-06:00):
┌──────────────────────────────────────────────────────────┐
│ Day-End Processing Pipeline │
├──────────────────────────────────────────────────────────┤
│ │
│ 23:00 日切开始 │
│ │ │
│ ├── Phase 1: 切换营业日期(5分钟) │
│ │ ├── 设置系统日期 = T → T+1 │
│ │ ├── T日的交易标记为T日 │
│ │ ├── T+1日起的交易标记为T+1日 │
│ │ └── 部分交易暂停(批处理涉及的类型) │
│ │ │
│ ├── Phase 2: 活期存款计息(60分钟) │
│ │ ├── 遍历所有活期账户(~500万) │
│ │ ├── 日利息 = 余额 × 日利率 │
│ │ │ (积数法: 累积每日余额×天数) │
│ │ ├── 每月21日结息(或每季末) │
│ │ ├── 结息: 计算→入账→生成利息凭证 │
│ │ └── 并行处理: 按账户号分10个批次 │
│ │ │
│ ├── Phase 3: 定期存款到期处理(30分钟) │
│ │ ├── 扫描T+1到期的定期存款 │
│ │ ├── 自动转存 或 转入活期 │
│ │ ├── 计算到期利息 │
│ │ └── 生成到期通知 │
│ │ │
│ ├── Phase 4: 贷款处理(60分钟) │
│ │ ├── 贷款计息(每日) │
│ │ ├── 到期还款处理 │
│ │ │ ├── 自动扣款(从关联账户) │
│ │ │ └── 扣款失败 → 生成催收工单 │
│ │ ├── 逾期处理 │
│ │ │ ├── 逾期天数+1 │
│ │ │ ├── 利率上浮(逾期罚息) │
│ │ │ └── 逾期>90天 → 不良贷款分类 │
│ │ └── 五级分类调整(正常/关注/次级/可疑/损失) │
│ │ │
│ ├── Phase 5: 费用处理(15分钟) │
│ │ ├── 账户管理费扣收 │
│ │ ├── 短信费扣收 │
│ │ └── 其他周期性费用 │
│ │ │
│ ├── Phase 6: 报表生成(60分钟) │
│ │ ├── 内部报表(总账/明细账/日记账) │
│ │ ├── 监管报表(大额交易报送/存贷款统计) │
│ │ ├── 风险报表(不良贷款/拨备/资本充足率) │
│ │ └── 数据同步到分析库(ClickHouse) │
│ │ │
│ ├── Phase 7: 对账(30分钟) │
│ │ ├── 内部对账: 总账=明细账 │
│ │ ├── 外部对账: 与央行/清算系统对账 │
│ │ └── 差异处理: 自动调平/人工处理 │
│ │ │
│ └── Phase 8: 校验与收尾(15分钟) │
│ ├── 借贷平衡校验(全行借方=贷方) │
│ ├── 日切结果汇总 │
│ ├── 异常清单生成(需要人工处理的) │
│ └── 标记日切完成 │
│ │
│ 06:00 日切结束 │
│ │
│ ★关键: 日切期间部分交易仍可进行(如ATM/线上转账) │
│ ★挑战: 计息和交易并发 → 需要快照隔离(Snapshot) │
│ │
└──────────────────────────────────────────────────────────┘
3.4 计息引擎
计息引擎设计:
┌──────────────────────────────────────────────────────────┐
│ Interest Engine │
├──────────────────────────────────────────────────────────┤
│ │
│ 活期存款计息(积数法): │
│ ├── 每日记录: 日终余额 × 1天 │
│ ├── 结息周期: 每季度末(3/6/9/12月21日) │
│ ├── 结息计算: │
│ │ 利息 = Σ(每日余额) × 日利率 │
│ │ 日利率 = 年利率 / 360 │
│ │ │
│ │ 示例: 年利率0.2%, 某季度90天 │
│ │ 第1-30天: 余额10000 │
│ │ 第31-60天: 余额15000 │
│ │ 第61-90天: 余额12000 │
│ │ 积数 = 10000×30 + 15000×30 + 12000×30 │
│ │ = 1,110,000 │
│ │ 利息 = 1,110,000 × (0.002/360) │
│ │ = 6.17元 │
│ └── 利息入账: 自动转入活期余额 │
│ │
│ 定期存款计息: │
│ ├── 整存整取: 到期一次性计息 │
│ │ 利息 = 本金 × 年利率 × 存期(年) │
│ ├── 零存整取: 每月存入固定金额 │
│ │ 利息 = 月存额 × 累计月数 × 月利率 │
│ └── 提前支取: 按活期利率计算 │
│ │
│ 贷款计息: │
│ ├── 等额本息: │
│ │ 月还款 = P × r(1+r)^n / ((1+r)^n - 1) │
│ │ P=本金, r=月利率, n=期数 │
│ ├── 等额本金: │
│ │ 每月本金 = P/n │
│ │ 每月利息 = 剩余本金 × 月利率 │
│ ├── 逾期罚息: 正常利率 × 1.5 │
│ └── 复利计算: 利息不还时计入本金(按合同约定) │
│ │
└──────────────────────────────────────────────────────────┘
第四步:深入讨论(10分钟)
4.1 数据库设计策略
核心银行数据库策略:
原则: 核心账务必须用关系型数据库 + ACID事务
数据库选型: PostgreSQL
├── 强ACID保证(金融系统的底线)
├── MVCC + 快照隔离(支持日切并发)
├── 行级锁(高并发转账)
├── 丰富的数据类型(JSON/NUMERIC精确计算)
└── 开源(降低License成本)
分库策略:
┌───────────────────────────────────────────┐
│ 分库方案: │
│ │
│ 核心库(account_db) ← 最重要,强一致 │
│ ├── account表 │
│ ├── ledger_entry表 │
│ └── transaction表 │
│ → 按客户号分片(8片) │
│ → 同一客户的账户和分录在同一个分片 │
│ → 保证单客户内的事务在同一个DB │
│ │
│ 产品库(product_db) ← 变更少,可缓存 │
│ ├── product表 │
│ ├── interest_rate表 │
│ └── fee_rule表 │
│ → 单库即可(数据量小) │
│ │
│ 合规库(compliance_db) ← 写多读少 │
│ ├── large_txn_report表 │
│ └── suspicious_txn表 │
│ → 单库(数据量中等) │
│ │
│ 分析库(analytics_db) ← 离线分析 │
│ ├── ClickHouse │
│ └── 从核心库T+1同步 │
│ │
│ 跨分片交易: │
│ ├── A行客户转账给B行客户 │
│ │ → 两个分片 → 需要分布式事务 │
│ ├── 方案: Saga + 补偿 │
│ │ Step 1: A分片扣款(本地事务) │
│ │ Step 2: B分片入账(本地事务) │
│ │ 失败: 补偿(A分片退款) │
│ └── 中间状态: A已扣款但B未入账 │
│ → 通过定时任务补偿(最终一致) │
└───────────────────────────────────────────┘
4.2 高可用设计
核心银行高可用架构:
┌──────────────────────────────────────────────────────────┐
│ High Availability Design │
├──────────────────────────────────────────────────────────┤
│ │
│ 双中心架构(同城双活): │
│ │
│ ┌─── 数据中心A(主) ────────────────────────────────┐ │
│ │ App Server × 10 │ │
│ │ DB Primary(分片1-4) │ │
│ │ Redis Cluster │ │
│ │ Kafka Cluster │ │
│ └───────────────────────────────────────────────────┘ │
│ │ │
│ 同步复制(数据库) │
│ 异步复制(Kafka/Redis) │
│ │ │
│ ┌─── 数据中心B(备) ────────────────────────────────┐ │
│ │ App Server × 10 (Standby) │ │
│ │ DB Standby(分片1-4) │ │
│ │ Redis Replica │ │
│ │ Kafka Replica │ │
│ └───────────────────────────────────────────────────┘ │
│ │
│ RPO/RTO: │
│ ├── RPO(数据丢失): 0(同步复制→零数据丢失) │
│ ├── RTO(恢复时间): <5分钟(自动切换) │
│ └── 年可用性: 99.99%(停机<52分钟/年) │
│ │
│ 故障切换流程: │
│ ├── 心跳检测(每3秒) │
│ ├── 连续3次心跳失败 → 判定故障 │
│ ├── 自动提升Standby为Primary │
│ ├── DNS切换(GSLB) │
│ ├── 应用重连(连接池自动重建) │
│ └── 告警通知 → 运维介入排查 │
│ │
│ 日切期间的可用性: │
│ ├── 问题: 日切批处理占用大量DB资源 │
│ ├── 解决: 批处理在读副本上运行(快照读) │
│ ├── 在线交易继续在主库处理 │
│ └── 计息结果通过事务写回主库 │
│ │
└──────────────────────────────────────────────────────────┘
4.3 监管合规
监管合规设计:
┌──────────────────────────────────────────────────────────┐
│ Compliance Framework │
├──────────────────────────────────────────────────────────┤
│ │
│ 1. 大额交易报送(实时) │
│ ├── 个人现金: 单笔≥5万元 → 自动报送 │
│ ├── 企业现金: 单笔≥20万元 → 自动报送 │
│ ├── 个人转账: 单笔≥50万元 → 自动报送 │
│ ├── 实现: 交易完成→异步MQ→合规服务→央行接口 │
│ └── SLA: 交易完成后1个工作日内报送 │
│ │
│ 2. 可疑交易监控(准实时) │
│ ├── 规则引擎: 预定义可疑行为模式 │
│ │ ├── 短时间内大量小额转账(拆分交易) │
│ │ ├── 异地频繁交易 │
│ │ ├── 与黑名单账户有交易 │
│ │ └── 交易金额与客户画像不符 │
│ ├── 实现: Flink流处理 → 规则匹配 → 告警 │
│ └── 输出: 可疑交易报告(SAR) │
│ │
│ 3. 监管报表(批处理) │
│ ├── 存款统计报表(日/月) │
│ ├── 贷款统计报表(日/月) │
│ ├── 不良贷款报表(月) │
│ ├── 资本充足率报表(季) │
│ ├── 流动性报表(日) │
│ └── 实现: 日切批处理→分析库→报表引擎→自动提交 │
│ │
│ 4. 审计追踪(全量) │
│ ├── 所有交易完整日志(不可删除) │
│ ├── 所有操作员操作日志 │
│ ├── 系统配置变更日志 │
│ ├── 保留年限: ≥15年(监管要求) │
│ └── 存储: 冷存储(S3/OSS) + 热存储(ES, 近1年) │
│ │
└──────────────────────────────────────────────────────────┘
第五步:扩展性设计(5分钟)
5.1 服务拆分策略
微服务拆分(按业务能力):
Phase 1: 粗粒度拆分(上线初期)
├── 客户服务(Customer)
├── 账户服务(Account) ← 含记账
├── 存款服务(Deposit) ← 含计息
├── 贷款服务(Loan) ← 含还款/催收
├── 支付服务(Payment) ← 对外支付
├── 合规服务(Compliance)
└── 批处理服务(Batch)
Phase 2: 细粒度拆分(业务增长后)
├── 账户服务 → 拆为 账户+账本+限额
├── 存款服务 → 拆为 活期+定期+结构性存款
├── 贷款服务 → 拆为 贷款+催收+资产管理
├── 支付服务 → 拆为 内部转账+跨行支付+国际汇款
└── 新增: 计息引擎(独立服务)、费用引擎(独立服务)
拆分原则:
├── 同一聚合根内的操作在同一个服务(DDD指导)
├── 同一事务中的操作尽量在同一个服务
├── 高频变更和低频变更分离
└── 核心和非核心分离(核心服务更高SLA)
5.2 从500万到5000万客户
扩展路径:
500万客户(当前):
├── 8个数据库分片
├── 10个应用实例
├── 200万TPS/天 → ~25 TPS均值
└── 单中心部署
5000万客户(目标):
├── 64个数据库分片
├── 50个应用实例
├── 2000万TPS/天 → ~250 TPS均值
├── 双中心部署
├── 读写分离(查询走只读副本)
├── 缓存策略:
│ ├── 产品参数: Redis缓存(15分钟TTL)
│ ├── 账户余额: 不缓存(必须实时)
│ ├── 客户信息: Redis缓存(5分钟TTL)
│ └── 限额计数: Redis Incr(日终清零)
└── 批处理优化:
├── 分片并行(64个分片并行计息)
├── 增量处理(只处理有变动的账户)
└── 日切时间: 7小时→3小时
面试官追问及应对
追问1: "如何处理跨分片转账?"
同行跨分片转账方案:
方案: Saga + 最终一致性
流程:
1. 创建转账事务记录(status=PENDING)
2. 分片A: 本地事务扣款(status=DEDUCTED)
3. 发送MQ消息到分片B
4. 分片B: 本地事务入账(status=CREDITED)
5. 确认转账完成(status=SUCCESS)
失败补偿:
├── Step 2失败(扣款失败): 直接返回失败
├── Step 3-4失败(入账失败):
│ ├── 自动重试3次
│ └── 仍失败 → 补偿: 分片A退款(status=REVERSED)
└── 超时处理:
├── 定时任务扫描DEDUCTED超过5分钟的记录
├── 主动查询分片B是否入账
└── 未入账 → 补偿退款
一致性保证:
├── 转账事务表: 记录每一步的状态
├── 幂等性: 每步操作可安全重试
├── 对账: 日终校验所有转账的最终状态
└── 告警: PENDING超过10分钟 → P1告警
追问2: "日切期间如何保证交易不中断?"
日切不停机方案:
核心思路: 日切在"读副本+快照"上运行,不影响主库的在线交易
实现:
1. 23:00 创建数据库快照(PostgreSQL pg_dump或逻辑复制)
2. 批处理任务在只读副本上执行计算
3. 计算结果通过事务批量写入主库
├── 活期计息: 累积一批(1000条)一次写入
├── 贷款处理: 逐笔写入(涉及复杂逻辑)
└── 写入时加分布式锁(防止与在线交易冲突)
4. 在线交易照常处理
├── 如果与日切处理同一账户 → 排队等待
├── 锁粒度: 账户级别(不影响其他账户)
└── 等待时间通常<100ms
日切与交易冲突处理:
├── 场景: 正在给账户A计息,此时A有一笔转账
├── 解决: 计息使用快照余额,转账使用实时余额
├── 两个操作互不影响(MVCC快照隔离)
└── 验证: 日切结束后校验总账平衡
完整答案总结
核心银行系统设计要点:
1. 账户模型: 复式记账(借方=贷方), 余额=可用+冻结
2. 事务保证: ACID是金融系统的底线,单分片内强一致,跨分片Saga
3. 日切设计: 快照+只读副本,不停机处理,7小时窗口
4. 计息引擎: 积数法(活期)、等额本息/等额本金(贷款)、逾期罚息
5. 监管合规: 大额自动报送、可疑交易实时监控、15年审计日志
6. 高可用: 同城双活、RPO=0、RTO<5分钟、99.99%
7. 扩展性: 按客户号分片、读写分离、批处理并行化