当前位置: 首页 > news >正文

MySQL缓存策略

在开始本期讲解之前,我们需要明确最重要的一个问题

MySQL缓存方案缓存的是什么?

缓存的时用户定义的热点数据,用户直接从缓存获取热点数据,降低读写压力。

这里要注意,缓存的是用户定义的热点数据,所以大家要明白MySQL本身的缓存区和这里缓存策略的缓存区是两码事。

我们用什么来缓存?

这里采用的是redis来缓存MySQL的数据,大家都知道redis是内存数据库,读取数据的速度比在磁盘读取快得多。大概是十万倍。

当然我们也不是盲目的什么时候都用缓存方案,在读的需求远远大于写的需求时我们用缓存方案,因为如果写是主要的,我们这个缓存区就没啥大用了。

同时MySQL作为项目主要的数据库,便于统计分析,redis作为辅助数据库,存放热点数据。

提升MySQL性能的方法

读写分离

主从复制

在实现读写分离之前需要先实现主从复制

1. 主库更新事件 DML 操作( update 、 insert 、 delete ) 通过 io-thread 写到 binlog;

2. 从库请求读取 binlog,通过 io-thread 写入从库本地 relay-log(中继日志);

3. 从库通过 sql-thread 读取 relay-log,并把更新事件在从库中重放(replay)一遍;

读写分离

读操作从从数据库中读,写操作只写主数据库。但是在同步过程中难免导致数据不一致,能保证最终一致性。

缓存方案的解决

没有缓冲层之前,我们对数据的读写都是基于 mysql;所以不存在同步问题;这句话也不是必然, 比如读写分离就存在同步问题(数据一致性问题); 引入缓冲层后,我们对数据的获取需要分别操作缓存数据库和 mysql;那么这个时候数据可能下面几个状态:

1. mysql 有,缓存无

2. mysql 无,缓存有

3. 都有,但数据不一致

4. 都有,数据一致

5. 都没有

显然我们可以接受4和5,因为都是正常情况。那么在其他情况下我们还能接收那个呢。

首先明确一点:我们获取数据的主要依据是 mysql,只需要将 mysql 的数据正确同步到缓存数据库 就可以了;同理,缓存有,mysql 没有,这比较危险,此时我们可以认为该数据为脏数据;所以我 们需要在同步策略中避免该情况发生;同时可能存在 mysql 和缓存都有数据,但是数据不一致,这种也需要在同步策略中避免。

具体热点数据读写策略

读策略很简单,先从redis里读,如果没有就从MySQL里读。

主要的分歧在写里

以安全为主

写流程:先删除缓存,再写 mysql,后面数据同步交由 go-mysql-transfer 等中间件处理;(将问题 3 转化成 1) 先删除缓存,为了避免其他服务读取旧的数据;也是告知系统这个数据已经不是最新,建议从 mysql 获取数据; 但是对于服务 A 而言,写入 mysql 后,接着读操作必须要能读到最新的数据。

但是大家要明白,我们设置缓存方案的主要目的就是提升效率,现在却为了数据安全降低了效率,所以这种方案是很少使用的,除非是读远大于写的情况下才使用。

以效率为主

写流程:先写缓存,并设置过期时间(如 200ms),再写 mysql,后面数据同步交由其他中间件 处理; 这里设置的过期时间是预估时间,大致上是 mysql 到缓存同步的时间; 在写的过程中如果 mysql 停止服务,或数据没写入 mysql,则 200 ms 内提供了脏数据服务;但仅 仅只有 200ms 的数据错乱;

这里设置的过期时间其实就是与MySQL网络传输时间+MySQL处理事件+MySQL同步到redis的时间

安全问题就是在这200ms中可能提供脏数据,但几率很小了。

同步方案

go-mysql-transfer

这种方案其实是通过伪装从数据库来将MySQL同步到redis的方案

1.首先修改MySQL配置文件 my.ini,使主数据库和从数据库的id不同

