3. 高并发系统基础
在进入金融账务系统的代码实现之前,必须先建立一套统一的性能语言。否则团队讨论“系统很慢”“要扛住大促”时,每个人脑子里的指标都不一样。本节把高并发领域最核心的概念一次讲清,并说明它们在账务场景中的特殊含义。
一、四个基础指标:并发、吞吐量、响应时间、QPS/TPS
并发(Concurrency)指系统在某一时刻同时处理的请求数量,它描述的是“同时存在多少件事在做”。吞吐量(Throughput)指单位时间内系统成功完成的请求数量,描述的是“做完多少件事”。响应时间(Response Time / Latency)指从请求发出到收到响应所经历的时间,通常关注平均值、P95、P99 等分位值。QPS 是每秒查询数,TPS 是每秒事务数,在账务系统中一个 TPS 往往对应一次完整的转账事务,包含多条 SQL 与一次记账。
这四个指标并非独立,而是相互制约。根据利特尔法则(Little's Law):并发数 ≈ 吞吐量 × 平均响应时间。这意味着在并发固定的情况下,响应时间越长,吞吐量越低。很多团队只盯着 QPS 数字,却忽略了 P99 已经恶化到数秒,用户体验和资金安全其实已经受损。
账务系统看指标的顺序建议是:先看 P99 响应时间是否达标,再看 TPS 是否满足业务峰值,最后才看平均 QPS。因为金融场景中,一笔慢请求可能意味着锁等待、死锁或对账不平,其危害远大于吞吐量下降。
二、CAP 与 BASE:分布式账务的理论底座
CAP 定理指出,在分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)三者不可同时完全满足。由于网络分区在真实环境中不可避免,P 必须保留,因此实际选择是在 C 与 A 之间取舍。
金融账务系统通常优先选择 CP:在分区发生时宁可拒绝部分请求,也不能让两个节点各自记账导致资金错乱。但纯粹的 CP 会带来可用性下降,于是引入 BASE 理论作为补充:Basically Available(基本可用)、Soft state(软状态)、Eventually consistent(最终一致)。
| 理论 | 核心主张 | 账务系统落地方式 |
|---|---|---|
| CAP | 分区时在一致性与可用性间取舍 | 核心记账走 CP,查询走 AP |
| BASE | 基本可用、软状态、最终一致 | 异步对账、补偿事务、消息最终一致 |
| ACID | 强一致、隔离、持久 | 单库单笔事务内保证 |
实践中常见的组合是:核心扣款与入账在单库内用 ACID 保证强一致,跨库跨服务用 BASE 做最终一致。例如转账时先冻结付款方余额,再异步通知收款方入账,中间通过可靠消息与对账任务兜底。
三、水平扩展:从单机到集群的扩容路径
当单机 TPS 达到瓶颈,最直接的思路是垂直扩展(升级 CPU、内存、SSD),但它有物理上限且成本陡增。真正支撑高并发的是水平扩展:增加机器数量,把流量分散到多个节点。
水平扩展要解决三个问题:无状态化、数据分片、请求路由。应用层尽量做成无状态,会话与上下文外置到 Redis;数据库按用户 ID 或账户 ID 分库分表;网关或分片中间件根据分片键把请求路由到对应节点。
# 分片路由示例(按账户 ID 取模)
shard = account_id % 16
db = "account_db_" + shard
# 同一账户的扣款、入账、查询必须命中同一分片
# 否则跨分片事务会退化为分布式事务,成本极高
水平扩展最大的误区是“加机器就能解决一切”。如果存在热点账户(如平台大商户),所有请求仍会打到同一分片,加再多机器也无用。热点问题必须靠账户拆分、缓冲记账或异步合并来解决,而不是靠扩容。
四、案例与复盘:一次大促的指标推演
假设某支付平台大促峰值 TPS 为 8000,平均响应时间要求 P99 小于 200ms。按利特尔法则,所需并发约为 8000 × 0.2 = 1600。若单节点可稳定支撑 400 并发,则至少需要 4 个应用节点,再考虑 1.5 倍冗余,实际部署 6 个节点。
数据库侧,若单分片可写 1500 TPS,则 8000 TPS 需要至少 6 个分片,考虑增长预留到 8 个分片。复盘时常见问题包括:只压测了平均响应时间而忽略 P99;分片键选择不当导致数据倾斜;异步对账任务在大促期间积压,最终一致性延迟超出业务容忍范围。
建议在项目初期就建立一张“容量与指标对照表”,把 TPS、P99、并发、分片数、节点数写在一起。每次架构调整后更新,避免拍脑袋扩容。