MySQL缓存策略(一致性问题、数据同步以及缓存故障)

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: MySQL缓存策略(一致性问题、数据同步以及缓存故障)

一、数据库有哪些提升读写性能的方式呢?


  1. 连接池:阻塞io+线程池
  2. 异步连接:非阻塞io
  3. 从sql执行出发:即时执行+预编译执行(可以直接跳过句法分析、优化器等步骤,执行速度更快)
  4. 读写分离
  5. 缓存方案

1、连接池和异步连接

左边是多个线程来操作数据库和缓存,可以加上代理层proxy统一管理

或者使用dbserver(代理层)去代理访问数据库

skynet采用异步连接的方式,节约了网络传输的时间。

openresty采用的是连接池的方式

2、读写分离

主数据库处理写操作,而从数据库处理查询的操作,数据库的一致性则通过主从复制来实现

适用于读远比写多的场景,分摊服务器压力,提高机器的系统处理效率

主从复制这种集群方式:解决了单点故障问题(比如主数据库宕机了,就可以从 从数据库去获得备份)

主从复制还可以实现读写分离,将读写操作,分配到主从数据库中,分摊服务器压力

但是这个方案,由于主从复制并不能保证同时复制到从数据库中,因而可能在中途出现读取数据不一致的问题,但是最终是一致的(具体要看业务使用场景)。

下面介绍主从复制的原理

主从复制

原理图

  1. 主库更新事件(update、insert、delete)通过 io-thread 写到binlog;
  2. 从库请求读取 binlog,通过 io-thread 写入(write)从库本地 relay log(中继日志);
  3. 从库通过sql-thread读取(read) relay log,并把更新事件在从库中执行(replay)一遍;

复制流程:

  1. Slave上面的IO进程连接上Master,并请求从指定日志文件的指定位置(或者从最开始的日
    志)之后的日志内容。
  2. Master接收到来自Slave的IO进程的请求后,负责复制的IO进程会根据请求信息读取日志指
    定位置之后的日志信息,返回给Slave的 IO进程。返回信息中除了日志所包含的信息之外,
    还包括本次返回的信息已经到Master端的bin-log文件的名称以及bin-log的位置。
  3. Slave的IO进程接收到信息后,将接收到的日志内容依次添加到Slave端的relay-log文件的最
    末端,并将读取到的Master端的 bin-log的文件名和位置记录到master-info文件中,以便在
    下一次读取的时候能够清楚的告诉Master从何处开始读取日志。
  4. Slave的Sql进程检测到relay-log中新增加了内容后,会马上解析relay-log的内容成为在
    Master端真实执行时候的那些可执行的内容,并在自身执行。
    写的时候写主数据库,读的时候读从数据库

二、为什么需要缓冲层?

1、前提

读多写少,单个主节点能支撑项目数据量;数据的主要依据是 mysql;

2、mysql

mysql 有缓冲层,它的作用也是用来缓存热点数据,这些数据包括数据文件、索引文件等;mysql

缓冲层是从自身出发,跟具体的业务无关;这里的缓冲策略主要是 lru,当然是经过优化的 lru;

mysql数据主要存储在磁盘当中,适合大量重要数据的存储;磁盘当中的数据一般是远大于内存当

中的数据;一般业务场景关系型数据库(mysql)作为主要数据库;

3、缓冲层

缓存数据库可以选用redis,memcached;它们所有数据都存储在内存当中,当然也可以将内存

当中的数据持久化到磁盘当中;内存的数据和磁盘的数据是一比一的;

4、存储比较

5、几项重要的数据

  1. 内存的访问速度是磁盘访问速度的10万倍(数量级倍率);内存的访问速度大约是100ns,
    而一次磁盘访问大约是10ms;访问mysql时访问磁盘的次数跟b+树的高度相关;
  2. 一般大部分项目中,数据库读操作是写操作的10倍左右;