2.修改app.yml配置端口信息以及配置redis地址

3.配置热点数据的具体信息

4.写lua同步逻辑

触发器+UDF

这种方案其实是在MySQL中使用c++的函数实现同步的,但是这种方案不具备事务,不能回滚,使用较少。

缓存方案的故障及解决

缓存穿透

问题:数据在缓存和mysql都无,一直读取不存在的数据,造成mysql访问性能急剧下降

解决:

1.缓存设置<key,nil>这样给读取一个空数据

2.部署布隆过滤器,这个过滤器可以先检查redis和mysql里是否有这个数据,有就读没有直接返回

缓存击穿

问题:缓存无,mysql有,大量的并发连接请求造成mysql访问性能急剧下降

解决:

1.过热数据不过期:在mysql同步到redis的数据也会设置过期时间,面对缓存击穿可以设置过热数据不过期,这样就访问redis即可

2.分布式锁,请求数据的时候获取锁,若获取成功,则操作后释放锁;若获取失败,则休眠一段时间(200ms) 再去获取,当获取成功,操作后释放锁

缓存雪崩

问题:表示一段时间内,缓存集中失效(redis 无, mysql 有),导致请求全部走 mysql,有可能搞垮数 据库,使整个服务失效。

解决:

1.如果因为设置了相同的过期时间,造成缓存集中失效; 设置随机过期值或者其他机制错开失效时间;

2.如果因为缓存数据库宕机,造成所有数据涌向 mysql; 采用高可用的集群方案,如哨兵模式、cluster 模式;

3.如果因为系统重启的时候,造成缓存数据消失; 重启时间短,redis 开启持久化(过期信息也会持久化)就行了; 重启时间长提前将热数据导 入 redis 当中。

更多资料在:https://github.com/0voice查询

http://www.dtcms.com/a/330818.html

相关文章:

  • 计算机视觉--opencv(代码详细教程)(二)
  • iPhone 17 系列发布会定于 9 月 9 日举行-邀请函或 9 月 2 日发出
  • MCP Server搭建
  • OpenCV中对图像进行平滑处理的4种方式
  • 微美全息(WIMI.US)借区块链与聚类技术,开启物联网去中心化安全架构新纪元
  • 我的第一个开源项目-jenkins集成k8s项目
  • .Net4.0 WPF中实现下拉框搜索效果
  • RabbitMQ高级特性——消息确认、持久性、发送方确认、重试
  • 解锁Prompt秘籍:框架、技巧与指标全解析
  • 基于Django的福建省旅游数据分析与可视化系统【城市可换】
  • 《量子雷达》第4章 量子雷达的检测与估计 预习2025.8.14
  • 【51单片机学习】定时器、串口、LED点阵屏、DS1302实时时钟、蜂鸣器
  • 量子人工智能
  • Python训练营打卡Day32-神经网络的训练
  • Swift 数据类型全景解析(基础到高阶)
  • 按位运算的枚举在 Swift 里如何实现?
  • 《吃透 C++ 类和对象(中):拷贝构造函数与赋值运算符重载深度解析》
  • 【数据分享】2014-2023年长江流域 (0.05度)5.5km分辨率的每小时日光诱导叶绿素荧光SIF数据
  • Pytest自动化测试框架总结
  • iOS性能监控新方法多版本对比与趋势分析实战指南
  • C++进阶:特殊类
  • 手写MyBatis第16弹:泛型魔法应用:MyBatis如何破解List的运行时类型
  • 笔试——Day38
  • 根据图片远程地址复制图片内容,可以在富文本、word等文本里粘贴
  • word——删除最后一页空白页
  • Exif.js获取手机拍摄照片的经纬度
  • 【网络】TCP/UDP总结复盘
  • Unity人形角色IK优化指南
  • AI搜索优化专家孟庆涛:以技术温度重构“人机信息对话”新范式
  • 手机实时提取SIM卡打电话的信令声音-当前现状与思考