4.2.4 MYSQL的缓存策略
文章目录
- 4.2.4 MYSQL的缓存策略
- 1. MYSQL缓存方案用来干什么
- 2. 缓存相关知识
- 1. mysql主从复制
- 2. 为什么需要缓冲层
- 3. 还有哪些类型数据库
- 3. 那些方式会提升MYSQL读写性能
- 1. mysql读写分离
- 2. 连接池
- 3. 异步连接
- 4. 缓存方案是怎么解决的
- 1. redis和MYSQL一致性状态分析
- 1. 流程:先读缓存,有直接返回(不需要访问mysql),没有,访问mysql,有返回并同步到缓存,没有就是整个系统都木有
- 2. 写策略:
- 2. 同步方案
- 5. 缓存方案问题以及解决
- 1. 缓存穿透
- 2. 缓存击穿
- 3. 缓存雪崩
- 6. 缓存方案的弊端
- 1. 不能处理多语句任务
- 2. redis不支持回滚
- 3. redis和mysql不一致问题
4.2.4 MYSQL的缓存策略
1. MYSQL缓存方案用来干什么
主要用于提高查询性能、减少磁盘 I/O 和 CPU 消耗,使得频繁访问的数据可以从内存中快速获取,从而大幅提升数据库响应速度
2. 缓存相关知识
MySQL 的缓存方案是指其在数据库运行过程中,使用内存缓存机制来优化查询性能、减少磁盘 I/O 和提升吞吐能力的一整套技术组合
1. mysql主从复制
MySQL 主从复制是指一个 主库(Master) 将数据的更新操作同步到一个或多个 从库(Slave) 的机制。
工作流程(基于异步复制为例):
Client → 写操作 → Master(主库)↓ 产生 binlog(二进制日志)↓ 从库通过 I/O 线程读取 binlogSlave(从库) → SQL 线程重放 binlog → 数据同步
阶段 | 描述 |
---|---|
1. 主库记录 binlog | 所有写操作都会写入 binary log 日志 |
2. 从库 I/O 线程读取 binlog | 从库连接主库,读取 binlog 并保存为 relay log(中继日志) |
3. 从库 SQL 线程执行 relay log | 将 relay log 转为 SQL 在从库中执行,实现数据同步 |
2. 为什么需要缓冲层
缓冲层,本质上是指在系统和慢速设备(如磁盘)之间加一个高速中间存储区域(一般在内存),目的是提高系统整体性能和减少资源消耗
读多写少,单个主节点能支撑项目数据量;数据的主要依据是 mysql;但是磁盘 I/O 很慢
3. 还有哪些类型数据库
除了关系型数据库(Relational Database,简称 RDBMS,如 MySQL、PostgreSQL、Oracle 等)之外,还有以下几类非关系型数据库(NoSQL 数据库)和新兴数据库类型,它们各有特点、应用场景不同:
一、非关系型数据库(NoSQL)
-
键值型(Key-Value)数据库
结构:键 => 值(value 可为任意类型,如字符串、JSON、二进制等)
优点:超高性能、适合缓存、简单的数据模型
应用:缓存、会话管理、分布式存储
常见代表:
Redis(内存数据库,支持持久化)
Memcached(高性能但不支持持久化) -
文档型数据库
结构:存储类似 JSON 的文档结构,字段可以灵活变化
优点:灵活、适合快速开发、支持嵌套数据结构
应用:内容管理、社交平台、日志系统
常见代表:
MongoDB
CouchDB -
列族型(列式)数据库
结构:按列存储数据而非按行,适合处理大规模分析类数据
优点:高压缩率、高查询效率(适合 OLAP)
应用:大数据仓库、日志分析
常见代表:
Apache HBase(基于 Hadoop HDFS)
Cassandra
ClickHouse -
图数据库
结构:节点(Node)+ 边(Edge)+ 属性(Properties)
优点:擅长表达关系、关系计算快
应用:社交网络、推荐系统、知识图谱
常见代表:
Neo4j
JanusGraph
二、新型数据库类型
-
时序数据库(Time Series DB)
专门用于处理时间序列数据(指标监控、IoT、金融数据)
常见代表:InfluxDB、TimescaleDB -
多模型数据库
同时支持多种模型(文档 + 图 + 关系等)
常见代表:ArangoDB、OrientDB -
NewSQL
结合关系型数据库的事务与 NoSQL 的扩展性
常见代表:TiDB、CockroachDB
3. 那些方式会提升MYSQL读写性能
1. mysql读写分离
读写分离是指:主库处理写操作、从库处理读操作,实现负载均衡和高并发能力。结合主从复制,从库有与主库一致的数据,应用程序通过中间件或代码逻辑将写请求路由到主库,读请求路由到从库。
架构图示:
+-----------+| 应用层 |+-----------+/ \写操作 / \ 读操作+----+ +----+|主库| --> |从库|+----+ +----+
2. 连接池
数据库连接是“重量级资源”,频繁创建和关闭连接会耗费大量时间。连接池通过复用连接,大幅提升性能:
优点:
- 减少连接建立/销毁的时间开销
- 控制最大连接数,防止数据库过载
- 支持连接健康检查、空闲回收等机制
3. 异步连接
传统数据库操作是同步阻塞的,异步连接可以使应用非阻塞执行 SQL 查询,提升响应效率:
- 应用线程发出 SQL 后不等待数据库返回,而是立即执行其他逻辑
- 数据库结果准备好后,通过回调或事件通知处理
- 适合高并发场景,如 Web 服务、异步任务处理
4. 缓存方案是怎么解决的
1. redis和MYSQL一致性状态分析
状态编号 | MySQL 状态 | Redis 状态 | 问题 |
---|---|---|---|
状态1 | 有 | 无 | 缓存穿透,需从 DB 读取再写缓存 |
状态2 | 无 | 有 | 读取到脏数据,严重一致性问题 |
状态3 | 有 | 有(不一致) | 缓存未更新,读到旧数据,数据不一致 |
状态4 | 有 | 有(一致) | ✅ 正确状态 |
状态5 | 无 | 无 | ✅ 正确状态(比如刚初始化) |
我们只希望有4,5两种状态,所以关键在于**:避免状态2、3,修复状态1**。
1. 流程:先读缓存,有直接返回(不需要访问mysql),没有,访问mysql,有返回并同步到缓存,没有就是整个系统都木有
2. 写策略:
- 安全为主(强一致)策略:先删缓存,再写数据库
1. 删除 Redis 缓存(del key)
2. 更新 MySQL 数据
优点:可以保证缓存是旧的,不会读到脏数据缺点:可能会在并发场景下造成缓存击穿(刚删缓存就被读了)
- 效率为主(最终一致)策略:先写 DB,再异步更新缓存
1. 更新 MySQL 数据
2. 异步更新 Redis(如消息队列触发、延迟任务)
优点:效率更高,适合读多写少的场景缺点:存在数据瞬时不一致风险
前提是业务可容忍短时间的不一致
2. 同步方案
同步方案 | 描述 | 适用场景 |
---|---|---|
延迟双删 | 更新数据库后删缓存两次(间隔一段时间) | 强一致要求较高 |
消息队列同步 | DB 更新后写入 MQ,异步刷新缓存 | 写多、缓存更新频繁场景 |
订阅 binlog | 监听 MySQL binlog,变更时更新缓存 | 大型系统,使用 Canal/Debezium |
定时刷新 | 定时任务刷新缓存数据 | 缓存数据更新频率低场景 |
解释一下为什么要延迟双删:
线程A(查询请求) | 线程B(更新请求) |
---|---|
删除缓存(step 1) | |
读取缓存(发现没了) | |
从数据库读取旧数据 | |
更新数据库为新数据(step 2) | |
将旧数据写入 Redis(step 3) |
结果:Redis 又被写入了旧数据,造成数据不一致
5. 缓存方案问题以及解决
1. 缓存穿透
指查询一个数据库和缓存中都不存在的 key(比如恶意构造的 user_id=-1),每次请求都穿透缓存打到数据库,造成缓存形同虚设
解决方案:
- 布隆过滤器(推荐):拦截非法 key
- 空值缓存:将查询结果为 null 的 key 也存入 Redis,设置较短过期时间(如 1~5 min)
2. 缓存击穿
某个热点 key 过期瞬间,大量请求同时访问数据库,引发数据库压力骤增。此时可能造成数据库可能被击垮,出现服务雪崩。
解决方案:
- 互斥锁机制(分布式锁):只允许一个请求重建缓存,其他请求等待。
- 永不过期 + 异步更新:缓存不过期,后台定时刷新
- 逻辑过期:缓存结构中加时间戳,自主判断是否需要异步更新
3. 缓存雪崩
大量 key 在同一时间失效,导致请求同时访问数据库。造成数据库崩溃,系统短时间内无法恢复。
解决方案:
- 过期时间设置随机值(抖动):避免集中失效
- 热点数据预热:重启服务后预加载缓存
- 多级缓存:如本地缓存 + 分布式缓存
6. 缓存方案的弊端
1. 不能处理多语句任务
Redis 作为缓存系统,无法感知事务范围。例如涉及多表写入、回滚逻辑时,缓存不能自动同步状态
- 重要业务仍以数据库为主,一致性关键数据优先从数据库读取
2. redis不支持回滚
Redis 的写入是立刻生效的,不像数据库那样支持事务回滚(ACID),一旦写入 Redis,后续数据库失败,可能出现缓存脏写
- 采用「先删缓存,再更新数据库」的强一致策略
- 通过 MQ 异步补偿缓存更新
3. redis和mysql不一致问题
网络延迟、并发覆盖、先写缓存再写 DB 等操作顺序问题
- 延迟双删:先删缓存,再更新 DB,等待 DB 写入完成后再删缓存
- MQ 或 Canal 同步 binlog
- 增加缓存版本号机制(避免并发写入覆盖)