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

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 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

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
4天前
|
存储 缓存 安全
基于iOS平台的高效图片缓存策略实现
【4月更文挑战第22天】 在移动应用开发中,图片资源的加载与缓存是影响用户体验的重要因素之一。尤其对于iOS平台,由于设备存储空间的限制以及用户对流畅性的高要求,设计一种合理的图片缓存策略显得尤为关键。本文将探讨在iOS环境下,如何通过使用先进的图片缓存技术,包括内存缓存、磁盘缓存以及网络请求的优化,来提高应用的性能和响应速度。我们将重点分析多级缓存机制的设计与实现,并对可能出现的问题及其解决方案进行讨论。
|
5天前
|
存储 缓存 算法
实现iOS平台的高效图片缓存策略
【4月更文挑战第22天】在移动应用开发中,图片资源的处理是影响用户体验的重要因素之一。特别是对于图像资源密集型的iOS应用,如何有效地缓存图片以减少内存占用和提升加载速度,是开发者们面临的关键挑战。本文将探讨一种针对iOS平台的图片缓存策略,该策略通过结合内存缓存与磁盘缓存的机制,并采用先进的图片解码和异步加载技术,旨在实现快速加载的同时,保持应用的内存效率。
|
23天前
|
缓存 关系型数据库 MySQL
MySQL 查询优化:提速查询效率的13大秘籍(索引设计、查询优化、缓存策略、子查询优化以及定期表分析和优化)(中)
MySQL 查询优化:提速查询效率的13大秘籍(索引设计、查询优化、缓存策略、子查询优化以及定期表分析和优化)(中)
|
2天前
|
缓存 NoSQL 关系型数据库
在Python Web开发过程中:数据库与缓存,MySQL和NoSQL数据库的主要差异是什么?
MySQL与NoSQL的主要区别在于数据结构、查询语言和可扩展性。MySQL是关系型数据库,依赖预定义的数据表结构,使用SQL进行复杂查询,适合垂直扩展。而NoSQL提供灵活的存储方式(如JSON、哈希表),无统一查询语言,支持横向扩展,适用于处理大规模、非结构化数据和高并发场景。选择哪种取决于应用需求、数据模型及扩展策略。
10 0
|
11天前
|
缓存 NoSQL Java
使用Redis进行Java缓存策略设计
【4月更文挑战第16天】在高并发Java应用中,Redis作为缓存中间件提升性能。本文探讨如何使用Redis设计缓存策略。Redis是开源内存数据结构存储系统,支持多种数据结构。Java中常用Redis客户端有Jedis和Lettuce。缓存设计遵循一致性、失效、雪崩、穿透和预热原则。常见缓存模式包括Cache-Aside、Read-Through、Write-Through和Write-Behind。示例展示了使用Jedis实现Cache-Aside模式。优化策略包括分布式锁、缓存预热、随机过期时间、限流和降级,以应对缓存挑战。
|
14天前
|
存储 缓存 自动驾驶
缓存策略与Apollo:优化网络请求性能
缓存策略与Apollo:优化网络请求性能
|
18天前
|
存储 缓存 iOS开发
基于iOS的高效图片缓存策略实现
【4月更文挑战第9天】在移动应用开发中,图片资源的加载与缓存是影响用户体验的重要因素之一。特别是对于iOS平台,合理设计图片缓存策略不仅能够提升用户浏览图片时的流畅度,还能有效降低应用程序的内存压力。本文将介绍一种针对iOS环境优化的图片缓存技术,该技术通过多级缓存机制和内存管理策略,实现了图片快速加载与低内存消耗的目标。我们将从系统架构、关键技术细节以及性能评估等方面展开讨论,为开发者提供一套实用的图片缓存解决方案。
17 0
|
23天前
|
存储 缓存 iOS开发
实现iOS平台的高效图片缓存策略
【4月更文挑战第4天】在移动应用开发中,图片资源的加载与缓存是影响用户体验的关键因素之一。尤其对于iOS平台,由于设备存储和内存资源的限制,设计一个高效的图片缓存机制尤为重要。本文将深入探讨在iOS环境下,如何通过技术手段实现图片的高效加载与缓存,包括内存缓存、磁盘缓存以及网络层面的优化,旨在为用户提供流畅且稳定的图片浏览体验。
|
28天前
|
canal 消息中间件 关系型数据库
【分布式技术专题】「分布式技术架构」MySQL数据同步到Elasticsearch之N种方案解析,实现高效数据同步
【分布式技术专题】「分布式技术架构」MySQL数据同步到Elasticsearch之N种方案解析,实现高效数据同步
78 0
|
1月前
|
canal 关系型数据库 MySQL
四种常用的 MySQL 数据同步 ES 的方法
【2月更文挑战第16天】
198 2
四种常用的 MySQL 数据同步 ES 的方法

热门文章

最新文章