土法炼钢兴趣小组的算法知识备份

【金融科技工程】账务数据库设计:TiDB/OceanBase/Postgres 下的分片、索引、热点账户

文章导航

分类入口
architecturefintech
标签入口
#ledger-db#oceanbase#tidb#postgresql#sharding#hot-account#archive#tigerbeetle

目录

引子

上一篇《复式记账工程化》把账务模型落到了 accountsjournal_entriespostings 三张表。到这里,设计图纸画得再漂亮,也挡不住一个现实问题:这三张表放哪儿

“放数据库”三个字在账务场景里远不是一行 CREATE TABLE 能解决的。一个成熟支付机构,日分录(postings)量级在亿到十亿级,单行写入必须带事务,读写延迟在 P99 十毫秒以内,还要满足 RPO=0(零数据丢失)、RTO<1min(故障一分钟切换)、审计数据保留七到十年、任何一行都不能被 UPDATE。你要扛住这些约束,数据库选型、分片策略、索引、归档、并发控制几乎都要重新推一遍。

这篇文章的读者画像是:

我们不会挨个讲 SQL 语法,重点在为什么选、怎么切、怎么扛热点、怎么归档、怎么对审计交差。文末会落到一份选型清单和一张可以直接抄的部署架构图。


一、金融账务的 SLA 框架

账务数据库的设计上限由业务 SLA(Service Level Agreement)决定。离开 SLA 谈”用什么数据库最好”是空中楼阁。

1.1 RPO 与 RTO

这两个指标直接排除了”异步主从 MySQL”、“跨可用区异步同步的 PostgreSQL 主从”这类方案在关键账务路径上的独立部署可能。要么叠加同步复制,要么直接上共识协议。

1.2 一致性与隔离级别

账务强一致来源于复式记账的约束:借贷必须同事务成功或同事务失败,余额视图必须反映最新分录。工程语境下至少需要:

1.3 审计、归档与合规

把以上组合起来,账务数据库实际要满足的”组合 SLA”是:

维度 账务数据库目标
写入吞吐 单集群 10k–100k TPS(分录行)
读延迟 P99 < 10 ms
可用性 99.99%(年停机 < 52 分钟)
RPO 0
RTO < 1 min
保留年限 热数据 1–2 年、温 3–7 年、冷 10–30 年
一致性 线性一致、事务原子
审计 append-only、不可篡改

1.4 不同业务形态的差异

不是所有账务都长一个样:

后面选型要对照不同形态来看。


二、主流选型对比

把能选的都摆出来,再按成本、规模、案例筛。

2.1 PostgreSQL

优势

劣势

适用规模:中小规模账务(日分录 < 1 亿)、B 端 SaaS、证券/基金/信托核心。典型用法是主 + 同步复制从 + 异地异步备 + 分区归档。

案例:Stripe 早期账务层核心表建在 PostgreSQL 上;Revolut 2020 年代初期全栈 PostgreSQL;国内不少持牌支付机构的备付金账务使用 PostgreSQL + Patroni 集群。

2.2 MySQL InnoDB

优势

劣势

适用规模:互联网支付、电商账务中等到大规模。阿里/蚂蚁、京东、美团、拼多多、字节跳动的账务体系都有长期在 MySQL 上深耕的历史。

典型演进路径:单机 MySQL → 一主多从 → 垂直拆分(按业务域)→ 水平分库分表(按 account_id / user_id hash)→ 分布式数据库(OceanBase / TiDB)。

2.3 OceanBase

蚂蚁集团自研的分布式关系数据库,原生 Paxos 三副本、MySQL 协议兼容(也兼容部分 Oracle 语法),典型”金融核心场景”产品。

优势

劣势

适用规模:日分录 10 亿 + 的超大规模账务、银行核心、证券账户体系。

2.4 TiDB

PingCAP 开源的分布式数据库,TiKV + TiDB Server + PD 三组件架构,Raft 多副本。

优势

劣势

适用规模:日分录数亿到十亿级、有 HTAP 诉求、开源栈偏好。

2.5 CockroachDB

美国 Cockroach Labs 开源产品(自 2022 年起部分核心代码转为 CockroachDB Community License,非完全 OSI 开源),主打全球部署。

