Redis与MySql数据一致性问题

1.数据为什么不一致

1.单库情况下发生不一致的情况

同一时刻发生了并发读写请求,例如A是写,B是读

  1. A请求发送了一个写的操作到服务端,第一步淘汰缓存,但是因为一些原因卡主了
  2. B请求发送一个读操作,读取缓存,因为淘汰缓存,所以B会请求数据库,但是因为A还没有更新,读取的是脏数据
  3. A请求执行完成,写操作完成。但是缓存中还是旧数据,后面的读操作读到的将都会是旧数据,这就造成了数据的不一致

2.主从同步、读写分离的情况下,读从库而产生数据不一致

  1. A发送一个写操作到服务端,第一步先淘汰缓存
  2. A请求写主数据库,完成了数据的更新
  3. B发起一个读操作,读缓存,缓存淘汰,会从从数据库中读取数据,
  4. 但是可能由于网络波动或其他因素,主从同步还没同步成功,所以B就是读出脏数据,放到缓存中。造成数据的不一致。

根本原因:就是主从同步延迟所导致的

二、解决方法

1.MySql持久化数据,Redis只读数据

redis启动之后,从数据库加载数据

读请求
不要求强一致性的读请求,走redis,要求强一致性的直接从mysql读取

写请求
数据首先都写到数据库,之后更新redis(先写redis再写mysql,如果写入失败事务回滚会造成redis中存在脏数据)

优化
在更新数据库前后都进行删除缓存操作,并且设置合理的超时时间。

(1) 先删除缓存
(2)更新数据库
(3)休眠500毫秒
(4)再次删除缓存

2.Mysql和Redis处理不同的数据类型
MySQL处理实时性数据,例如金融数据、交易数据

Redis处理实时性要求不高的数据,例如网站最热贴排行榜,好友列表等

在并发不高的情况下,读操作优先读取redis,不存在的话就去访问MySQL,并把读到的数据写回Redis中;写操作的话,直接写MySQL,成功后再写入Redis(可以在MySQL端定义CRUD触发器,在触发CRUD操作后写数据到Redis,也可以在Redis端解析binlog,再做相应的操作)

在并发高的情况下,读操作和上面一样,写操作是异步写,写入Redis后直接返回,然后定期写入MySQL

几个例子:

1.当更新数据时,如更新某商品的库存,当前商品的库存是100,现在要更新为99,先更新数据库更改成99,然后删除缓存,发现删除缓存失败了,这意味着数据库存的是99,而缓存是100,这导致数据库和缓存不一致。

解决方法:
这种情况应该是先删除缓存,然后在更新数据库,如果删除缓存失败,那就不要更新数据库,如果说删除缓存成功,而更新数据库失败,那查询的时候只是从数据库里查了旧的数据而已,这样就能保持数据库与缓存的一致性。

2.在高并发的情况下,如果当删除完缓存的时候,这时去更新数据库,但还没有更新完,另外一个请求来查询数据,发现缓存里没有,就去数据库里查,还是以上面商品库存为例,如果数据库中产品的库存是100,那么查询到的库存是100,然后插入缓存,插入完缓存后,原来那个更新数据库的线程把数据库更新为了99,导致数据库与缓存不一致的情况

解决方法:
遇到这种情况,可以用队列的去解决这个问,创建几个队列,如20个,根据商品的ID去做hash值,然后对队列个数取摸,当有数据更新请求时,先把它丢到队列里去,当更新完后在从队列里去除,如果在更新的过程中,遇到以上场景,先去缓存里看下有没有数据,如果没有,可以先去队列里看是否有相同商品ID在做更新,如果有也把查询的请求发送到队列里去,然后同步等待缓存更新完成。
这里有一个优化点,如果发现队列里有一个查询请求了,那么就不要放新的查询操作进去了,用一个while(true)循环去查询缓存,循环个200MS左右,如果缓存里还没有则直接取数据库的旧数据,一般情况下是可以取到的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值