概述

当我们在使用缓存时,如果发生数据变更,那么你需要同时操作缓存和数据库,而它们两个又分属不同的系统,因此无法做到同时操作成功或失败,因此在并发读写下很可能出现缓存与数据库数据不一致的情况

理论上可以通过分布式事务保证同时操作成功或失败,但这会影响系统性能,一般很少使用。虽然没办法做到缓存和数据库强一致,但我们可以让他们的数据尽可能在绝大部分时间内保持一致,并保证最终是一致的

缓存更新设计

一般来说都是采用删除缓存的方式更新缓存,这就涉及到先删除缓存还是先更新数据库的顺序问题了

1. 先删除缓存,后更新数据库

先删除缓存,后更新数据库,如果数据库没有更新成功,下次读缓存发现不存在,则从数据库读取,并重建缓存,此时数据库和缓存依旧保持一致,但还是旧值

高并发下,假设有两个线程并发读写数据,可能会发生以下场景:

  • 线程 A 要更新 X = 2(原值 X = 1)
  • 线程 A 先删除缓存
  • 线程 B 读缓存,发现不存在,从数据库中读取到旧值(X = 1)
  • 线程 A 将新值写入数据库(X = 2)
  • 线程 B 将旧值写入缓存(X = 1)
  • 最终 X 的值在缓存中是 1(旧值),在数据库中是 2(新值),发生不一致

可见,在高并发下这种方式容易出现长时间的脏数据,一般不建议使用

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

先更新数据库,后删除缓存,如果缓存没有删除成功,数据库是最新值,缓存中是旧值,会发生不一致

再看两个线程并发读写数据:

  • 某一时刻缓存中 X 失效不存在(数据库 X = 1)
  • 线程 A 读取数据库,得到旧值(X = 1)
  • 线程 B 更新数据库(X = 2)
  • 线程 B 删除缓存
  • 线程 A 将旧值写入缓存(X = 1)
  • 最终 X 的值在缓存中是 1(旧值),在数据库中是 2(新值),发生不一致

这种方式依旧会出现数据不一致,但概率很低,所以普遍采用这种方式

更多优化

通过前面分析,我们采用了先更新数据库,再删除缓存的方式,还可以进一步优化

1. 保证两步都执行成功

前面提到,无论采用哪种方式,只要第二步失败都会有问题,所以我们需要保证第二步成功执行

一种简单的办法是失败就重试,但这会占用资源,并且立即重试大概率还是失败,所以可以采用异步重试,就是把重试请求写到消息队列,由专门的消费者来重试,直到成功

或者更直接的做法,为了避免第二步执行失败,我们可以把操作缓存这一步,直接放到消息队列中,由消费者来操作缓存,这样做的好处是即使系统重启了,消息也不会丢失

也可以通过订阅数据库变更日志,再操作缓存的方式,以 MySQL 举例,当一条数据发生修改时,MySQL 就会产生一条变更日志(Binlog),我们可以订阅这个日志,拿到具体操作的数据,然后再根据这条数据,去删除对应的缓存。订阅变更日志,目前也有了比较成熟的开源中间件,例如阿里的 canal

2. 延迟双删

一般数据库会使用【主从复制 + 读写分离】提高性能,这种情况下也有可能出现数据不一致:

  • 线程 A 更新主库 X = 2(原值 X = 1)
  • 线程 A 删除缓存
  • 线程 B 查询缓存,没有命中,查询「从库」得到旧值(从库 X = 1)
  • 从库「同步」完成(主从库 X = 2)
  • 线程 B 将「旧值」写入缓存(X = 1)
  • 最终 X 的值在缓存中是 1(旧值),在主从库中是 2(新值),也发生不一致

解决办法就是延时双删,比如线程 A 在更新数据库并删除缓存后,延迟一段时间再删除一次,延迟时间取决于主从复制的延迟时间,一般凭经验估算 1s - 5s 左右