优势

劣势

适用规模:跨境支付、全球化 SaaS 账务、需要多地数据主权合规的场景。国际案例如 Bose、DoorDash、Form3(开放银行支付平台)。

2.6 Oracle

优势

劣势

适用规模:传统银行核心、保险、清算机构。典型案例:中国人民银行第二代支付系统(CNAPS2)历史上依赖 Oracle + DB2,逐步向国产数据库迁移中。

2.7 专用账务数据库:TigerBeetle

一个非常有意思的路线:为复式记账专门设计的数据库,用 Zig 写,单表结构(accounts + transfers)、强一致(VSR/Viewstamped Replication)、单机百万 TPS 设计目标。

优势

劣势

适用规模:新建高性能账务、加密资产交易所内账、游戏内经济系统。

2.8 自研 Ledger:Stripe、Square、大厂内部账务

互联网金融公司普遍在通用数据库之上包一层”Ledger Service”:

这里的核心启发:数据库不是账务的全部,账务服务层负责”复式约束、幂等、热点拆解、审计落库”,数据库负责”存、查、事务、复制”

2.9 一张选型对比表

数据库 开源 协议 副本协议 RPO=0 典型规模(日分录) 代表案例
PostgreSQL PG 逻辑/物理复制 依赖同步复制配置 < 1 亿 Stripe 早期、Revolut
MySQL + 分库分表 MySQL semi-sync 近似 10 亿 + 阿里早期、京东、Square
OceanBase 社区版开源 MySQL/Oracle Paxos 100 亿 + 蚂蚁、网商、工行
TiDB MySQL Raft 10 亿 + 微众、中国人寿、PayPay
CockroachDB BSL PG Raft 1–10 亿 DoorDash、Form3
Oracle Oracle Data Guard 10 亿 + 传统银行核心
TigerBeetle 自定义 VSR 设计百万 TPS 少量新系统

三、分片维度的选择

只要数据库在单机或单集群规模达到瓶颈,就必须分片。分片维度直接决定了事务代价热点分布索引成本运维复杂度

3.1 按用户(user_id / account_owner_id)分片

适用:面向 C 端的钱包、银行核心、证券经纪业务。

优点

缺点

3.2 按科目(account_code)分片

适用:总账(General Ledger)、财务报表系统。

优点

缺点

3.3 按时间分片

适用:流水表、事件日志、审计日志。

优点

缺点

3.4 按机构(institution_id / merchant_id)分片

适用:B 端 SaaS、PaaS 支付平台,一个租户就是一个机构。

优点

缺点

3.5 组合维度与”分片键即路由”

实战中极少单维度,典型做法:

以蚂蚁/支付宝早期的经验为例(公开资料可查):账户表按用户 ID hash 分 N 片(N 从 100 到 上千再到 OceanBase 之后不再可见),每片再按月分区。商户 / 渠道 / 平台账户单独放在”系统分片”里,和普通用户 C2C 路径走不同库。

3.6 跨分片事务的代价

真实数字不夸张地说:跨分片事务是单分片事务成本的 5–10 倍。原因:

  1. 多段 RPC / 两阶段提交协议额外网络;
  2. 分布式锁持有时间变长,并发度下降;
  3. 故障模式增多(协调者故障、参与者故障),需要补偿;
  4. 监控、审计、幂等语义变复杂。

应对策略:

3.7 分片演进的工程原则

  1. 分片键一旦确定,极难更换。上线前务必压测头部与长尾的数据倾斜;
  2. 分片数量取 2 的幂或质数:2 的幂便于一致性哈希扩容;
  3. 预留分片:上线时分片数 > 当前需要,比如未来 3 年的 2 倍容量;
  4. 路由层独立:ShardingSphere、Vitess 这类在应用和数据库间插一层,而不是把路由逻辑写在应用里;
  5. 分片映射元数据本身要高可用:路由信息放在 etcd / ZK / PD 里,不能丢。

四、热点账户:金融系统的”头号 BUG 制造机”

4.1 什么是热点账户

一笔 C2C 转账可能涉及:

