Redis - CAP原则 => 缓存与数据库的一致性

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. 先更新数据库,再更新缓存

  2. 先删除缓存,再更新数据库

  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. 邮件发送注册成功信息  102. 手机发送注册成功信息  63. 用户信息插入数据库 1秒
将上面3个操作存入队列,以异步方式执行,即先执行最重要的第3步
然后后续服务器空闲时再执行1,2

并发程度高,可以采用异步队列,可用kafka、rocketmq等消息中间件处理消息生产和消费,当然这些是专业的消息队列中间件

轻量级的任务可以用Redis的消息队列,如list队列,lpush、rpop

其他

  • 同步工具canal :基于Java实现的一个非常成熟的数据库同步方案,模拟Mysql主从复制

在这里插入图片描述

canal项目地址

  • UDF自定义函数
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值