Redis - CAP原则 => 缓存与数据库的一致性
这里的数据库是指Mysql等存放在磁盘的数据库,缓存是指Redis等在内存的数据库实时同步实时同步:缓存或DB修改,另一方同步修改强一致性要求比较高,可采用实时同步:查询时先查询缓存,查询不到再查询数据库,并保持到缓存;更新缓存时先更新数据库,再将缓存设置为过期,更新数据(建议不要更新缓存内容,而是设置缓存过期)非实时同步非实时同步:缓存或数据库修改,另一方不需要同步修改非实时同步:定时任务:设置
CAP原则
一致性(Consistency):读操作总是能读取到之前完成的写操作结果,系统每时每刻每个节点上的同一份数据都是一致
如Mysql数据库与Redis缓存的数据应当一致
可用性(Availability):非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)
对与系统,某个节点坏了不会影响其他节点,任何时候系统都能提供读写业务(不需要数据一致),高可用性 99.9999%,即全年允许的服务中断时间为31.5秒
分区可容忍性(Partition tolerance):大多数分布式系统都分布在多个子网络。每个子网络就叫做一个区(partition);分区可容忍性:系统节点无法通信,系统依旧可以运行
可用性和分区容忍性区别:
-
可用性是指节点故障,如主、从redis宕机,剩下的从redis依旧可以提供服务,该系统有可用性
-
分区容忍性是指节点间无法通信,如主从redis无法通信,系统依旧可用
CAP = Consistency + Availability + Partition tolerance
CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾,即有CA、CP、AP三种情况
这里指分布式系统,非分布式系统(单机系统)当然没有CAP这个概念
- CA:不保证分区容忍,也就是不考虑分布式系统多个数据库间无法通信的问题,即单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大
分布式系统中P是必须的,网络并不可靠,当分区间通信异常,C/A无法同时存在:分区无法通信,无法数据一致;为了追求数据一致就要禁止写入,无法高可用
- CP:不保证可用性,满足一致性,分区容忍的系统,通常性能不是特别高
该系统更新主mysql数据库,为了追求一致性,需要主从mysql数据一致,直到主从mysql都更新成功才返回成功
- AP:不保证一致性,满足可用性,分区容忍性的系统
不保证一致性,主mysql更新成功就返回成功,但主从数据不一致,后续通过主Mysql的binlog日志方式把数据同步到从Mysql
Redis是保证AP不保证C:系统要不管何时系统都能够响应读写请求
一致性
数据库如mysql等磁盘数据库,后端系统中数据最终存储在数据库中
缓存如redis等内存数据库,速度快,在运行时提高系统性能
这两种数据库同时在系统中,就需要两种数据库数据的一致性
缓存与数据库的数据一致性问题:当插入或者更新一条数据,怎么保持数据一致?
可以想到3种策略
-
先更新数据库,再更新缓存
-
先删除缓存,再更新数据库
-
先更新数据库,再删缓存
策略1:
先处理数据库再更新缓存:当处理数据库成功,处理缓存失败,就会造成数据库为真实数据db = new,缓存为旧数据cache = old
缓存与数据库不一致,读取时先读缓存数据old,得到的结果为old
策略2:
先删除缓存再更新数据库:
同时有一个请求A进行更新操作,另一个请求B进行查询操作,会出现如下情形:
(1)请求A进行写操作,删除缓存
(2)请求B查询发现缓存不存在
(3)请求B去数据库查询得到旧值
(4)请求B将旧值写入缓存
(5)请求A将新值写入数据库
结果缓存与数据库不一致,且读到的数据为old
策略3:
先更新数据库,再删缓存:
一个请求A做查询操作,一个请求B做更新操作,那么会有如下情形产生
(1)缓存刚好失效
(2)请求A查询数据库,得一个旧值
(3)请求B将新值写入数据库
(4)请求B删除缓存
(5)请求A将查到的旧值写入缓存
三个策略都存在缺陷,应该先改数据库,再删缓存(不同情况下2,3都有选择)
一般会放弃一定的一致性,追求最终一致。缓存有过期时限,因此会达成最终一致。如果先动缓存,再动数据库,在这个中间如果缓存变了,数据库没变,比如数据库宕机未接收到指令,slave顶上,一方面数据一致性被破坏,一方面业务操作也没成功。反之,如果是缓存机器宕机,当缓存过期以后会从数据库更新,达成最终一致。
mysql等数据库才是系统的根本,redis存储在内存,并不安全
Redis一致性策略
实时同步
实时同步:缓存或DB修改,另一方同步修改
强一致性要求比较高,可采用实时同步:查询时先查询缓存,查询不到再查询数据库,并保存到缓存;更新缓存时先更新数据库,再将缓存设置为过期,更新数据(建议不要更新缓存内容,而是设置缓存过期-删除缓存)
这就是前面推荐的一致性策略:先更新数据库,再删除缓存
实现很简单:
非实时同步
当高并发情况下如热门文章点赞,频繁操作数据库会影响系统性能,就要用非实时的方式
非实时同步:缓存或数据库修改,另一方不需要同步修改
非实时同步:
- 定时任务:设置一定时间间隔更新数据 - 》统计点赞数,每隔一秒同步一次
- 异步队列:将操作存入队列如list,以异步形式执行 -》 统计点赞数,存入消息队列中,服务器空闲就处理消息队列,将点赞数同步
异步队列 => 注册用户:
1. 邮件发送注册成功信息 10秒
2. 手机发送注册成功信息 6秒
3. 用户信息插入数据库 1秒
将上面3个操作存入队列,以异步方式执行,即先执行最重要的第3步
然后后续服务器空闲时再执行1,2步
并发程度高,可以采用异步队列,可用kafka、rocketmq等消息中间件处理消息生产和消费,当然这些是专业的消息队列中间件
轻量级的任务可以用Redis的消息队列,如list队列,lpush、rpop
其他
- 同步工具canal :基于Java实现的一个非常成熟的数据库同步方案,模拟Mysql主从复制
- UDF自定义函数
更多推荐
所有评论(0)