前两者是分布账户,后三者是集中账户 = 热点账户。一台机器哪怕 SSD、哪怕 InnoDB,行级锁争抢也会卡死在那几行上。

公开案例:Uber 2019 年 CNCF 演讲披露早期 MySQL 上 “platform fee account” 单行 QPS 瞬时过万,成为整个支付链路瓶颈;蚂蚁的”贷款平台总账”、支付宝的”手续费总账”都是同类问题的历史体现。

4.2 Shadow Account(影子账户)/ 分桶

思路:把一个逻辑账户拆成 N 个物理桶(subaccount / shadow),写入时随机或哈希打散到某个桶,余额查询时对 N 个桶求和。

-- 原始(热点)
UPDATE accounts SET balance = balance + 100 WHERE account_id = 'FEE-POOL';

-- 分桶后
-- 写入:对 merchant_id hash 到桶
UPDATE accounts_buckets
SET balance = balance + 100
WHERE account_id = 'FEE-POOL' AND bucket = hash(merchant_id) % 64;

-- 读取:聚合
SELECT SUM(balance) FROM accounts_buckets WHERE account_id = 'FEE-POOL';

工程注意

4.3 批量合并(Batching)

思路:业务写入不直接打到热点账户行,先写入到”待合并队列”(一张流水表或 Kafka),定时(秒级)批处理合并一笔大额分录落到热点账户。

业务事件 → 写入 fee_pending 表(按 merchant 一行一笔,不争抢)
            → 每 N 秒或每 M 条 flush:
                 INSERT 一笔合并分录到 journal
                 UPDATE FEE-POOL 账户余额 += SUM(pending)
                 DELETE fee_pending

适用:手续费池、渠道归集、平台总账这类”可容忍秒级延迟”的账户。

代价

4.4 事件溯源(Event Sourcing)

思路:账户余额不是”现值”,而是”从创建到现在所有事件的累加”。写入就是 append 一条事件(几乎无锁),余额是一个视图(可物化)。

events: (account_id, seq, delta, ts, event_id)
  PK: (account_id, seq)
  写:INSERT, 按 account_id 自然分散
  读余额:SUM(delta) WHERE account_id=...;或物化视图 / snapshot + 增量

优点

缺点

TigerBeetle 内部模型近似于这个思路。Stripe Ledger 的 postings 表也有强烈 append-only 色彩。

4.5 异步双写与对账兜底

对超热账户,有些系统走”同步写分布账户 + 异步写热点账户”:

这是工程折中,必须配对账。否则”异步丢了几条”无人发现。


五、索引设计

5.1 账务核心索引模式

以上篇的 postings 表为例:

CREATE TABLE postings (
  posting_id       BIGINT PRIMARY KEY,
  entry_id         BIGINT NOT NULL,
  account_id       BIGINT NOT NULL,
  direction        SMALLINT NOT NULL, -- 1 借 / -1 贷
  amount           NUMERIC(38, 4) NOT NULL CHECK (amount > 0),
  currency         CHAR(3) NOT NULL,
  effective_time   TIMESTAMPTZ NOT NULL,
  created_time     TIMESTAMPTZ NOT NULL DEFAULT now(),
  business_type    SMALLINT NOT NULL,
  business_id      BIGINT NOT NULL
);

最关键索引

-- 账户流水查询(最高频)
CREATE INDEX idx_postings_account_time
  ON postings (account_id, effective_time DESC)
  INCLUDE (direction, amount, currency, entry_id, business_id);

-- entry 聚合(对账)
CREATE INDEX idx_postings_entry ON postings (entry_id);

-- 业务回溯
CREATE INDEX idx_postings_business ON postings (business_type, business_id);

几个设计要点:

  1. (account_id, effective_time DESC):账户明细倒序是最频繁的查询模式(“我最近 20 笔”),DESC 索引避免排序;
  2. INCLUDE 覆盖索引(PostgreSQL 11+、SQL Server、MySQL 8.0 generated columns 替代):让热查询在索引内完成,不回表;
  3. entry_id 索引:用于”一笔业务的所有借贷”聚合,对账必用;
  4. 业务回溯索引:风控、客服从业务 ID 反查分录。

5.2 Partial Index / Filtered Index

