1.Cache aside pattern

这是最经典的 缓存+数据库 读写模式,操作如下:
①读的时候,先读缓存,缓存没有就读数据库,然后将取出的数据放到缓存,同时返回请求响应。

②更新的时候,先删除缓存,然后更新数据库。

2.为什么是删除缓存,而不是更新缓存呢?

①因为很多时候,缓存中放的并不是简单的从数据中取出来值,可能要进行一个状态的替换,一些数据的计算,还有可能要进行数据的组合等等。

②二八法则,即20%的数据,占用了80%的访问量,这个更新的数据,可能是冷门数据,好久也访问不了不了一次,这样只会占用缓存内存。lazy思想,数据等你第一次要的时候再去加载,避免没必要的内存和时间浪费。

3.最初级的缓存不一致问题以及解决方案

问题 :先修改数据库,再删除缓存,如果缓存删除失败了,那么就会早上数据库和缓存数据不一致。
解决思路 :先删除缓存,再修改数据库,如果删除缓存成功了,如果修改数据库失败了,那么数据库中是旧数据,缓存中是空的,那么数据不会不一致。因为读的时候缓存没有,则读数据库中旧数据,然后更新到缓存中

4.比较复杂的数据不一致问题分析

问题 :数据发生了变更,先删除了缓存,然后要去修改数据库,此时还没修改。
一个请求过来,去读缓存,发现缓存空了,去查询数据库,查到了修改前的旧数据,放到了缓存中。数据变更的程序完成了数据库的修改。
这样就又导致了数据不一致

5.为什么上亿流量高并发场景下,缓存会出现这个问题?

因为只有在对一个数据在并发的进行读写的时候,才可能会出现这种问题。

6.数据库与缓存更新与读取操作进行异步串行化

为了解决上面的并发读写问题,可以考虑将更新和读取操作进行串行化。
①更新数据的时候,根据数据的唯一标识,将操作路由之后,发送到一个jvm内部的队列里面去。

②读取数据的时候,如果发现缓存中没有,那么将从数据库读取数据的操作和更新缓存的操作一起路由到同一个JVM内部的队列中去。

③一个队列对应一个工作线程,然后线程从队列里面去取请求进行操作。

这样就可以将同一个key的操作进行串行化,一个数据变更的操作,先执行,删除缓存,然后再去更新数据库,但是还没完成更新,此时如果一个读请求过来,读到了空的缓存,那么可以先将缓存更新的请求发送到队列中,此时会在队列中积压,然后同步等待缓存更新完成。

这里有一个优化点,一个队列中,其实多个更新缓存请求串在一起是没意义的,因此可以做过滤,如果发现队列中已经有一个更新缓存的请求了,那么就不用再放个更新请求操作进去了,直接等待前面的更新操作请求完成即可。

待那个队列对应的工作线程完成了上一个操作的数据库的修改之后,才会去执行下一个操作,也就是缓存更新的操作,此时会从数据库中读取最新的值,然后写入缓存中。

如果请求还在等待时间范围内,不断轮询发现可以取到值了,那么就直接返回; 如果请求等待的时间超过一定时长,那么这一次直接从数据库中读取当前的旧值。

7.高并发的场景下,该解决方案要注意的问题

①读请求长时间阻塞问题
由于读请求进行了非常轻度的异步化,所以一定要注意读超时的问题,每个读请求必须在超时时间范围内返回。
该解决方案,最大的风险点在于说,可能数据更新很频繁,导致队列中积压了大量更新操作在里面,然后读请求会发生大量的超时,最后导致大量的请求直接走数据库。
务必通过一些模拟真实的测试,看看更新数据的频繁是怎样的。

②读请求并发量过高
还有一个风险,就是突然间大量读请求会在几十毫秒的延时hang在服务上,看服务能不能抗的住,需要多少机器才能抗住最大的极限情况的峰值。
但是因为并不是所有的数据都在同一时间更新,缓存也不会同一时间失效,所以每次可能也就是少数数据的缓存失效了,然后那些数据对应的读请求过来,并发量应该也不会特别大。

③多服务实例部署的请求路由
可能这个服务部署了多个实例,那么必须保证说,执行数据更新操作,以及执行缓存更新操作的请求,都通过nginx服务器路由到相同的服务实例上。

④热点商品的路由问题。导致请求的倾斜
万一某个商品的读写请求特别高,全部打到相同的机器的相同的队列里面去了,可能造成某台机器的压力过大。
就是说,因为只有在商品数据更新的时候才会清空缓存,然后才会导致读写并发,所以更新频率不是太高的话,这个问题的影响并不是特别大。
但是的确可能某些机器的负载会高一些。