6、总结

  1. 由于mysql的缓冲层不由用户来控制,也就是不能由用户来控制缓存具体数据;
  2. 访问磁盘的速度比较慢,尽量获取数据从内存中获取;
  3. 主要解决读的性能;因为写没必要优化,必须让数据正确的落盘;如果写性能出现问题,那
    么请使用横向扩展集群方式来解决;
  4. 项目中需要存储的数据应该远大于内存的容量,同时需要进行数据统计分析,所以数据存储
    获取的依据应该是关系型数据库;
  5. 缓存数据库可以存储用户自定义的热点数据;以下的讨论都是基于热点数据的同步问题;

三、引入缓存

在没有引入缓存前,是服务器直接访问mysql,由于mysql的读写性能(磁盘io较慢)问题,额外再使用一个缓存数据库

原理图

为了解决mysql的读写性能(磁盘io较慢)问题,增加了缓存数据库(cache,比如redis),主要用于缓存用户的热点数据(内存访问的速度相比磁盘快很多)。


mysql是主要数据库,数据主要依据

cache缓存用户的热点数据

mysql中的缓冲池和这里的缓存的区别?

mysql中也有缓冲池,但是它存储的mysql的索引等数据,是mysql内部的热点数据。

这里的缓存cache是为了缓存业务中用户的热点数据。

例子:

比如12点钟有个秒杀活动,12点会涌入大量用户,但是12点前几乎没什么人登入,从而mysql中没有相应的缓存热点数据,为了能使得12点用户正常登入,因此要提前缓存用户的热点数据,避免大量用户涌入,mysql磁盘读写的性能直接影响到的了整个系统的响应能力。

需要考虑的问题

在没有缓存cache的时候,仅有一个mysql,(读:直接读mysql,写:直接写mysql)那么去访问很容易,现在有了mysql和cache,因此需要指定相应的缓存策略

四、为什么有同步的问题?

没有缓冲层之前,我们对数据的读写都是基于 mysql;所以不存在同步问题;这句话也不是必

然,比如读写分离就存在同步问题(数据一致性问题);

引入缓冲层后,我们对数据的获取需要分别操作缓存数据库和 mysql;那么这个时候数据可能存

在几个状态?

针对热点数据讨论,热点数据有以下几种状态

1.mysql有,cache没有(正常的情况下,可以通过策略去避免它)

2.mysql没有,cache有(不正常,避免)

3.mysql和cache都有,数据不一致(不正常,避免)

4.mysql和cache都有,数据一致(策略最终要实现的目的)

5.mysql和cache都没有(正常)

五、尝试解决同步(一致性)

制定读写策略

读策略:

1.先看cache是否有数据,如果有直接返回

2.如果没有,去访问mysql

3.如果mysql有,缓存数据传cache

4.如果mysql中没有,说明数据没有

写策略:

有 删除、修改、插入 这几种操作。

在写策略中,会出现一致性的问题

六、一致性问题以及如何解决

1、强一致性

强一致性(任何时候都要保证访问mysql和cache中对应数据的一致):当cache中数据不存在的时候,就会去访问mysql,也能保证强一致性。具体选择哪种一致性,跟业务逻辑有关)

也就是说,不能出现 1.mysql没有,cache有 2.mysql和cache都有,数据不一致

这种情况的出现

缓存和数据库一致性问题

实现强一致性的方案

删除:先去删除缓存(避免出现.mysql没有,cache有这种情况),

修改: 删除缓存,再去修改mysql(调换顺序,如果先修改mysql可能会出现,读到的可能是缓存中还没更新的数据,导致缓存和mysql中数据不一致问题)

插入:删除缓存,再去修改mysql(新数据避免缓存里已经有了这个数据,也是要先删除缓存)

上述这样操作后变成了(mysql有,cache没有)情况,cache中删除了,而我们最终要达到的目的是(mysql和cache都有,数据一致),因此要将mysql中的数据同步到cache(redis)当中。

即使是mysql中数据同步到cache中,有时间延迟,但是顺序是一致的,如下方的黑色(mysql中数据)和红色时间线(cache中数据),如果有数据还未到达cache,那么会直接访问mysql,能保证强一致性。

Redis缓存和MySQL数据一致性的后端高并发架构解决方案