PostgreSQL、SQL Server 支持 partial index,MySQL 目前只能通过生成列近似。典型场景:

-- 只对未入账的、待处理的分录建索引(占比小)
CREATE INDEX idx_postings_pending ON postings (created_time)
  WHERE status = 'PENDING';

-- 大额分录专用索引(风控监控)
CREATE INDEX idx_postings_large ON postings (effective_time, account_id)
  WHERE amount >= 1000000;

Partial index 的优势:索引变小、更新代价低、大账户的冷数据不污染索引。

5.3 时间分区 + 本地索引

当表达到十亿级,分区变成必须。PostgreSQL 声明式分区:

CREATE TABLE postings (...) PARTITION BY RANGE (effective_time);
CREATE TABLE postings_2026_04 PARTITION OF postings
  FOR VALUES FROM ('2026-04-01') TO ('2026-05-01');
CREATE INDEX ON postings_2026_04 (account_id, effective_time DESC);

要点

5.4 MySQL / TiDB / OceanBase 的差异

5.5 索引反模式


六、冷热分层与归档

6.1 三层数据分层模型

┌─────────────────┐
│  热层(Hot)     │  最近 1–2 年   OLTP 主库(OB/TiDB/PG)
│  全索引、事务    │
├─────────────────┤
│  温层(Warm)    │  2–7 年       列存副本 + 只读副本(TiFlash/OB 列存/PG 归档分区)
│  报表、对账、审计│
├─────────────────┤
│  冷层(Cold)    │  7–30 年      对象存储 + Iceberg + Parquet(S3/OSS)
│  WORM、审计取证  │
└─────────────────┘

6.2 热层:Online

6.3 温层:Near-line

6.4 冷层:Archive

6.5 归档迁移流程

flowchart LR
  A[OLTP 主库] -->|CDC/逻辑复制| B[温层列存]
  A -->|分区 DETACH| C[归档区]
  B -->|ETL 按月| D[Iceberg + Parquet<br/>S3 Object Lock]
  D -->|Trino/Spark| E[审计/取证/报表]
  B -->|只读副本| E

关键点

  1. 归档迁移是按分区粒度做的,不要按行做(代价差 1000 倍);
  2. 迁移完成后,冷层要有校验:行数、SUM(amount)、MAX(effective_time) 三项对齐;
  3. 冷层数据任何变更必须通过”红冲 + 新分录”体现,从不修改历史 Parquet 文件;
  4. 审计团队对冷层的访问走独立权限和只读通道。

6.6 PostgreSQL 归档的实战细节

-- 归档时先 detach 分区
ALTER TABLE postings DETACH PARTITION postings_2020_01 CONCURRENTLY;

-- 导出为 Parquet(COPY + 外部工具 / pg_parquet)
COPY postings_2020_01 TO PROGRAM 'aws s3 cp - s3://archive/postings/year=2020/month=01/data.parquet'
  WITH (FORMAT parquet);

-- 校验无误后 DROP
DROP TABLE postings_2020_01;

实务上建议用工具:


七、并发控制

7.1 MVCC 基础

PostgreSQL、MySQL InnoDB、Oracle、OceanBase、TiDB 都实现了 MVCC:读不阻塞写、写不阻塞读。账务读查询(余额、明细)几乎都在快照上跑,不持锁。

要点:

7.2 扣款路径:悲观 vs 乐观

悲观(SELECT FOR UPDATE)

BEGIN;
SELECT balance FROM accounts WHERE account_id = ? FOR UPDATE;
-- 业务校验 balance >= amount
UPDATE accounts SET balance = balance - ? WHERE account_id = ?;
INSERT INTO postings (...) VALUES (...);
COMMIT;

优点:语义直观,并发正确;缺点:热点账户锁等待严重。

乐观(版本号 / CAS)

UPDATE accounts
SET balance = balance - ?, version = version + 1
WHERE account_id = ? AND version = ? AND balance >= ?;
-- affected_rows = 0 → 重试或失败

优点:无显式锁,并发高;缺点:冲突率高时全是重试浪费。

选择:分布账户(用户钱包)用悲观简单可靠;热点账户用分桶 + 乐观 CAS。

7.3 死锁避免