关于redis的几件小事(八)缓存与数据库双写时的数据一致性的更多相关文章

  1. Redis使用总结(二、缓存和数据库双写一致性问题)

    首先,缓存由于其高并发和高性能的特性,已经在项目中被广泛使用.在读取缓存方面,大家没啥疑问,都是按照下图的流程来进行业务操作. 但是在更新缓存方面,对于更新完数据库,是更新缓存呢,还是删除缓存.又或者 ...

  2. 面试前必知Redis面试题—缓存雪崩+穿透+缓存与数据库双写一致问题

    今天来分享一下Redis几道常见的面试题: 如何解决缓存雪崩? 如何解决缓存穿透? 如何保证缓存与数据库双写时一致的问题? 一.缓存雪崩 1.1什么是缓存雪崩? 回顾一下我们为什么要用缓存(Redis ...

  3. (转)面试前必知Redis面试题—缓存雪崩+穿透+缓存与数据库双写一致问题

    背景:redis问题在面试过程中经常被问到,对于常见问题一定不能放过. 面试前必知Redis面试题—缓存雪崩+穿透+缓存与数据库双写一致问题 一.缓存雪崩 1.1什么是缓存雪崩? 如果缓存数据设置的过 ...

  4. 关于redis的几件小事(一)redis的使用目的与问题

    1.redis是用来干嘛的? Redis is an open source (BSD licensed), in-memory data structure store, used as a dat ...

  5. K:缓存数据库双写数据一致性方案

    对于缓存和数据库双写,其存在着数据一致性的问题.对于数据一致性要求较高的业务场景,我们通常会选择使用分布式事务(2pc.paxos等)来保证缓存与数据库之间的数据强一致性,但分布式事务的复杂性与对资源 ...

  6. 关于redis的几件小事(七)redis缓存雪崩与穿透

    1.缓存雪崩 (1)什么是缓存雪崩 缓存雪崩指的是在同一时刻,缓存大量失效,导致大量的请求直接到了数据库,数据库压力剧增,引起系统崩溃.可能出现的情况有: ①大量的key设置了相同的过期时间,导致在缓 ...

  7. 关于redis的几件小事(六)redis的持久化

    1.redis持久化的意义 redis持久化的意义,在于 故障恢复 . 如果没有对数据进行持久化,那么如果redis遇到灾难性的故障,就会丢失所有的数据. 如果通过redis的持久化机制将数据持久化到 ...

  8. 关于redis的几件小事(四)redis的过期策略以及内存淘汰机制

    1.数据为什么会过期? 首先,要明白redis是用来做数据缓存的,不是用来做数据存储的(当然也可以当数据库用),所以数据时候过期的,过期的数据就不见了,过期主要有两种情况, ①在设置缓存数据时制定了过 ...

  9. 关于redis的几件小事(三)redis的数据类型与使用场景

    1.string 这是最基本的类型了,就是普通的set和get,做简单的kv缓存. 2.hash 这个是类似map的一种结构,这个一般就是可以将结构化的数据,比如一个对象(前提是这个对象没嵌套其他的对 ...

随机推荐

  1. 【实用软件】GIF屏幕录制软件-ScreenToGif (在GitHub开源)

    抛个问题,自问自答 ScreenToGif 经常会遇到一些场景,需要你向别人展示一些操作或是效果——例如告诉别人某某软件的配置步骤啊.刚某个动画效果怎么样啊.某某电影里面的一个镜头多么经典啊.打得大快 ...

  2. Redis内存满了的几种解决方法(内存淘汰策略与Redis集群)

    1,增加内存: 2,使用内存淘汰策略. 3,Redis集群. 重点介绍下23: 第2点: 我们知道,redis设置配置文件的maxmemory参数,可以控制其最大可用内存大小(字节). 那么当所需内存 ...

  3. python 装饰器 (test = submit(test))

    两层的装饰器,这里对于register不需要进行输入 usename, passwd = 'alex', 'abc123' def register(func): def wrapper(*args, ...

  4. 使用Laravel首次运行出现 No application encryption key has been specified.

    先观察Laravel根目录下是否有 .env文件,有则看1,无则看2 1.若直接报500错误: 输入命令: php artisan key:generate 2.若文件根目录下没有 .env文件 (1 ...

  5. 如何在gradle项目中添加额外非开源jar包并提交代码

    前提:项目开发中,遇到一个地方需要用到公司自定义的jar包,然后要放到代码里又不方便提交到私服 具体实施: 首先在项目中增加一个 libs目录,然后把这种非开源又不在私服上的jar包扔进去, 然后打开 ...

  6. springmvc+mybatis多数据源切换

    前文:之前练习SSM时配置的都是单数据源,现在项目需求多数据源,所以自己查阅了以下资料,在controller中手动切换数据源成功,以下的配置细节. 实际上应该在dao层进行注解的方式切换,使用AOP ...

  7. spring_quartz的实现

    一.在spring配置文件中引用对应的定时任务配置文件 二.定义定时任务的业务代码 三.配置定时任务配置文件spring-quartz.xml <?xml version="1.0&q ...

  8. 国内npm源

    永久使用lnpm config set registry https://registry.npm.taobao.org // 配置后可通过下面方式来验证是否成功 npm config get reg ...

  9. 利用java执行shell脚本

    BPMN中存在由系统执行的脚本任务,shell脚本任务也是该系统任务脚本中的一种,利用的也是由java执行shell脚本. 代码中的ProcessBuilder类,为java.lang.Process ...

  10. flannel下k8s pod及容器无法跨主机互通问题

    参照文档    https://blog.csdn.net/a610786189/article/details/80340556 https://blog.csdn.net/weixin_43092 ...