一文通关Redis、MySQL数据一致性

背景:实习中mt让用延时双删处理DB和redis数据一致性,但是面试说不出来,脑子里一团浆糊,这篇从旁路缓存、延时双删的角度把数据库缓存不一致的情况全列举一遍,并探讨这个方案的合理性

需要知道的知识

  • 在遭遇读写并发时需要用到此内容,在公司中的场景是如连续两次修改用户名,显示的还是第一次修改的结果。其实可以理解为写-写-读并发了
  • 旁路缓存:针对写操作,先更新数据库记录,再删除缓存。
  • 延时双删:针对写操作,更新数据库记录->删除缓存,延时一会再删除一次缓存
  • 缓存的写入远远快于数据库的写入
  • 读操作:先读取缓存中数据,缓存中没有再读数据库,并重建缓存
  • 不论读操作还是写操作,都是可以被打断的,如写操作更新完数据库,还未删除缓存时候,可能会插入一段读操作,造成问题。

旁路缓存和换个顺序的旁路缓存

经典旁路缓存可以很容易的画出来问题所在:


此时再读,就会读到20,但是数据库中是30,这种情况其实还好,因为重建缓存并不慢
下面这种就比较糟糕了,也是实际中不会考虑使用的,就是先删除缓存,再写数据库:

如上,更新DB是件很慢的事,所以这种情况出问题的概率是比第一种要大的。
这里也是第一个面试考点:为什么不更新缓存而要删除
1)删除一个数据,相比更新一个数据更加轻量级,不需要判断缓存中有没有对应数据。
2)在实际业务中,缓存的数据可能不是直接来自数据库表,也许来自多张底层数据表的聚合。

为什么先删库,后删缓存:
因为可以大幅降低不一致时间,且如果更新数据库失败,缓存并没有删除,只需要回滚数据库即可,反之我们数据库和缓存都需要回滚,而缓存的回滚是我们不愿意进行的。
时序图如图:

而写库和删缓存之间的时间是很少的,所以后删缓存一定是效率较高的

延时双删

解决的就上面经典旁路缓存的问题:

这样原先的缓存DB不一致时间为"重建缓存为20"~缓存失效。
现在的不一致时间为"重建缓存为20"~删除缓存
大大降低了不一致的时间
代码如下:

@PutMapping("/updateTitle/{id}")
    public ResponseResult updateTitle(@RequestBody String title,@PathVariable Integer id) throws InterruptedException {
        //删缓存
        redisCache.deleteObject(id.toString());
        //更新库
        Article article = articleService.getById(id);
        article.setTitle(title);
        articleService.updateById(article);
        
        //下发定时任务
        //再次删缓存
        delayJob(id);
        return ResponseResult.okResult();
    }

    public void delayJob(Integer id) {
        Timer timer = new Timer();
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                if (!executed) {
                    System.out.println("执行定时任务");
                    redisCache.deleteObject(id.toString());
                }
            }
        };
        timer.schedule(task,2000);
    }
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值