2、最终一致性

读写分离,主库将数据同步到从库,是需要时间,那么在同步期间,主从之间数据有差异;

这里有写两种方案:

第一种:直接写mysql,等待mysql同步数据到redis;

第二种:先写redis,设置key的过期时间为200ms(经验值),等待mysql回写redis,覆盖key,

设置更长的过期时间;

200ms 默认的是 写mysql到mysql同步到redis的时长;这个需要根据实际环境进行设置;

最终一致性(开始不一致,最终访问mysql和cache中对应数据达成一致):在修改过程中,读取数据可能会出现mysql和cache中数据不一致的问题

如果读写分离,一致性要求高

第一种:主从半同步辅助

第二种:直接去主数据读取

实现最终一致性的方案:给缓存设置失效时间

1)先更新缓存,后更新数据库

写的时候往缓存中写,同时设置缓存的失效时间,失效后再刷入数据库

在性能方面,比方案一的性能要高。(这是先更新缓存,后更新数据库的情况,但是可能会出现问题)

2)先更新数据库,后更新缓存

写的时候只往数据库mysql写,刷新(同步)到cache中,同时,写入缓存中的数据,都设置失效时间(这样后续更新该数据的时候,不需要删除这一步骤了,缓存中失效删除后,会直接访问mysql从而保证强一致性)

七、如何实现数据同步呢?

在读取数据的时候,如果redis中没有相应的数据,就会将mysql中的数据同步到redis中,那么如何实现这个数据同步呢?

也就是下图中,虚线那个过程

数据同步方案

对于 触发器+UDF(user define function),不建议使用,会出现异常数据,效率非常低

1、数据同步方案

中间采用 一个组件 使得数据同步

mysql发送数据给canel

然后redis从canel客户端取数据

还有一种方案是

实现的原理就是,将中间件(go-mysql-transfer)伪装成一个从数据库,通过主从复制数据,然后再用中间件同步给redis

既然已经复制到 从数据库了

那么如果将数据通过 从数据库(中间件) 同步到redis呢?

首要对于中间件部分,它需要知道

1.mysql和redis的连接地址

2.热点数据是什么?定义热点数据

3.定义热点数据同步

八、缓存故障

1、缓存穿透

假设某个数据redis不存在,mysql也不存在,而且一直尝试读怎么办?缓存穿透,数据最终压力

依然堆积在mysql,可能造成mysql不堪重负而崩溃;

解决

  1. 发现mysql不存在,将redis设置为  设置过期时间 下次访问key的时候 不再访问
    mysql 容易造成redis缓存很多无效数据;
  2. 布隆过滤器,将mysql当中已经存在的key,写入布隆过滤器,不存在的直接pass掉;

2、缓存击穿

缓存击穿 某些数据redis没有,但是mysql有;此时当大量这类数据的并发请求,同样造成mysql

过大

解决

  1. 加锁
    请求数据的时候获取锁,如果获取成功,则操作,获取失败,则休眠一段时间(200ms)再去获
    取;获取成功,则释放锁
    首先读redis,不存在,读mysql,存在,写redis key的锁
    整个流程走完,才让后面的服务器访问
    (当同个业务不同线程访问redis未命中时,先获取一把互斥锁,然后进行数据库操作,此时另外一个线程未命中时,拿不到锁,等待一段时间后重新查询缓存,此时之前的线程已经重新把数据加载到redis之中了,线程二就直接缓存命中。这样就不会使得大量访问进入数据库)
  2. 将很热的key,设置不过期

3、缓存雪崩

表示一段时间内,缓存集中失效(redis无 mysql 有),导致请求全部走mysql,有可能搞垮数据库,

使整个服务失效;

解决

缓存数据库在整个系统不是必须的,也就是缓存宕机不会影响整个系统提供服务;

  1. 如果因为缓存数据库宕机,造成所有数据涌向mysql;
    采用高可用的集群方案,如哨兵模式、cluster模式;
  2. 如果因为设置了相同的过期时间,造成缓存集中失效;
    设置随机过期值或者其他机制错开失效时间;
  3. 如果因为系统重启的时候,造成缓存数据消失;
    重启时间短,redis开启持久化(过期信息也会持久化)就行了; 重启时间长提前将热数据导
    入redis当中;