Redis 数据一致性的更多相关文章

  1. redis缓存雪崩、缓存穿透、数据库和redis数据一致性

    一.缓存雪崩 回顾一下我们为什么要用缓存(Redis):减轻数据库压力或尽可能少的访问数据库. 在前面学习我们都知道Redis不可能把所有的数据都缓存起来(内存昂贵且有限),所以Redis需要对数据设 ...

  2. Redis分布式集群几点说道

    原文地址:http://www.cnblogs.com/verrion/p/redis_structure_type_selection.html  Redis分布式集群几点说道 Redis数据量日益 ...

  3. Azure Redis Cache (1) 入门

    <Windows Azure Platform 系列文章目录> Microsoft Azure Redis Cache基于流行的开源Redis Cache. 1.功能 Redis 是一种高 ...

  4. 【Redis】Redis分布式集群几点说道

    Redis数据量日益增大,使用的公司越来越多,不仅用于做缓存,同时趋向于存储这一块,这样必促使集群的发展,各个公司也在收集适合自己的集群方案,目前行业用的比较多的是下面几种集群架构,大部分都是采用分片 ...

  5. redis缓存介绍以及常见问题浅析

    # 没缓存的日子: 对于web来说,是用户量和访问量支持项目技术的更迭和前进.随着服务用户提升.可能会出现一下的一些状况: 页面并发量和访问量并不多,mysql足以支撑自己逻辑业务的发展.那么其实可以 ...

  6. 002 Redis使用及API

    Redis的使用及相关API 1.作用: 提高查询效率 一定程度上可以减轻数据库服务器的冲击压力,从而保护了数据库 //1.是否包含key redisTemplate.hasKey(key) //2. ...

  7. php架构之路

    鉴于最近跟小伙伴聊了很多PHP架构发展方向的问题,相关技术整理了一下,也顺便规划了一下自己的2019年. 一.常用的设计模式以及使用场景 以下是我用到过的   工厂,单例,策略,注册,适配,观察者,原 ...

  8. redis客户端、分布式锁及数据一致性

    Redis Java客户端有很多的开源产品比如Redission.Jedis.lettuce等. Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持:Redis ...

  9. redis系列之数据库与缓存数据一致性解决方案

    redis系列之数据库与缓存数据一致性解决方案 数据库与缓存读写模式策略 写完数据库后是否需要马上更新缓存还是直接删除缓存? (1).如果写数据库的值与更新到缓存值是一样的,不需要经过任何的计算,可以 ...

  10. 高并发下Redis如何保持数据一致性(避免读后写)

    通常意义上我们说读后写是指针对同一个数据的先读后写,且写入的值依赖于读取的值. 关于这个定义要拆成两部分来看,一:同一个数据:二:写依赖于读.(记住这个拆分,后续会用到,记为定义一.定义二)只有当这两 ...

随机推荐

  1. AB32VG1系列之手把手入门与RTC简单评测

    说是评测, 时间仓库仅仅是玩了一下例程而已. 后面有时间打算移植 CoreMark 看看与Cortex-M3的对比. AB32VG1系列之手把手入门与RTC简单评测

  2. C语言从键盘上输入年份和月份,计算并输出这一年的这一月共有多少天。

    #include<stdio.h> void main() { int y, n, s = 0;//定义变量 scanf_s("%d-%d", &y, & ...

  3. 【免费】小傅哥 DDD 开发小册

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 大家好,我是技术UP主小傅哥. 如果在面试的时候,面试官问你DDD是什么,你怎么解释?是不是感 ...

  4. 深入了解Rabbit加密技术:原理、实现与应用

    一.引言 在信息时代,数据安全愈发受到重视,加密技术作为保障信息安全的核心手段,得到了广泛的研究与应用.Rabbit加密技术作为一种新型加密方法,具有较高的安全性和便捷性.本文将对Rabbit加密技术 ...

  5. ssm整合-项目异常处理方案

    项目异常分类: 项目异常处理方案: 需要自定义异常处理 然后在处理器中加入 package com.itheima.controller; import com.itheima.exception.B ...

  6. Nginx的安装与运行

    前言:本文是基于虚拟机上的centOS 7对Nginx的安装,可以使用uname -a查看centOS系统版本,本文用来记录安装nginx的步骤和相关命令,方便日后使用时查看. 去官网https:// ...

  7. 火山引擎ByteHouse基于云原生架构的实时导入探索与实践

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 随着企业降本增效.智能化数据决策需求的增强,传统的商业数据库已经难以满足和响应快速增长的业务诉求.在此背景下,云原 ...

  8. Liunx--centos7服务器上 安装 jenkins,实现持续集成发布

    1.下载并安装jenkins wget -v https://pkg.jenkins.io/redhat-stable/jenkins-2.176.3-1.1.noarch.rpmrpm -ivh j ...

  9. 持续集成Jenkins

    一.简单慨念 持续集成(Continuous integration,简称 CI),随着近几年的发展,持续集成在项目中 得到了广泛的推广和应用. 软件集成就是用一种较好的方式,使多种软件的功能集成到一 ...

  10. 解决vps掉线问题

    解决vps掉线问题 常见现象 在有时候遇到网络或者断电等一系列突发状况时,可能会导致在传输大文件或是好不容易拿到一个session断连了,所以有了这次学习解决这个问题的记录 场景复现 这里直接用kal ...