当执行写操作后,需要保证从缓存读取到的数据与数据库中持久化的数据是一致的,因此需要对缓存进行更新。

因为涉及到数据库和缓存两步操作,难以保证更新的原子性。

在设计更新策略时,我们需要考虑多个方面的问题:

  • 对系统吞吐量的影响:比如更新缓存策略产生的数据库负载小于删除缓存策略的负载
  • 并发安全性:并发读写时某些异常操作顺序可能造成数据不一致,如缓存中长期保存过时数据
  • 更新失败的影响:若某个操作失败,如何对业务影响降到最小
  • 检测和修复故障的难度: 操作失败导致的错误会在日志留下详细的记录容易检测和修复。并发问题导致的数据错误没有明显的痕迹难以发现,且在流量高峰期更容易产生并发错误产生的业务风险较大。

更新缓存有两种方式:

  • 删除失效缓存: 读取时会因为未命中缓存而从数据库中读取新的数据并更新到缓存中
  • 更新缓存: 直接将新的数据写入缓存覆盖过期数据

更新缓存和更新数据库有两种顺序:

  • 先数据库后缓存
  • 先缓存后数据库

两两组合共有四种更新策略,现在我们逐一进行分析。

并发问题通常由于后开始的线程却先完成操作导致,我们把这种现象称为“抢跑”。 下面我们逐一分析四种策略中“抢跑”带来的错误。

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

若数据库更新成功,删除缓存操作失败,则此后读到的都是缓存中过期的数据,造成不一致问题。

可能发生的并发错误:

时间 线程A 线程B 数据库 缓存
1 缓存失效 v1 null
2 从数据库读取v1 v1 null
3 更新数据库 v2 null
4 删除缓存 v2 null
5 写入缓存 v2 v1

先更新数据库,再更新缓存

同删除缓存策略一样,若数据库更新成功缓存更新失败则会造成数据不一致问题。

可能发生的并发错误:

时间 线程A 线程B 数据库 缓存
0 v0 v0
1 更新数据库为 v1 v1 v0
2 更新数据库为 v2 v2 v0
3 更新缓存为 v2 v2 v2
4 更新缓存为 v1 v2 v1

当两个写线程发生冲突时,可以通过比较数据版本方式避免线程A写入旧的数据。

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

可能发生的并发错误:

时间 线程A 线程B 数据库 缓存
1 删除缓存 v1 null
2 缓存失效 v1 null
3 从数据库读取v1 v1 null
4 更新数据库为v2 v2 null
5 将v1写入缓存 v2 v1

先更新缓存,再更新数据库

若缓存更新成功数据库更新失败, 则此后读到的都是未持久化的数据。因为缓存中的数据是易失的,这种状态非常危险。

因为数据库因为键约束导致写入失败的可能性较高,所以这种策略风险较大。

可能发生的并发错误:

时间 线程A 线程B 数据库 缓存
0 v0 v0
1 更新缓存为 v1 v0 v1
2 更新缓存为 v2 v0 v2
3 更新数据库为 v2 v2 v2
4 更新数据库为 v1 v1 v2

异步更新

双写更新的逻辑复杂,一致性问题较多。现在我们可以采用订阅数据库更新的方式来更新缓存。

阿里巴巴开源了mysql数据库binlog的增量订阅和消费组件 - canal

我们可以采用API服务器只写入数据库,而另一个线程订阅数据库 binlog 增量进行缓存更新的策略。

这种策略存在和先更新数据库后删除缓存类似的并发问题:

时间 读线程 写线程 异步线程 数据库 缓存
1 缓存失效 v1 null
2 从数据库读取v1 v1 null
3 更新数据库为v2 v2 null
4 删除缓存/更新缓存 v2 null
5 写入缓存 v2 v1

这个问题同样可以采用异步线程更新缓存,且写入缓存时比较数据版本的方法来解决。

