Mysql的缓存方案

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
简介: Mysql的缓存方案

mysql主从复制

原理图

1. 主库更新事件(update、insert、delete)通过io-thread写到binlog;(事务提交之后产生的文件)

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

3. 从库通过sql-thread读取(read) relay log,并把更新事件在从库中执⾏(replay)⼀遍;

读写分离

当我们写完主数据库之后再去读从数据库,读到的数据不一定是最新的数据。

最终⼀致性

写主读从,

为什么需要缓冲层?

前提

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

mysql

mysql有缓冲层,它的作⽤也是⽤来缓存热点数据,这些数据包括数据⽂件、索引⽂件等;mysql 缓冲层是从⾃身出发,跟具体的业务⽆关;这⾥的缓冲策略主要是lru,当然是经过优化的lru; mysql数据主要存储在磁盘当中,适合⼤量重要数据的存储;磁盘当中的数据⼀般是远⼤于内存当 中的数据;mysql是关系型数据库,⽅便 OLTP 进⾏统计分析;⼀般业务场景关系型数据库 (mysql)作为主要数据库;

缓冲层

缓存数据库可以选⽤redis,memcached;它们所有数据都存储在内存当中,当然也可以将内存当 中的数据持久化到磁盘当中;内存的数据和磁盘的数据是⼀⽐⼀的;

存储⽐较

⼏项重要的数据

1. 内存的访问速度是磁盘访问速度的10万倍(数量级倍率);内存的访问速度⼤约是100ns, ⽽⼀次磁盘访问⼤约是10ms;访问mysql时访问磁盘的次数跟b+树的⾼度相关;

2. ⼀般⼤部分项⽬中,数据库读操作是写操作的10倍左右;

总结

1. 由于mysql的缓冲层不由⽤户来控制,也就是不能由⽤户来控制缓存具体数据;

2. 访问磁盘的速度⽐较慢,尽量获取数据从内存中获取;

3. 主要解决读的性能;因为写没必要优化,必须让数据正确的落盘;如果写性能出现问题,那 么请使⽤横向扩展集群⽅式来解决;

4. 项⽬中需要存储的数据应该远⼤于内存的容量,同时需要进⾏数据统计分析,所以数据存储 获取的依据应该是关系型数据库;

5. 缓存数据库可以存储⽤户⾃定义的热点数据;以下的讨论都是基于热点数据的同步问题;

原理图

为什么有同步的问题?

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

1. mysql有,缓存⽆

2. mysql⽆,缓存有

3. 都有,但数据不⼀致

4. 都有,数据⼀致

5. 都没有

4和5显然是没问题的,我们现在需要考虑1、2以及3;

⾸先明确⼀点:我们获取数据的主要依据是mysql,所以mysql数据正确就万事⼤吉,只需要将 mysql的数据正确同步到缓存数据库就可以了;同理,缓存有,mysql没有,这⽐较危险,此时我 们可以认为该数据为脏数据;所以我们需要在同步策略中避免该情况发⽣;同时可能存在mysql和 缓存都有数据,但是数据不⼀致,这种也需要在同步策略中避免; 缓存不可⽤的话,我们整个系统应该要保持正常⼯作; mysql不可⽤的话,应该停⽌对外提供服务; 另外可以将问题 3 转化为问题 1

尝试解决同步(⼀致性)

主要数据存储在mysql当中,所以先写mysql,如果mysql不可⽤,直接返回;mysql写成功后, 再将数据同步给redis就⾏了,如果此时redis不可⽤,应该怎么做?

先从redis当中获取数据,如果redis不可⽤,直接去mysql获取;如果redis有,直接返回;如果 redis没有,转⽽向mysql请求,如果mysql没有,直接返回;如果MySQL有,则返回并将数据回写到redis当中;

总结

1. 业务层引⼊了两个变化⽅向,尽量减少redis的流程;

2. 业务层控制热数据流程;回写流程控制热数据流程;

3. 热数据不是总是热数据;需要将热数据设置超时时间;

解决数据同步问题

⼀致性问题

强⼀致性

同步是否成功的依据来源于mysql是否同步到redis,即使没有同步成功,也没关系;

