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

MySQL缓存策略

前言

        MySQL是大部分业务的铁打需求。而事实上,几乎所有业务的查询操作占比远远高于增删改操作,在这种读远大于写的情况下,MySQL的一些机制反而成了累赘。比如redolog落盘机制,我们每次读都要访问磁盘,访问量一大就会使系统整体性能下降。你可能会疑惑,MySQL不是有个Buffer Pool和Change Buffer吗。没错,内存的访问速度是磁盘访问速度的10万倍,速度上它以绝对的优势战胜了磁盘,并且LRU机制让它能够更新数据。但是!如果用户将在一个固定时间大量访问,LRU机制就是鸡肋,因为热点数据不会改变,而是要提前备好供访问。

        所以我们要使用缓存策略,将热点数据提前备好到内存,供某一时刻用户的大量访问。将MySQL用做统计与数据分析的主数据库,缓存数据库(如Redis)就用来助力,但是不会影响整体的可用性,也就是说缓存数据库可有可无。

b3c1f9b0896445b4af298d886321ee9e.png

        当然,提高MySQL访问性能的方法有很多,比如读写分离(类似MongoDB)、连接池等等。MySQL有binlog供主从复制,以备不时之需,读操作直接访问多个从数据库,写操作则访问主数据库,这样就达到读写分离的目的。由于异步复制的机制,主从数据库数据就有时差,从数据库的数据就不会是最新的,这时候就要考虑读一致性要求,有要求就没办法,必须读主数据库,这种方法实在性价比低。我们知道SQL语句只能一条条执行,所以我们可以使用多条连接并发执行。连接池就可以提供并发功能。但是要注意一个事务只能在一条连接执行,多条连接在MySQL中就有多个线程,会执行紊乱。

缓存方案

        我们以热点数据作为参照物,如果用户读的是热点数据,就读从数据库,如果是非热点数据,就读MySQL,可以设计一个热点数据表来供判断。考虑到将MySQL与Redis这两个进程组合成一个数据库,就要分析数据的一致性问题,值得注意的是:单看热点数据,MySQL没有Redis却有,这不符合MySQL作为主数据库的原则;热点数据一致数据不一致,那我要这个从数据库干鸡毛。

418b31c7f57f4170bf0f408f444642c8.png

        对于读,我们可以先读Redis,如果没有就去读MySQL,有就直接返回。MySQL也没有就返回读失败,有就将数据同步到Redis。

b400003fd3d943e881973c9e34910d51.png

        对于写,我们一般在安全与效率之间做权衡。如果以安全优先,MySQL会断开长时间没有操作的连接,如果两条连接断开一条,断开了MySQL那条,为了确保数据一致,可以选择之间删除Redis的缓存,写MySQL,再同步回Redis,但是这种操作很无脑而且违背了使用Redis读的初衷;所以一般选择效率优先,Redis(key-value数据库)可以设置key的值的有效期我们可以先写Redis,设置key的过期时间(一般为200ms),再马上去写MySQL,最后MySQL同步回Redis,如果MySQL写成功了,就可以同步到Redis,这一整个写操作就完成了,如果写MySQL失败了,数据就没有,就不需要同步,Redis的数据也过期自动删除,这样就当没写过。这种策略就实实在在的保证了数据一致性。如果在过期时间之内访问这个写的数据,是有效的,在过期时间之后就由MySQL是否写成功来决定

90252802c64f47e396545a278e02b5b6.png

        关于同步策略,可以选择开源方案go_mysql_transfer伪装从数据库,它是通过拉取MySQL的binlog获得行数据再同步到Redis。也可以选择触发器+udf,热点数据表设置触发器,与redis连接同步数据。这里不再赘述。

缓存问题

缓存穿透

        MySQL与Redis都没有热点数据,却直读取这个不存在的数据,MySQL崩溃。我们可以在Redis中设置键值对<key,null>,这样就相当于有效访问,但是没有数据。此外,还可以使用布隆过滤器,可确定访问的热点数据一定不存在,提前判断热点数据有没有,没有就不访问。

缓存击穿

        Redis没有的数据,MySQL却有,大量的MySQL并发连接请求造成MySQL崩溃。可以设置Redis过热数据不过期。或者可用分布式锁将Redis与MySQL的访问加锁,做同步。

缓存雪崩

        大量缓存数据集中失效,但是MySQL却有,造成MySQL崩溃,多出些重启情况。可以间隔设置过期时间。或者在重启时预热向Redis导入热数据。

其他

        MySQL与Redis是有区别的,Redis不支持回滚,如果两个都使用事务就无法满足一致性,所以使用这种缓存方案只支持一条一条的SQL语句。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 数据分析-13-时间序列异常值检测的类型及常见的检测方法
  • Linux集群管理-网站集群批量管理-ssh服务
  • MariaDB 导入报错: Error at line 1: Unknown command ‘\-‘. 版本冲突的解决方法
  • 无人机应用新纪元:图形工作站配置推荐与硬件解析
  • 数据结构——复杂度讲解
  • Bio-Linux-shell详解-1-从0开始
  • 苹果CMS vs. 海洋CMS:哪个系统更易于百度收录?
  • leetcode hot100_part02_双指针
  • 解决 Node.js 项目中的 Yarn 安装错误
  • 使用 Apache Cassandra 实现 LLM 缓存:提升 AI 应用性能的实用指南
  • 设计模式 22 模板方法模式
  • 240909-ChuanhuChatGPT集成Ollama的环境配置
  • 101.游戏安全项目-创建人物对象结构
  • 游戏开发引擎___unity位置信息和unlit shader(无光照着色器)的使用,以桌子的渲染为例
  • 【devops】devops-git之介绍以及日常使用
  • JS 中的深拷贝与浅拷贝
  • [deviceone开发]-do_Webview的基本示例
  • ES6核心特性
  • exports和module.exports
  • iOS | NSProxy
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • Java 11 发布计划来了,已确定 3个 新特性!!
  • JAVA之继承和多态
  • React+TypeScript入门
  • SegmentFault 2015 Top Rank
  • swift基础之_对象 实例方法 对象方法。
  • Travix是如何部署应用程序到Kubernetes上的
  • 动态规划入门(以爬楼梯为例)
  • 欢迎参加第二届中国游戏开发者大会
  • 力扣(LeetCode)21
  • 前端知识点整理(待续)
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 如何在 Tornado 中实现 Middleware
  • 系统认识JavaScript正则表达式
  • 正则表达式
  • 国内唯一,阿里云入选全球区块链云服务报告,领先AWS、Google ...
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • ​Python 3 新特性:类型注解
  • ​低代码平台的核心价值与优势
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • $Django python中使用redis, django中使用(封装了),redis开启事务(管道)
  • (2)(2.10) LTM telemetry
  • (7)svelte 教程: Props(属性)
  • (HAL库版)freeRTOS移植STMF103
  • (react踩过的坑)Antd Select(设置了labelInValue)在FormItem中initialValue的问题
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (附源码)计算机毕业设计SSM教师教学质量评价系统
  • (转)visual stdio 书签功能介绍
  • (转)使用VMware vSphere标准交换机设置网络连接
  • **PyTorch月学习计划 - 第一周;第6-7天: 自动梯度(Autograd)**
  • .gitignore文件设置了忽略但不生效
  • .NET Project Open Day(2011.11.13)
  • .NET Windows:删除文件夹后立即判断,有可能依然存在
  • .NETCORE 开发登录接口MFA谷歌多因子身份验证
  • .Net的C#语言取月份数值对应的MonthName值