中间件专栏之MySQL篇——MySQL缓存策略
本文所说的MySQL缓存策略与前文提到的buffer pool不同,那是MySQL内部自己实现的,本问所讲的缓存策略是使用另一个中间件redis来缓存MySQL中的热点数据。
一、为什么需要MySQL缓存方案
缓存用户定义的热点数据,用户可以直接从缓存中获取热点数据,降低数据库的读写压力。具体的原因如下:1、内存访问速度约是磁盘的10万倍,可极大节省时间;2、一般使用缓存的场景读的需求远远大于写的需求;3、MySQL自身的缓冲层与业务无关,无法实现用户自定义热点数据的缓存;4、一般而言,MySQL作为主数据库,redis作为辅助数据库,存放热点数据(主数据库一定是磁盘数据库,因为要保证数据的安全)。
二、缓存方案的基本原理
redis和MySQL数据一致性状态分析,共分为5种情况:
1、数据MySQL有,redis无;
2、数据MySQL无,redis有;
3、数据MySQL有,redis有,但不一致;
4、数据MySQL有,redis有,且一致;
5、数据MySQL无,redis无;
其中,状态1,4,5是合理的状态,2,3是不合理状态,并且状态4是理想状态,其他状态需要向状态4靠拢。
用户定义的热点数据如何读写?
读:先读redis(下文统称缓存),缓存存在则直接返回;不存在则访问MySQL,再写入缓存。
写:1、保证安全的方法:先删除缓存中的数据,再写入MySQL,最后同步至缓存;
2、提高效率但损失部分安全性的方法:先写入缓存并设置过期时间(过期时间=MySQL网络传输时间+MySQL处理时间+MySQL同步到缓存时间),再写入MySQL,最后MySQL再同步至缓存。该方法的唯一脆弱性在于MySQL还没同步到缓存的那段时间,可能出现数据不一致。(描述的比较抽象,读者若不理解可在评论区留言)。
上述讲到的MySQL同步至缓存,如何同步?
常用的有go-mysql-transfer,主要原理是伪装MySQL从数据库,此处不赘述,可自行查阅资料。
三、缓存方案的常见故障问题及解决方案
在使用Redis缓存用户定义的热点数据时,可能会遇到一些故障问题,通常会影响到应用的性能和数据一致性。以下是一些常见的故障问题及其解决方案:
1. 缓存雪崩
问题描述:缓存雪崩是指在同一时间大量缓存失效或重启缓存时,所有的请求都直接访问数据库,造成数据库压力骤增,进而引发系统崩溃或性能下降。
解决方案:
- 缓存失效时间错峰:为不同的缓存设置不同的过期时间,避免所有缓存同时失效。例如,可以给热点数据设置较长的过期时间,并随机化失效时间。
- 使用Redis持久化机制:启用Redis的AOF(Append Only File)或RDB(快照)持久化机制,在Redis重启时可以恢复缓存数据,避免每次重启都从数据库加载。
- 引入多级缓存:在Redis之外引入本地缓存(如应用服务器本地内存)来缓解Redis压力。
2. 缓存击穿
问题描述:缓存击穿是指某个热点数据的缓存失效时,多个请求同时访问数据库,造成数据库压力过大。特别是当某些热点数据缓存已经过期时,所有请求都直接访问数据库,可能会导致系统性能问题。
解决方案:
- 加锁机制:当缓存失效时,可以使用分布式锁(如Redis的
SETNX)来保证同一时刻只有一个请求去加载数据,其他请求等待缓存更新,减少对数据库的压力。 - 使用队列缓存更新机制:可以使用队列(如Redis的List或Stream)来将数据加载的请求排队,避免多个请求同时去访问数据库。
3. 缓存数据不一致
问题描述:由于缓存和数据库的数据不同步,可能会导致数据不一致的问题。例如,数据库中的数据发生了变更,而缓存没有及时更新。
解决方案:
- 缓存更新策略:
- 主动更新:当数据库中的数据发生变化时,主动更新或删除相应的缓存。这通常通过数据库触发器或应用层代码来实现。
- 延迟双删策略:在缓存更新时,先删除缓存,再写入新的缓存。如果出现缓存未更新的情况,再进行第二次删除缓存,避免由于并发问题导致缓存一致性问题。
- 使用定时任务同步:定时任务可以用于同步数据库和缓存的数据,定期清除过期或失效的缓存数据。
4. Redis单点故障
问题描述:如果Redis作为缓存的唯一节点,发生故障(如宕机),将会导致整个缓存不可用,影响应用的性能。
解决方案:
- Redis集群或哨兵模式:使用Redis的高可用方案(如Redis Sentinel、Redis Cluster等)来保证Redis的高可用性。这样即使主节点宕机,Redis集群或哨兵可以自动进行主从切换,保证服务的连续性。
- 持久化机制:启用Redis的AOF或RDB持久化机制,确保数据在Redis崩溃后能够恢复。
5. 缓存穿透
问题描述:缓存穿透是指请求访问的数据既不存在于缓存中,也不存在于数据库中,导致每次请求都直接查询数据库,增加数据库负载。
解决方案:
- 使用布隆过滤器:在缓存前面加一个布隆过滤器,当某个数据不存在时,布隆过滤器可以直接判断并阻止请求访问数据库。
- 空值缓存:对于不存在的数据,可以将空值缓存一段时间,避免同样的请求频繁访问数据库。比如,当查询的数据不存在时,可以将返回值为空的情况缓存,设置较短的过期时间。
6. 缓存容量限制
问题描述:Redis缓存有限,当缓存数据量过大时,可能会出现Redis内存不足,导致缓存数据丢失或者缓存失效。
解决方案:
- LRU(Least Recently Used)淘汰策略:Redis提供了多种淘汰策略,默认使用LRU算法,在内存不足时,Redis会自动删除最久未使用的缓存数据。可以根据业务需求调整淘汰策略。
- 合理设计缓存策略:对缓存数据进行合理设计,定期清理过期缓存,避免无意义的数据存储占用内存。
其中1,2,5是最为常见的故障。
四、MySQL三大日志的作用、区别以及刷盘时机
1. 二进制日志(Binlog)
作用:
- 数据恢复:二进制日志记录了所有更改数据库结构或数据的操作(如
INSERT、UPDATE、DELETE等),因此可以用于数据库恢复。在发生故障时,可以通过备份加上二进制日志来恢复到某个特定时间点的数据。 - 主从复制:二进制日志是MySQL主从复制的基础。主数据库将操作写入二进制日志,从数据库通过读取主数据库的二进制日志来同步数据。
- 审计:可以用来记录数据库的所有更改操作,帮助审计和追踪某些特定操作的执行情况。
刷盘时机:
- Binlog的写入是按事务提交的,即当事务提交时,binlog会同步到磁盘。使用
sync_binlog参数控制刷新频率。 - sync_binlog=0:表示不强制写入,可能会丢失binlog日志。
- sync_binlog=1:每次写入都会强制刷新binlog到磁盘。
- sync_binlog>1:表示每次写入时会在多个binlog文件之间做同步,降低写入频率,但增加一些风险。
2. 错误日志(Error Log)
作用:
- 记录启动和停止:记录MySQL服务器的启动和关闭过程中的各种信息,包括启动、停止、重启等日志。
- 错误记录:记录运行中的各种错误信息,如语法错误、权限问题、资源不足等。
- 警告信息:记录数据库在运行过程中遇到的一些警告信息或非致命错误。
刷盘时机:
- 错误日志通常在数据库启动时和操作过程中进行记录,通常以文件的形式存在并实时更新。因此,错误日志的刷盘时机通常为每次写入日志时即进行刷新,不需要额外的配置。
3. 查询日志(General Log)
作用:
- 记录所有查询:查询日志会记录MySQL服务器接收到的所有SQL查询语句(无论是否成功执行),这对于开发、调试、性能分析非常有用。
- 性能分析:通过查看查询日志,可以分析哪些查询语句执行时间较长,或者执行频率较高,从而帮助优化SQL查询。
区别:
- 查询日志与错误日志:
- 查询日志记录的是所有执行的SQL语句,不管是否出错;
- 错误日志记录的是MySQL启动/停止/崩溃等相关的错误信息,以及执行失败的SQL语句。
- 查询日志与二进制日志:
- 查询日志记录所有的查询操作,但不涉及数据的改变,它是“所有SQL语句的镜像”;
- 二进制日志记录的是实际对数据库数据产生变化的操作,通常会比查询日志更为简洁且有用,用于恢复和主从同步。
刷盘时机:
- 查询日志会随着每次SQL语句的执行而实时记录,所以一般会进行实时刷盘。
刷盘时机总结:
- 二进制日志(Binlog):根据
sync_binlog参数设置,常见的做法是每次事务提交时写入磁盘。 - 错误日志(Error Log):实时刷盘,记录数据库运行状态和错误信息。
- 查询日志(General Log):实时刷盘,记录所有的查询操作。
总结:
| 日志类型 | 主要功能 | 是否包含数据变化 | 是否记录所有操作 | 刷盘时机 |
|---|---|---|---|---|
| 二进制日志 | 数据恢复、主从复制、审计 | 是 | 否 | 事务提交时写入 |
| 错误日志 | 记录数据库错误、启动/停止等信息 | 否 | 否 | 实时刷盘 |
| 查询日志 | 记录所有SQL查询 | 否 | 是 | 实时刷盘 |
PS:还有一种说法是三大日志是binlog,redolog,undolog,因此我把另两种也总结在下面。
Undo Log 和 Redo Log 是 MySQL 中事务日志的一部分,用于支持事务的回滚(Undo)和恢复(Redo) 。
1. Undo Log
作用:
- 事务回滚:Undo Log 主要用于支持事务的回滚(Rollback)操作。当一个事务中的操作出现错误或用户主动回滚时,Undo Log 用于撤销事务中已经进行的操作,将数据恢复到事务开始之前的状态。
- 多版本并发控制(MVCC):Undo Log 也被 MySQL 用于实现 多版本并发控制,即不同事务可以并发操作同一行数据而不冲突。通过存储数据的历史版本,其他事务可以读取旧的版本,避免锁冲突。
- 保持一致性:在数据库崩溃或重启时,Undo Log 会确保未提交的事务所做的修改不会被永久保留,从而保证数据库的一致性。
刷盘时机:
- Undo Log 的刷盘通常是与 事务的提交和回滚 相关的。当事务提交或回滚时,Undo Log 记录会写入磁盘。如果事务未提交,则这些记录会被删除。
- 一般情况下,Undo Log 是缓存在内存中的,在事务提交时会刷新到磁盘,具体的刷盘频率和配置取决于
innodb_flush_log_at_trx_commit配置。
2. Redo Log
作用:
- 事务恢复:Redo Log 记录了已提交事务的操作,用于数据库崩溃后的恢复操作。Redo Log 中包含了已提交事务对数据库数据的修改,数据库崩溃时,通过 Redo Log 来确保所有已提交的事务不会丢失。
- 确保持久性(Durability):Redo Log 是 MySQL InnoDB 存储引擎实现事务持久性(Durability)特性的关键。即使数据库发生崩溃,只要事务已经提交,相应的数据修改也会被持久化。
- 崩溃恢复:在 MySQL 崩溃恢复时,Redo Log 会被用来恢复已提交的事务。这是通过重放 Redo Log 中记录的操作来实现的。
刷盘时机:
- Redo Log 的写入频率可以通过
innodb_flush_log_at_trx_commit来控制。常见的值有:innodb_flush_log_at_trx_commit = 1:每次事务提交时,都会将 Redo Log 刷新到磁盘,确保事务持久性。这种设置保证了最强的数据一致性,但性能开销较大。innodb_flush_log_at_trx_commit = 2:每次事务提交时,Redo Log 写入到操作系统的缓冲区,但不立即刷新到磁盘。系统崩溃时,可能会丢失一些未刷新的日志,但性能相对较好。innodb_flush_log_at_trx_commit = 0:Redo Log 写入到内存,但并不立刻刷新到磁盘。性能最好,但崩溃恢复时可能会丢失已提交事务的数据。
Undo Log 和 Redo Log 的区别
| 特性 | Undo Log | Redo Log |
|---|---|---|
| 功能 | 支持事务回滚,撤销操作,保证一致性 | 支持事务恢复,保证持久性 |
| 内容 | 记录事务对数据的修改前的值(用于回滚) | 记录事务对数据的修改后的值(用于恢复) |
| 是否持久化 | 不持久化,仅在事务中有效 | 持久化,确保崩溃恢复时不会丢失已提交的事务数据 |
| 使用场景 | 事务回滚,MVCC(多版本并发控制) | 事务提交后,数据库崩溃恢复时 |
| 刷盘时机 | 事务提交或回滚时写入磁盘 | 事务提交时,具体配置决定刷新频率 |
| 存储位置 | 存储在内存中,在事务提交或回滚时写入磁盘 | 存储在磁盘上,一直保留用于崩溃恢复 |
总结:
- Undo Log 主要用于支持事务回滚和多版本并发控制,确保事务操作可以撤销,并且保持数据一致性。
- Redo Log 主要用于事务的持久性,确保已提交事务的数据在系统崩溃后不会丢失,保证事务的持久性。
相关文章:
中间件专栏之MySQL篇——MySQL缓存策略
本文所说的MySQL缓存策略与前文提到的buffer pool不同,那是MySQL内部自己实现的,本问所讲的缓存策略是使用另一个中间件redis来缓存MySQL中的热点数据。 一、为什么需要MySQL缓存方案 缓存用户定义的热点数据,用户可以直接从缓存中获取热点…...
CSS 日常开发常用属性总结
文章目录 CSS 日常开发常用属性总结一、 常用 CSS 属性1、布局相关(1)display:(2)position:(3)float:(4)clear: 2、尺寸与溢出&#x…...
CF 886A.ACM ICPC(Java实现)
题目分析 输入6个值,判断某三个值的和能够等于另外三个值的和 思路分析 首先判断总和是不是一个偶数,如果不是就“NO”。由于小何同学算法不好,只能使用三层for循环强行判断某三个值是否能等于总和的一半,可以就“YES”。 代码 …...
Spring Boot 自动装配深度解析与实践指南
目录 引言:自动装配如何重塑Java应用开发? 一、自动装配核心机制 1.1 自动装配三大要素 1.2 自动装配流程 二、自定义自动配置实现 2.1 创建自动配置类 2.2 配置属性绑定 2.3 注册自动配置 三、条件注解深度应用 3.1 常用条件注解对比 3.2 自定…...
【windows driver】 开发环境简明安装教程
一、下载路径 https://learn.microsoft.com/en-us/windows-hardware/drivers/other-wdk-downloads 二、安装步骤: 1、安装Visual Studio IDE 笔者建议安装最新版本,可以向下兼容。发文截止到目前,VS2022是首选,当前笔者由于项…...
探秘基带算法:从原理到5G时代的通信变革【八】QAM 调制 / 解调
文章目录 2.7 QAM 调制 / 解调2.7.1 概述2.7.2 星座图星座图的结构与性能发射端的信息编码与接收端的解码差分编码的分类与实现差分编码的模4格雷加法器公式16QAM星座图与映射关系 2.7.3 信号表达式正交振幅调制的基本原理与系统分析相位误差对QAM性能的影响多电平正交振幅调制…...
Flink性能指标详解MetricsAnalysis
文章目录 Flink 组成1.JobManager2.TaskManager3.ResourceManager4.Dispatcher5.Client6. Env JobManager MetricsTaskManager Metrics Flink 组成 1.JobManager 管理任务 作业调度:负责接收和调度作业,分配任务到 TaskManager。资源管理:…...
Git强制覆盖分支:将任意分支完全恢复为main分支内容
Git强制覆盖分支:将任意分支完全恢复为main分支内容 场景背景完整操作步骤一、前置准备二、操作流程步骤 1:更新本地 main 分支步骤 2:强制重置目标分支步骤 3:强制推送至远程仓库 三、操作示意图 关键风险提示(必读&a…...
WPF 如何使文本显示控件支持显示内容滚动显示
WPF中如何使文本显示控件支持显示内容滚动显示 在WPF中,TextBlock 控件本身并不直接支持滚动功能,因为它的设计初衷是用于静态文本展示。但是,你可以通过一些技巧和自定义控件来实现 TextBlock 的滚动效果。以下是几种常见的方法:…...
Halcon 车牌识别-超精细教程
车牌示例 流程: 读取图片转灰度图阈值分割,找车牌内容将车牌位置设置变换区域形状找到中心点和弧度利用仿射变换,斜切车牌旋转转正,把车牌抠出来利用形态学操作拼接车牌号数字训练ocr开始识别中文车牌 本文章用到的算子(解析) Halcon 算子-承接车牌识别-CSDN博客 rgb1_to_gray…...
HTTP/1.1 和 HTTP/2 的区别,HTTP/2 有哪些新特性?
HTTP/1.1 和 HTTP/2 的区别及新特性详解 一、核心区别:连接管理与多路复用 HTTP/1.1 使用「短连接」或「持久连接」,但每个 TCP 连接在同一时刻只能处理一个请求(HOL Blocking)。浏览器通常通过开启多个 TCP 连接(…...
Redis实战篇《黑马点评》8 附近商铺
8.附近商户 8.1GEO数据结构的基本用法 GEO就是Geolocation的简写形式,代表地理坐标。Redis在3.2版本中加入了对GEO的支持,允许存储地理坐标信息,帮助我们根据经纬度来检索数据,常见的命令有 GEOADD:添加一个地理空间…...
【02】Cocos游戏开发引擎从0开发一款游戏-cocos项目目录结构熟悉-调试运行项目-最重要的assets资源文件认识-场景sense了解-优雅草卓伊凡
【02】Cocos游戏开发引擎从0开发一款游戏-cocos项目目录结构熟悉-调试运行项目-最重要的assets资源文件认识-场景sense了解-优雅草卓伊凡 开发背景 接下来我们直接打开我们的项目开始进一步操作, 实战开发 导入项目 我把得到的项目解压到本地,我们开…...
通过ollama本地化部署deepseek后,通过API方式请求特别的慢
通过ollama本地化部署deepseek后,通过API方式请求特别的慢 一、现象二、原因分析 一、现象 deepseek火了之后,本地私有化部署大模型的门槛大大降低,即使是在家里的windows电脑,也非常简单就可以安装大模型并且使用,最…...
CSS3中布局方式说明
CSS3 提供了多种灵活的布局方式,适用于不同的场景和需求。以下是主要的布局方式及其特点: 1. Flexbox 布局(弹性盒子) 用途:一维布局(水平或垂直方向排列元素)。特点: 通过 display…...
kafka-web管理工具cmak
一. 背景: 日常运维工作中,采用cli的方式进行kafka集群的管理,还是比较繁琐的(指令复杂?)。为方便管理,可以选择一些开源的webui工具。 推荐使用cmak。 二. 关于cmak: cmak是 Yahoo 贡献的一款强大的 Apac…...
T41LQ专为人工智能物联网(AIoT)应用设计,适用于智能安防、智能家居、机器视觉等领域 软硬件资料+样品测试
君正(Ingenic)T系列芯片涵盖多个型号,每个型号根据不同应用需求提供了多个版本。以下是各型号及其主要版本: 1. T23系列: T23N:标准版,适用于移动摄像机、安全监控、视频通话和视频分析等应用…...
Unity中动态切换光照贴图LightProbe的方法
关键代码:LightmapSettings.lightmaps lightmapDatas; LightmapData中操作三张图:lightmapColor,lightmapDir,以及一张ShadowMap 这里只操作前两张: using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI;public cl…...
考研408数据结构线性表核心知识点与易错点详解(附真题示例与避坑指南)
一、线性表基础概念 1.1 定义与分类 定义:线性表是由n(n≥0)个相同类型数据元素构成的有限序列,元素间呈线性关系。 分类: 顺序表:元素按逻辑顺序存储在一段连续的物理空间中(数组实现&…...
C++基础知识(七)之STL算法、智能指针、文件操作、C++异常、断言
二十一、STL算法 STL提供了很多处理容器的函数模板,它们的设计是相同的,有以下特点: 1)用迭代器表示需要处理数据的区间。 2)返回迭代器放置处理数据的结果(如果有结果)。 3)接受…...
vue3.2响应式优化
Vue 3.2 在响应式方面做了诸多优化,进一步提升了性能,下面为你详细介绍: 1. shallowReactive 和 shallowRef 的性能优势 原理:shallowReactive 和 shallowRef 是浅层响应式 API。shallowReactive 仅对对象的第一层属性进行响应式…...
【Linux】线程概念与控制
线程概念与控制 一.Linux线程概念1.什么是线程?2.分页式存储管理1.虚拟地址和页表的由来2.物理内存管理3.页表4.页目录结构5.两级页表的地址转换6.缺页中断(异常) 3.线程的优点(面试题)4.线程的缺点5.线程异常6.线程用途 二.Linux进程VS线程1.进程和线程2.进程的多个…...
零基础学习Python之循环详解:从入门到实践_我的学习Python记录11
零基础学习Python之循环详解:从入门到实践_我的学习Python记录11 一、前言 最近我在学习Python,发现很多编程概念和用法都让我感到陌生,尤其是循环这个概念。今天,我将分享我学到的循环知识,希望能帮助到和我一样的初…...
电子电路中,正负双电源供电的需求原因
1. 允许信号双向摆动 - **交流信号的处理**:许多电路(如音频放大器、运算放大器)需要处理正负交替变化的交流信号(例如声音信号、传感器输出)。如果仅用单正电源(如12V),信号的“负…...
ROS环境搭建
ROS首次搭建环境 注:以下内容都是在已经安装好ros的情况下如何搭建workplace 一、创建工作空间二、创建ROS包三、注意 注:以下内容都是在已经安装好ros的情况下如何搭建workplace 如果没有安装好,建议鱼香ros一步到位:鱼香ROS 我也是装了好久…...
java后端开发day26--常用API(一)
(以下内容全部来自上述课程) 1.Math 1.简单介绍 是一个帮助我们用于进行数学计算的工具类私有化构造方法,所有的方法都是静态的 2.常用方法 不要背,忘了就查文档。 3.练习题 1.判断一个数是否为质数(优化版&am…...
SpringBoot接口自动化测试实战:从OpenAPI到压力测试全解析
引言:接口测试的必要性 在微服务架构盛行的今天,SpringBoot项目的接口质量直接影响着系统稳定性。本文将分享如何通过自动化工具链实现接口的功能验证与性能压测,使用OpenAPI规范打通测试全流程,让您的接口质量保障体系更加完备。…...
分布式中间件:Redis介绍
目录 Redis 概述 Redis 的特点 高性能 丰富的数据结构 持久化 分布式特性 简单易用 Redis 的数据结构 字符串(String) 哈希(Hash) 列表(List) 集合(Set) 有序集合&…...
Python中文自然语言处理库SnowNLP
SnowNLP 介绍 SnowNLP 是一个基于 Python 的中文自然语言处理库,专为处理中文文本而设计。它受到 TextBlob 的启发,但与 TextBlob 不同的是,SnowNLP 没有使用 NLTK,所有的算法都是自己实现的,并且自带了一些训练好的字…...
Linux-计算机网络.udp
1.收发函数: read()/write () ///通用文件读写,可以操作套接字。 recv(,0) /send(,0) ///TCP 常用套机字读写 recvfrom()/sendto() ///UDP 常用套接字读写 ssize_t recv(int sockfd, void *buf, size_t len, …...