跨账户转账经典死锁:事务 A 锁账户 X 再锁 Y,事务 B 锁 Y 再锁 X。

防御

  1. 账户 ID 排序加锁:永远先锁 min(from, to) 再锁 max(from, to)
  2. 统一事务模板:账务服务层做这件事,业务方不接触 FOR UPDATE
  3. 超时短:MySQL innodb_lock_wait_timeout 设 3–5s;
  4. 监控死锁:MySQL SHOW ENGINE INNODB STATUS、PG pg_stat_activity + pg_locks

7.4 隔离级别陷阱

7.5 行级锁热点

即便有悲观锁,同一行的高并发更新是逃不掉的。应对就是前面第四节的热点方案——分桶、批量合并、事件溯源

7.6 分布式事务

下一篇《幂等、事务与一致性》会专门展开。


八、压测与容量规划

真实数字不要乱编,但几个工业常识区间可以参考:

重要TPC-C / TPC-E 是合成负载,和真实账务差异不小。上生产前必须用自己的 业务流量回放 做压测:

  1. 从生产采样最近 7 天流水;
  2. 按账户 ID 重放(保证热点账户比例正确);
  3. 包含读写比(账务侧典型 7:3,一次写配几次流水读);
  4. 跨分片比例不能丢:典型 5%–15% 的事务跨分片;
  5. 灰度切流:10% → 30% → 100%,每步有回退开关。

容量规划的一个经验公式:

峰值 TPS ≈ 日交易量 / 86400 * 峰谷比(3–10)
热点账户 QPS ≈ 峰值 TPS * 热点账户参与率(0.5–1.0)
单库上限 ≈ 单机 TPS * 0.6(保留 40% 冗余)
分片数 ≥ 峰值 TPS / 单库上限

九、数据完整性:让数据库帮你兜底

9.1 Check 约束

ALTER TABLE postings
  ADD CONSTRAINT chk_amount_positive CHECK (amount > 0),
  ADD CONSTRAINT chk_direction CHECK (direction IN (-1, 1)),
  ADD CONSTRAINT chk_currency_iso CHECK (currency ~ '^[A-Z]{3}$');

ALTER TABLE accounts
  ADD CONSTRAINT chk_balance_nonneg
    CHECK (balance >= 0 OR allow_negative = TRUE);

9.2 余额守恒约束

复式记账的最强约束:每一笔 entry,借方合计 = 贷方合计。可以用触发器或延迟约束:

-- PostgreSQL 延迟约束示例
CREATE OR REPLACE FUNCTION check_entry_balanced(eid BIGINT) RETURNS VOID AS $$
DECLARE net NUMERIC;
BEGIN
  SELECT COALESCE(SUM(direction * amount), 0) INTO net
  FROM postings WHERE entry_id = eid;
  IF net <> 0 THEN
    RAISE EXCEPTION 'Entry % not balanced: %', eid, net;
  END IF;
END;
$$ LANGUAGE plpgsql;

通过事务级触发器(或在服务层强制)保证每个 entry 提交前守恒。

9.3 外键与事件日志

支付事件 → 分录的映射通过 business_type + business_id 字段建立软外键(真正的外键跨表跨库难)。每一笔分录都能回到业务事件是审计的基石。

9.4 生成列与物化视图


十、审计、WORM 与哈希链

十.1 Append-Only 是底线

账务表必须禁止 UPDATE / DELETE(余额表例外,但余额是物化,可以重算):

十.2 数据库内审计日志

审计日志要独立存储(不要和业务同库),保留与账务一致的年限。

十.3 哈希链 / Merkle 日志

对高合规要求(证券、跨境、数字资产)系统,除了 append-only 之外,还要能对外证明”这段历史没被偷改过”:

hash_i = H(posting_i || hash_{i-1})

每日终结时把 hash_N 写入独立存储(公证、区块链、OSS WORM)。任何历史数据被改过,重算哈希会对不上。

工程实现:

10.4 BTG / Before-The-Gate

“事件进账务之前的门”。任何要写账务的请求必须先过 BTG 记录:

BTG 本身也是 append-only + 哈希链,保护”账务请求”这一层。


十一、真实案例演进