Redis 缓存更新一致性的更多相关文章

  1. (redis缓存更新策略)postgres 9.4.1 && redis 3.7.0 && redis_fdw_REL9_4_STABLE

    首先下载redis_fdw,这里要注意下载的版本.(https://github.com/pg-redis-fdw/redis_fdw) 一开始,我下载了REL9_4_STABLE_pre2.8版本, ...

  2. SpringBoot缓存管理(二) 整合Redis缓存实现

    SpringBoot支持的缓存组件 在SpringBoot中,数据的缓存管理存储依赖于Spring框架中cache相关的org.springframework.cache.Cache和org.spri ...

  3. Redis双写一致性与缓存更新策略

    一.双写一致性 双写一致性,也就是说 Redis 和 mysql 数据同步 双写一致性数据同步的方案有: 1.先更新数据库,再更新缓存 这个方案一般不用: 因为当有两个请求AB先后更新数据库后,A应该 ...

  4. Redis缓存和数据库一致性问题

    工作中,经常会遇到缓存和数据库数据一致性问题.从理论上设置过期时间,是保证最终一致性的解决方案.这种方案下,我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力即可 ...

  5. Redis缓存如何保证一致性

    为什么使用Redis做缓存 MySQL缺点 单机连接数目有限 对数据进行写速度慢 Redis优点 内存操作数据速度快 IO复用,速度快 单线程模型,避免线程切换带来的开销,速度快 一致性问题 读数据的 ...

  6. Redis缓存穿透、击穿、雪崩,数据库与缓存一致性

    Redis作为高性能非关系型(NoSQL)的键值对数据库,受到了广大用户的喜爱和使用,大家在项目中都用到了Redis来做数据缓存,但有些问题我们在使用中不得不考虑,其中典型的问题就是:缓存穿透.缓存雪 ...

  7. Redis系列十:缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级

    一.缓存雪崩 缓存雪崩我们可以简单的理解为:由于原有缓存失效,新缓存未到期间(例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,而 ...

  8. redis缓存与数据库一致性问题

    一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说如果你的系统不是严格要求 “缓存+数据库” 必须保持一致性的话,最好不要做这个方案,即:读请求和写请求串行化,串到一个内存队列里去. ...

  9. Redis缓存雪崩、缓存穿透、缓存击穿、缓存降级、缓存预热、缓存更新

    Redis缓存能够有效地加速应用的读写速度,就DB来说,Redis成绩已经很惊人了,且不说memcachedb和Tokyo Cabinet之流,就说原版的memcached,速度似乎也只能达到这个级别 ...

随机推荐

  1. Random Forest And Extra Trees

    随机森林 我们对使用决策树随机取样的集成学习有个形象的名字–随机森林. scikit-learn 中封装的随机森林,在决策树的节点划分上,在随机的特征子集上寻找最优划分特征. import numpy ...

  2. 使用powerdesigner进行数据库设计

    powerdesigner安装破解文件:链接:https://pan.baidu.com/s/1oKAdUqTKElQ9d86FV-SDTQ 密码:l4y5 基本操作参考:1.PowerDesigne ...

  3. nexus7入手

    平板一直关注了很久了,关键是不知道平板对我来说,拿它来做什么用.所以,一直也就是关注,也没有决心买了. 终于这次出手了,N7,到货了! 照片是原生的android系统,不习惯,不习惯,直接用刷机精灵, ...

  4. C++走向远洋——24(项目一,三角形,复制构造函数)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:sanjiaoxing.cpp * 作者:常轩 * 微信公众号: ...

  5. py面向对象编程基础

    '''类:一类事物的抽象,用于定义抽象类型 实例:类的单个实际描述 如:人是一个类,而单个人是一个实例 用class来创建一个类,调用一个类来创建一个实例'''class Person: passxi ...

  6. 峰哥说技术:07-SpringBoot 正好Thymeleaf视图

    Spring Boot深度课程系列 峰哥说技术—2020庚子年重磅推出.战胜病毒.我们在行动 07  峰哥说技术:SpringBoot 正好Thymeleaf视图 Spring Boot视图介绍 虽然 ...

  7. A. New Building for SIS Codeforce

    You are looking at the floor plan of the Summer Informatics School's new building. You were tasked w ...

  8. spring boot整合memcache

    1.导入memcached客户端jar包 <dependency> <groupId>com.whalin</groupId> <artifactId> ...

  9. VUE三 vue-router(路由)详解

    前端路由 根据不同的 url 地址展示不同的内容或页面,无需依赖服务器根据不同URL进行页面展示操作 优点 用户体验好,不需要每次都从服务器全部获取,快速展现给用户 缺点 使用浏览器的前进,后退键的时 ...

  10. H5系列一、静态页面总结

    1.img父标签设置高度,如果容器没有设置高度的话,图片会默认把容器底部撑大几像素 -- 大概3px,给容器设置高度. 2.input标记换行后默认有一个间隙,设置float属性.input标记默认还 ...