缓存雪崩和缓存击穿的区别?

缓存雪崩和缓存击穿 都是数据在 mysql有,redis无 的情况,

缓存击穿是指1个key并发访问mysql

缓存雪崩是指大量或者全部的key并发访问mysql

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
1月前
|
缓存 NoSQL 关系型数据库
MySQL 与 Redis 如何保证双写一致性?
我是小假 期待与你的下一次相遇 ~
307 7
|
4月前
|
Web App开发 存储 缓存
如何精准清除特定类型或标签的缓存数据?
如何精准清除特定类型或标签的缓存数据?
409 57
|
6月前
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
|
3月前
|
缓存 关系型数据库 MySQL
降低MySQL高CPU使用率的优化策略。
通过上述方法不断地迭代改进,在实际操作中需要根据具体场景做出相对合理判断。每一步改进都需谨慎评估其变动可能导致其他方面问题,在做任何变动前建议先在测试环境验证其效果后再部署到生产环境中去。
191 6
|
3月前
|
存储 缓存 监控
一次缓存引发的文件系统数据不一致问题排查与深度解析
本文详述了一次由自研分布式文件系统客户端 EFC 的缓存架构更新所引发的严重数据不一致问题的完整排查过程。
一次缓存引发的文件系统数据不一致问题排查与深度解析
|
4月前
|
缓存 关系型数据库 MySQL
在MySQL中处理高并发和负载峰值的关键技术与策略
采用上述策略和技术时,每个环节都要进行细致的规划和测试,确保数据库系统既能满足高并发的要求,又要保持足够的灵活性来应对各种突发的流量峰值。实施时,合理评估和测试改动对系统性能的影响,避免单一措施可能引起的连锁反应。持续的系统监控和分析将对维护系统稳定性和进行未来规划提供重要信息。
259 15
|
3月前
|
缓存 关系型数据库 MySQL
MySQL数据库性能调优:实用技术与策略
通过秉持以上的策略实施具体的优化措施,可以确保MySQL数据库的高效稳定运行。务必结合具体情况,动态调整优化策略,才能充分发挥数据库的性能潜力。
178 0
|
6月前
|
消息中间件 缓存 NoSQL
基于Spring Data Redis与RabbitMQ实现字符串缓存和计数功能(数据同步)
总的来说,借助Spring Data Redis和RabbitMQ,我们可以轻松实现字符串缓存和计数的功能。而关键的部分不过是一些"厨房的套路",一旦你掌握了这些套路,那么你就像厨师一样可以准备出一道道饕餮美食了。通过这种方式促进数据处理效率无疑将大大提高我们的生产力。
230 32
|
7月前
|
关系型数据库 MySQL 大数据
大数据新视界--大数据大厂之MySQL 数据库课程设计:MySQL 数据库 SQL 语句调优的进阶策略与实际案例(2-2)
本文延续前篇,深入探讨 MySQL 数据库 SQL 语句调优进阶策略。包括优化索引使用,介绍多种索引类型及避免索引失效等;调整数据库参数,如缓冲池、连接数和日志参数;还有分区表、垂直拆分等其他优化方法。通过实际案例分析展示调优效果。回顾与数据库课程设计相关文章,强调全面认识 MySQL 数据库重要性。为读者提供综合调优指导,确保数据库高效运行。
|
8月前
|
机器学习/深度学习 人工智能 缓存
MHA2MLA:0.3%数据微调!复旦团队开源推理加速神器,KV缓存狂降96.87%
MHA2MLA是复旦大学、华东师范大学、上海AI Lab等机构联合推出的数据高效微调方法,通过引入多头潜在注意力机制(MLA),显著优化基于Transformer的LLM推理效率,降低推理成本。
280 1
MHA2MLA:0.3%数据微调!复旦团队开源推理加速神器,KV缓存狂降96.87%

推荐镜像

更多