11.1 蚂蚁集团:从 MySQL 分库分表到 OceanBase

公开资料(蚂蚁技术白皮书、阿里云栖大会演讲)显示的演进:

关键工程经验:

  1. 账务服务化:业务不直接操作数据库,走”账务中心”服务;
  2. 单元化:同一用户的账户、订单、分录在同一单元;跨单元弹性切换;
  3. 分布式事务 GTS:上层统一调用,底层 2PC + 时钟;
  4. 三地五中心:RPO=0、RTO 分钟级;
  5. 对账是工程的一半:任何两条链路之间日终对账是硬要求。

11.2 PayPal:Couchbase + Oracle

PayPal 公开分享过账务架构:

启发:不是所有场景都要”一个数据库解决所有”。热点读可以出库,主账本保守稳妥。

11.3 Stripe:自建 Ledger

Stripe 工程博客(“Designing robust and predictable APIs with idempotency”、“Online migrations at scale”)披露:

11.4 Square / Block:MySQL 分库 + 自研 Subledger

公开演讲(QCon、SREcon)描述:

11.5 传统银行:Oracle / DB2 + 分布式改造

中国四大行、股份行在过去十年普遍走”核心系统分布式改造”路线:

监管侧信通院《分布式数据库发展报告》、银保监会《金融机构信息科技外包风险管理办法》为背景推动力。


十二、部署架构图

一张标准的”两地三中心 + 异地异步 + 冷归档”账务集群:

账务数据库部署架构(两地三中心 + 异地异步 + 冷归档)

同城机房 A(主)

Leader shard 0..N/3

Follower read-only

Sharding Proxy / SQL Gateway ShardingSphere / TiDB Server / OBProxy

Ledger Service(账务服务层) 复式约束 / 幂等 / 热点拆解

BTG: ledger_requests(哈希链)

同城机房 B(同步副本)

Follower Paxos/Raft

Follower read-only

Standby Proxy 健康检查 + 秒级切主

Ledger Service(热备) 单元化容灾

TiFlash / OB 列存(温层)

同城机房 C(见证节点 / Arbiter)

Paxos Voter(只投票不存数据) 避免双机房脑裂

监控 / 审计 / 配置中心 Prometheus · ELK · etcd

对账 / 报表 走温层 / 冷层 Trino · Spark · Flink Doris / StarRocks

sync vote

异地机房(异步复制 · 灾备)

异地副本集 CDC + 逻辑复制 RPO ≤ 秒 · RTO ≤ 分钟

异地 Ledger Service 只读 → 切主能力 演练季度一次

异地监控 / 对账 与主中心独立告警

冷归档(7–30 年 · WORM)

S3/OSS + Object Lock Iceberg + Parquet 哈希链 + 第三方存证

async CDC

ETL 归档

部署约束: · 同城三机房(A/B/C)Paxos/Raft 多数派同步,A+B 任一机房全损不丢数据; · 同城 RPO=0,同城单机房故障 RTO 秒级;异地机房异步复制,RPO 秒级 RTO 分钟级(用于极端灾难); · Sharding Proxy / Ledger Service 按单元化部署,路由表同步在配置中心(etcd / 配置平台); · 冷归档走对象存储 WORM,哈希链第三方存证(联盟链 / 公证机构); · 见证机房部署见证节点 + 监控 + 审计中心,与业务链路物理隔离。

十三、工程坑点

  1. 分片键拍脑袋:上线才发现 80% 流量集中在 20% 分片;
  2. 跨分片事务滥用:业务随手写跨库 join,性能塌方;
  3. 自增主键:分布式下热点 tail write;改 Snowflake / AUTO_RANDOM;
  4. CHAR vs VARCHAR vs NUMERIC 不统一:金额精度丢失灾难;
  5. 长事务:批处理跑了 30 分钟阻塞 VACUUM;
  6. 索引失效WHERE DATE(ts)WHERE ts::DATE、函数包裹;
  7. 只建主库索引:从库回放慢导致复制延迟;
  8. 在线加索引不 CONCURRENTLY / 不 ALGORITHM=INPLACE:锁表几分钟业务全挂;
  9. FOR UPDATE NOWAIT 没兜底:重试风暴;
  10. 余额物化表不对账:长期小差错滚成大事故;
  11. DDL 变更没评审:删字段、改类型直接上生产;
  12. 备份恢复没演练:真出事才发现备份没校验;
  13. 审计日志和业务同库:一起坏一起丢;
  14. 冷归档没有校验:迁移程序 bug,几百万行静悄悄丢了;
  15. 依赖云厂商单一区域:跨 region 切换演练缺失。