写流程:先删除缓存,再写mysql,后⾯数据的同步交由go-mysql-transfer;

先删除缓存,为了避免其他服务读取旧的数据;也是告知系统这个数据已经不是最新,建议从 mysql获取数据;

强⼀致性只适⽤于单数据中⼼的模型下;

多数据中⼼的模型下,不管先操作redis还操作mysql都会引起分布式异常问题的产⽣,此时可以通过加分布式锁的⽅式解决,但是这得不偿失;可以将多数据中⼼转化为单数据中⼼;或者强⼀致性需求读写都⾛mysql;其他⼀致性需求低的⾛最终⼀致性;

最终⼀致性

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

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

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

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

数据同步⽅案1

原理图

数据同步⽅案2

代码1

git clone https://gitee.com/mirrors/go-mysql-transfer.git

/*
mysql 配置⽂件 my.cnf
log-bin=mysql-bin # 开启 binlog
binlog-format=ROW # 选择 ROW 模式
binlog redolog binlog 事务提交后产⽣的 不要纠结回滚了怎么办?
server_id=1 # 配置 MySQL replaction 需要定义,不要和 go-mysql-transfer 的
slave_id 重复
*/
CREATE table `t_user`(
 `id` bigint,
 `name` varchar(100),
 `height` INT8,
 `sex` varchar(1),
 `age` INT8,
 `createtime` datetime,
 PRIMARY KEY(`id`)
);
insert into `t_user` values (10001, 'mark', 180, '1', 30, '2020-06-01');
update `t_user` set `age` = 31 where id = 10001;
delete from `t_user` where id = 10001;
-- go-mysql-transfer
--[[
安装步骤:
GO111MODULE=on
git clone https://gitee.com/0k/go-mysql-transfer.git
go env -w GOPROXY=https://goproxy.cn,direct
go build
修改 app.yml
执⾏ go-mysql-transfer
]]
local ops = require("redisOps") --加载redis操作模块
local row = ops.rawRow() --当前数据库的⼀⾏数据,table类型,key为列名称
local action = ops.rawAction() --当前数据库事件,包括:insert、updare、delete
if action == "insert" then -- 只监听insert事件
 local id = row["id"] --获取ID列的值
 local name = row["name"] --获取USER_NAME列的值
 local key = name .. ":" .. id
 local sex = row["sex"]
 local height = row["height"] --获取PASSWORD列的值
 local age = row["age"]
 local createtime = row["createtime"] --获取CREATE_TIME列的值
 ops.HSET(key, "id", id) -- 对应Redis的HSET命令
 ops.HSET(key, "name", name) -- 对应Redis的HSET命令
 ops.HSET(key, "sex", sex) -- 对应Redis的HSET命令
 ops.HSET(key, "height", height) -- 对应Redis的HSET命令
 ops.HSET(key, "age", age) -- 对应Redis的HSET命令
 ops.HSET(key, "createtime", createtime) -- 对应Redis的HSET命令
end

代码2

git clone https://gitee.com/josinli/mysql_redis.git

触发器:具备事务 外键具备事务 如果

不建议使⽤,有事务的场景容易出错;虽然保证了真正的强⼀致性;

这个实现每次插⼊修改都需要重新建⽴redis连接,操作完后⼜释放redis连接;

问题是否解决?

没有,我们刚刚思考的⽅向全是正常流程下的⽅式,我们来看异常情况;

缓存穿透

假设某个数据redis不存在,mysql也不存在,⽽且⼀直尝试读怎么办?缓存穿透,数据最终压⼒ 依然堆积在mysql,可能造成mysql不堪重负⽽崩溃

解决

1. 发现mysql不存在,将redis设置为 设置过期时间 下次访问key的时候 不再访问 mysql 容易造成redis缓存很多⽆效数据;

2. 布隆过滤器,将mysql当中已经存在的key,写⼊布隆过滤器,不存在的直接pass掉;

缓存击穿

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

原理图

解决

1. 加锁

请求数据的时候获取锁,如果获取成功,则操作,获取失败,则休眠⼀段时间(200ms)再去获 取;获取成功,则释放锁

