高并发系统设计
作为后端研发,工作中往往经常遇到一个关键词就是“高并发”。什么是高并发,什么范围内的traffic可以被称为高并发。如果说建立这样的概念,对于系统设计中线程竞争应对措施,数据库选择,与资源分配的 trade-off 会有明显的帮助。
阶段1:低并发(<100 QPS)
阶段2:中并发(1k-10k QPS)开始出现内部竞争
阶段3:高并发(10k-100k QPS)竞争成为主要瓶颈
阶段4:超高并发(>100k QPS)需要系统级重构
竞争的资源包括:
CPU核心、内存、数据库连接、锁、网络带宽
GenAI DB-connection simulation
阶段1:低并发(<100 QPS)
这个阶段一般Server没有什么性能瓶颈,主要需要实现应用的关键功能的业务逻辑。
阶段2:中并发(1k-10k QPS)开始出现内部竞争
在中等并发程度下需要开始考虑锁的设计,是否需要数据库连接池实现复用,数据库和服务器是否能支持负载,扩容之后有哪些一致性的问题。
例如 MySQL 单机数据库可负载~500 TPS 和 ~10000 QPS,需要考虑事务设计,锁的设计来保证数据的准确。
User A: READ(5) -----> WRITE(5-1=4)
User B: READ(5) --------------------> WRITE(5-1=4)
Final value: 4 ❌
Expected: 3 ✓
阶段3:高并发(10k-100k QPS)竞争成为主要瓶颈
在高并发情况下,数据库锁有可能会成为性能瓶颈。
设计案例:库存抢购,10万并发用户,页面显示剩余库存量。
在这个案例中写并发程度也很高,单行数据并发写入的时候会导致:
数据库连接池 saturated,如果使用的是乐观锁,会因为CAS空转导致时延增加。
常见解决方案:
1. 使用库存批次做 Redis 分片
对库存数据进行切片,提前 load 到 Redis 节点,当节点中库存不够时,再从数据库读取,这样可以显著减少数据库的负载。
如何同步数据库:
- 每一次扣减库存之后存入流水表,最后汇总计算剩余库存。
- 或者 Redis 定期快照,异步批量更新数据库。
设置 Reconcilation 任务,定期比对库存。
2. Redis 分布式锁
Redis 命令处理层仍是单线程,因此可以自然的形成锁。Redis 单个节点可以支撑 100,000 to 200,000 的QPS。
3. MySQL 分库分表
订单的数据表格可以根据用户ID切片:order1, order2; order3;采用多主多从的结构横向扩展写并发的负载,根据原先的 assumption, 大概需要10台独立的mysql主机支撑10万QPS的并发。
阶段4:超高并发(>100k QPS)需要系统级重构
异步化:引入消息队列(Kafka 等)将写请求削峰,秒杀请求先入队,异步落库
无状态水平扩展:应用层完全无状态,配合负载均衡横向扩容
最终一致性:放弃强一致,用补偿机制保证数据最终正确
Performance 观测
在应对上升的traffic的同时,有哪些方法来判断可能出现性能瓶颈:
四大黄金指标
Google 在《SRE:Google运维解密》中提出的分布式系统监控核心原则 。这四个指标是衡量系统健康状况的最佳实践
- Latency(延迟)响应请求的时间
- Traffic(流量)接收到的总请求数 QPS/RPS/TPS
- Errors(错误)请求失败的数量 (5xx, 4xx error rates)
- Saturation(饱和度)服务“满”的程度 a system or resource is being utilized or overloaded
Saturation异常的表现:CPU使用率持续高于80%;缓冲池命中率低、大量磁盘I/O;I/O等待时间长、写入堆积;网络吞吐量接近带宽上限、连接延迟高;连接数达到上限、线程创建延迟或内存耗尽。