十四、选型与落地清单

14.1 选型建议表

场景 日分录规模 推荐
初创支付 / 单一国家 < 1 亿 PostgreSQL + 分区 + 同步副本
高速增长互联网金融 1–10 亿 TiDB 或 MySQL 分库分表
大型支付 / 银行核心 10 亿+ OceanBase / 国产金融级数据库
全球化跨境支付 跨境 CockroachDB / 多集群 + 异步
加密 / 交易所内账 高并发 TigerBeetle + 关系型主账本
存量传统银行 稳定 Oracle + 分布式改造

14.2 落地 Checklist


十五、本文小结

账务数据库选型和设计的决策链条是这样的:

  1. SLA 先行:RPO=0、RTO<1min、保留年限决定副本协议与存储分层;
  2. 模型锁定:复式记账的 append-only 语义是底线;
  3. 数据库挑选:看规模、看生态、看案例;PostgreSQL 进、MySQL 分、OB/TiDB 扛大规模、TigerBeetle 特种;
  4. 分片维度:以 user_id / merchant_id 为主,时间为辅,尽量让事务本地化;
  5. 热点账户:分桶 + 合并 + 事件溯源,几乎一定要做;
  6. 索引(account_id, time DESC) + 覆盖索引 + partial + 分区本地;
  7. 并发:分布账户用悲观锁,热点账户用分桶 + 乐观 CAS;
  8. 分层:热 OLTP + 温列存 + 冷 Iceberg WORM;
  9. 审计:append-only + DB audit + 哈希链 + 第三方存证;
  10. 演练:切换、恢复、归档、红冲每季度跑一次。

下一篇我们进入幂等、事务与一致性,把”一笔请求进到账务服务”的全链路幂等、SAGA、TCC、对账补偿讲透。


参考资料


上一篇《复式记账工程化:科目、分录、余额、对账》

下一篇《幂等、事务与一致性:SAGA、TCC、对账补偿》

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-04-22 · architecture / fintech

【金融科技工程】复式记账工程化:科目、分录、余额、对账

把 500 年历史的复式记账翻译成工程师可以落地的数据模型、SQL 表结构与余额计算策略,覆盖充值、下单、退款、分润、红包、多币种与冲销的真实场景,并对比 TigerBeetle、beancount、Ledger CLI、Square LedgerDB、Stripe Ledger 等开源与工业实现。

2026-04-22 · architecture / fintech

【金融科技工程】金融级可靠性:两地三中心、单元化、RPO/RTO、灰度

金融系统的可用性不是 SLA 表里的一个数字,而是人民银行、银保监、GB/T 20988 六级灾备、SOX、FFIEC 这些监管框架共同压出来的工程形态。本文从 RTO/RPO 的定义出发,走过单机→主备→同城双活→两地三中心→三地五中心→单元化(LDC/Set)的架构演进,拆解异地多活的数据同步、冲突处理与流量调度,配套混沌工程、全链路压测、应急预案与复盘文化,最后用 Go 写一个可运行的多活流量切换骨架。结合光大 8·16 乌龙指、2021 AWS us-east-1 故障、2020 工行手机银行故障、蚂蚁春节红包等公开案例展开。

2026-04-22 · architecture / fintech

【金融科技工程】金融科技工程全景:从支付到交易所的系统分类与读图

金融科技(FinTech)不是普通后端加一张账户表。钱的原子性、监管的硬边界、一个小数点的代价,把这个领域推进到工程强度最高的那一档。本文是【金融科技工程】25 篇的总目录与阅读地图:先交代为什么它比一般业务系统更难,再给出对账体、支付体、交易体、风控合规体四维分类,把后续 24 篇挂到骨架上,最后给出一份绿地项目的落地顺序建议。


By .