⾸先读redis,不存在,读mysql,存在,写redis key的锁

整个流程⾛完,才让后⾯的服务器访问

2. 将很热的key,设置不过期

缓存雪崩

表示⼀段时间内,缓存集中失效(redis⽆ mysql 有),导致请求全部⾛mysql,有可能搞垮数据库, 使整个服务失效;

解决

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

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

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

 

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
10天前
|
存储 SQL 关系型数据库
Mysql高可用架构方案
本文阐述了Mysql高可用架构方案,介绍了 主从模式,MHA模式,MMM模式,MGR模式 方案的实现方式,没有哪个方案是完美的,开发人员在选择何种方案应用到项目中也没有标准答案,合适的才是最好的。
60 3
Mysql高可用架构方案
|
2月前
|
消息中间件 canal 缓存
项目实战:一步步实现高效缓存与数据库的数据一致性方案
Hello,大家好!我是热爱分享技术的小米。今天探讨在个人项目中如何保证数据一致性,尤其是在缓存与数据库同步时面临的挑战。文中介绍了常见的CacheAside模式,以及结合消息队列和请求串行化的方法,确保数据一致性。通过不同方案的分析,希望能给大家带来启发。如果你对这些技术感兴趣,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!
144 6
项目实战:一步步实现高效缓存与数据库的数据一致性方案
|
2月前
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
15天前
|
SQL 缓存 关系型数据库
美团面试:Mysql 有几级缓存? 每一级缓存,具体是什么?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴因未能系统梳理MySQL缓存机制而在美团面试中失利。为此,尼恩对MySQL的缓存机制进行了系统化梳理,包括一级缓存(InnoDB缓存)和二级缓存(查询缓存)。同时,他还将这些知识点整理进《尼恩Java面试宝典PDF》V175版本,帮助大家提升技术水平,顺利通过面试。更多技术资料请关注公号【技术自由圈】。
美团面试:Mysql 有几级缓存? 每一级缓存,具体是什么?
|
11天前
|
关系型数据库 MySQL
mysql 5.7.x版本查看某张表、库的大小 思路方案说明
mysql 5.7.x版本查看某张表、库的大小 思路方案说明
34 5
|
13天前
|
缓存 NoSQL 关系型数据库
mysql和缓存一致性问题
本文介绍了五种常见的MySQL与Redis数据同步方法:1. 双写一致性,2. 延迟双删策略,3. 订阅发布模式(使用消息队列),4. 基于事件的缓存更新,5. 缓存预热。每种方法的实现步骤、优缺点均有详细说明。
|
16天前
|
关系型数据库 MySQL
mysql 5.7.x版本查看某张表、库的大小 思路方案说明
mysql 5.7.x版本查看某张表、库的大小 思路方案说明
25 1
|
2月前
|
存储 SQL 关系型数据库
【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)
MySQL调优主要分为三个步骤:监控报警、排查慢SQL、MySQL调优。 排查慢SQL:开启慢查询日志 、找出最慢的几条SQL、分析查询计划 。 MySQL调优: 基础优化:缓存优化、硬件优化、参数优化、定期清理垃圾、使用合适的存储引擎、读写分离、分库分表; 表设计优化:数据类型优化、冷热数据分表等。 索引优化:考虑索引失效的11个场景、遵循索引设计原则、连接查询优化、排序优化、深分页查询优化、覆盖索引、索引下推、用普通索引等。 SQL优化。
531 15
【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)
|
2月前
|
存储 SQL 关系型数据库
一篇文章搞懂MySQL的分库分表,从拆分场景、目标评估、拆分方案、不停机迁移、一致性补偿等方面详细阐述MySQL数据库的分库分表方案
MySQL如何进行分库分表、数据迁移?从相关概念、使用场景、拆分方式、分表字段选择、数据一致性校验等角度阐述MySQL数据库的分库分表方案。
391 15
一篇文章搞懂MySQL的分库分表,从拆分场景、目标评估、拆分方案、不停机迁移、一致性补偿等方面详细阐述MySQL数据库的分库分表方案
|
1月前
|
SQL 关系型数据库 MySQL
mysql集群方案
mysql集群方案
38 0

热门文章

最新文章