对于分布式、高并发系统的开发,其核心思路确实可以归纳为"逐层治理、降级兜底"。我们从数据层 、缓存层 、业务层 和流量层四个维度来重新构建整个知识体系。
1. 数据层(数据库):守住数据的最终防线
:慢SQL分析 -> 索引优化 -> SQL改写。在此基础上,补充两个关键点:
-
执行计划是依据 :使用
EXPLAIN分析时,重点关注type(至少要达到range或ref)、rows(扫描行数)和Extra(是否出现Using filesort或Using temporary)。 -
索引优化的细节:
-
遵循联合索引的最左前缀匹配原则,避免索引失效。
-
应对深分页 问题(如
limit 100000, 10),采用延迟关联 (先查主键ID)或游标查询 (基于排序字段的where > 上次最大值)。
-
-
SQL改造的边界 :当单表SQL无法优化时,进行SQL拆分,将复杂联表查询拆分为多次单表查询,在应用层做关联,以解耦数据库压力。
2. 缓存层(Redis/本地缓存):扛住绝大部分读压力
引入缓存(Redis + 本地缓存)是提升性能的关键,但必须防范三大经典问题及对应的兜底方案:
-
缓存穿透(查不存在的数据):
- 兜底 :缓存空对象(
null值)或使用布隆过滤器拦截。
- 兜底 :缓存空对象(
-
缓存击穿(热点Key失效):
- 兜底 :使用互斥锁(如Redis的SETNX),只允许一个线程重建缓存,其他线程等待或重试。
-
缓存雪崩(大量Key同时失效):
- 兜底 :给缓存过期时间设置随机偏移量(如基础时间 + 随机秒数),避免集体失效。
-
数据一致性 :更新DB后,采用删除缓存(而非更新缓存)的策略,等待下一次查询时再重建,风险更低。
3. 业务层(并发与一致性):处理写的冲突与幂等
高并发下的写操作,核心目标是保证数据最终一致性和幂等性。
-
并发控制:
-
优先使用乐观锁(版本号) 控制并发更新(如
update set version = version + 1 where id = ? and version = ?),适合读多写少。 -
当乐观锁冲突严重或需要强一致性时,再考虑分布式锁 (如Redisson,需关注其WatchDog自动续期机制)。
-
-
幂等性保障:
-
DB层兜底 :利用数据库唯一索引作为最终防线,防止数据重复写入。
-
应用层处理 :采用**"先尝试插入,后捕获
DuplicateKeyException"** 的模式,消除先查后插的并发时间窗口。 -
ID生成 :分库分表下,必须使用分布式ID(如雪花算法),避免依赖数据库自增ID。
-
4. 流量与解耦层(MQ与限流):削峰填谷,保护系统
-
异步解耦:
-
明确业务边界 :核心链路(如扣库存)同步 ,非核心链路(如发积分、日志)异步。
-
使用RocketMQ事务消息 来保证核心事务与非核心操作的最终一致性 (需理解其状态回查机制)。
-
-
流量控制:
- 引入限流(如Sentinel),防止突发流量压垮系统,保护自身及下游依赖。
💎 总结:一个核心原则
所有上述手段,归根结底都围绕着一个核心原则:让专业的人做专业的事,层层设防,并准备好Plan B。
-
数据库 负责通过索引和唯一约束,保证绝对的准确与唯一。
-
缓存 负责通过多级存储和防击穿策略,保证极高的读取效率。
-
业务代码 负责通过锁和幂等设计,协调并发的写操作。
-
消息队列 负责通过异步和削峰,实现松耦合的系统生态。
这套体系,已经可以覆盖绝大多数分布式高并发场景的挑战。它并非简单的技术堆砌,而是一个需要根据业务场景不断权衡(如:强一致性vs.最终一致性、性能vs.可靠性)的动态决策过程。