精华内容
下载资源
问答
  • redis缓存和数据库都保存了数据信息,当我们更新了数据库的数据时,应该如何保证redis和数据库的数据同步呢?当前比较常用的是双写模式和失效模式。 1.双写模式 双写模式:每次修改数据库的数据后,然后在更新redis...


            redis缓存和数据库都保存了数据信息,当我们更新了数据库的数据时,应该如何保证redis和数据库的数据同步呢?当前比较常用的是双写模式和失效模式。

    1.双写模式

    双写模式:每次修改数据库的数据后,然后在更新redis中的数据,使用了两次写操作,称为双写模式

    双写模式存在的问题:高并发下有可能会有脏数据

    场景:

    1. 线程A在修改数据库之后、更新缓存之前,由于其他原因,cpu时间片被线程B抢到。
    2. 线程B改库、刷缓存一气呵成。
    3. 此时线程A再拿到cpu,执行更新缓存操作,那么此时缓存中的数据更新的就是线程A的脏数据,
      但其实我们想要的是线程B最新修改的数据,这样就出现了双写模式下不一致的情况,产生了脏数据!

    原理如下图:
    在这里插入图片描述


    2.失效模式

    失效模式:每次修改数据库的数据后,删除redis中缓存的数据,当有redis查询请求时,会先去数据库查询,然后更新到redis中,后续继续请求redis。更新时删除缓存数据,称为失效模式

    失效模式存在的问题:同样会存在脏数据问题

    场景一:先改数据库,再删redis

    1. 线程A修改数据库数据,并删除了缓存中对应的数据。
    2. 线程B要获取数据,发现缓存中没有,就去数据库查到线程A修改后的数据,然后准备更新缓存,但在更新之前,由于其他原因,cpu时间片被线程C抢到了,
    3. 此时线程C也修改了数据库数据,并删除已经为空的缓存。
    4. 然后cpu又被线程B抢到,线程B继续执行更新缓存操作,此时缓存中更新的是线程A修改后的数据,但其实我们想要的是线程C修改后的数据,这就产生了数据不一致的情况!!

    场景二:先删redis,再改数据库!

    1. 以减库存为例,假设库存量为100。线程A要减库存,会先删除redis数据,再对数据库中的库存量执行减 1 操作。
    2. 当线程A删除完redis数据, 准备执行减 1 操作时,cpu时间片被线程B抢占
    3. 线程B要查询库存,此时查到的还是原来的库存量(100),因为此时线程A还没来得及执行减 1 操作。然后线程B把原来的库存量100更新到redis
    4. 线程B执行完毕后,cpu时间片又回到线程A手中,线程A继续执行减 1 操作,执行完毕,数据库库存量为99,与redis中的100不相等,数据不一致!

    2.1 延迟双删

            延迟双删是在失效模式的基础上,在删除reids缓存时,让程序睡眠几十毫秒,再次执行删除缓存操作,可有效预防失效模式中缓存不一致问题,但是并不推荐。因为数据不一致问题本来就是极少情况发生的,如果使用延时双删,那么大部分正常的请求都会被阻塞几十毫秒,系统性能下降,显然得不偿失!


    3.缓存一致性解决方案

            如上所示,无论是双写模式还是失效模式,都无法完美解决缓存一致性问题!但在不同的业务场景对数据一致性的要求也不同,并非所有场景都需要数据强一致性,我们要根据实际业务场景来分析,具体解决方案如下所示:

    1. 对于并发很小的数据,比如个人信息、用户数据等。这些数据在使用双写或者失效模式后,由于并发量小,根本不需要考虑缓存一致性问题。可以给缓存数据加上过期时间,每隔一段时间触发读操作的主动更新即可!
    2. 如果并发量很高,但业务上能容忍短时间的缓存数据不一致,比如商品名称,商品分类三级菜单等。为缓存数据加上过期时间依然可以解决大部分业务对于缓存的要求。
    3. 如果并发量很高,且无法容忍数据不一致,比如库存。可以使用分布式锁来保证一致性!但也不用读写操作都加一把重量级的分布式锁,使用轻量级读写锁即可,通过添加读写锁保证写数据时读写都阻塞,仅读数据时相当于无锁!
    4. 还有一种方案,但代价也挺大。方案:所有的对库存的增、删、改、查操作都通过nginx路由到集群中某一台固定的机器上,在这台机器上定义一个内存队列。然后对库存的操作类型进行判断,每一个增、删操作放入队列,读操作不放入(防止队列元素过多)。然后从队列中逐个取出增、删操作并执行,读操作需要等到队列中没有增、删操作时才可执行! 这种方案也可以阻止并发带来的数据不一致,但却降低了系统可用性!

    3.1 redisson读写锁的底层原理

            //获取读写锁
            RReadWriteLock readWriteLock = redisson.getReadWriteLock("123");
            
            //写锁
            RLock writeLock = readWriteLock.writeLock();
            writeLock.lock();
            System.out.println(111);
            writeLock.unlock();
            
    		//读锁
            RLock readLock = readWriteLock.readLock();
            readLock.lock();
            System.out.println(111);
            readLock.unlock();
    

            redisson的readWriteLock其实和redisson的lock差不多,只不过加了个mode标识。底层的lua脚本根据mode的值,区分读写逻辑,读写锁与lock一样,都是可重入锁!

    ①:如果加的是读锁,mode = read,并发读数据不阻塞,写读互斥!

            return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,
            						//增加mode属性
                                    "local mode = redis.call('hget', KEYS[1], 'mode'); " +
                                    "if (mode == false) then " +
                                      "redis.call('hset', KEYS[1], 'mode', 'read'); " +
                                      "redis.call('hset', KEYS[1], ARGV[2], 1); " +
                                      "redis.call('set', KEYS[2] .. ':1', 1); " +
                                      "redis.call('pexpire', KEYS[2] .. ':1', ARGV[1]); " +
                                      "redis.call('pexpire', KEYS[1], ARGV[1]); " +
                                      "return nil; " +
                                    "end; " +
                                    //如果mode为读,其他的读不阻塞
                                    "if (mode == 'read') or (mode == 'write' and redis.call('hexists', KEYS[1], ARGV[3]) == 1) then " +
                                      "local ind = redis.call('hincrby', KEYS[1], ARGV[2], 1); " + 
                                      "local key = KEYS[2] .. ':' .. ind;" +
                                      "redis.call('set', key, 1); " +
                                      "redis.call('pexpire', key, ARGV[1]); " +
                                      "redis.call('pexpire', KEYS[1], ARGV[1]); " +
                                      "return nil; " +
                                    "end;" +
                                    "return redis.call('pttl', KEYS[1]);",
                            Arrays.<Object>asList(getName(), getReadWriteTimeoutNamePrefix(threadId)), 
                            internalLockLeaseTime, getLockName(threadId), getWriteLockName(threadId));
    

    ②:如果加的是写锁,mode = write,并发写数据,其他读写都阻塞

            return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,
            					//增加mode属性
                                "local mode = redis.call('hget', KEYS[1], 'mode'); " +
                                "if (mode == false) then " +
                                      "redis.call('hset', KEYS[1], 'mode', 'write'); " +
                                      "redis.call('hset', KEYS[1], ARGV[2], 1); " +
                                      "redis.call('pexpire', KEYS[1], ARGV[1]); " +
                                      "return nil; " +
                                  "end; " +
                                  //如果mode为写,判断haxists,使其他的读写都阻塞
                                  "if (mode == 'write') then " +
                                      "if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
                                          "redis.call('hincrby', KEYS[1], ARGV[2], 1); " + 
                                          "local currentExpire = redis.call('pttl', KEYS[1]); " +
                                          "redis.call('pexpire', KEYS[1], currentExpire + ARGV[1]); " +
                                          "return nil; " +
                                      "end; " +
                                    "end;" +
                                    "return redis.call('pttl', KEYS[1]);",
                            Arrays.<Object>asList(getName()), 
                            internalLockLeaseTime, getLockName(threadId));
    

    3.2 使用Canal解决缓存一致性问题

    Canal使我们的业务代码只关注于数据库的交互,不用管redis缓存的问题,因为Canal可以订阅mysql数据库的每一次更新,只要mysql数据库有更新,Canal就会把数据同步到redis

    使用Canal注意:

    • ①:mysql要开启binlog日志,才能被Canal所监控
    • ②:使用Canal在业务代码中执行修改缓存就可以
    • ③:使用Canal需要额外增加Canal中间件,加重系统复杂度。

    Canal操作流程图
    在这里插入图片描述

    总结:

            以上我们针对的都是读多写少的情况加入缓存提高性能,如果写多读多的情况又不能容忍缓存数据不一致,那就没必要加缓存了,可以直接操作数据库! 放入缓存的数据应该是对实时性、一致性要求不是很高的数据。切记不要为了用缓存,同时又要保证绝对的一致性做大量的过度设计和控制,增加系统复杂性!

    展开全文
  • 首先,缓存由于其高并发和高性能的特性,已经在项目中被广泛使用。...目前没有一篇全面的博客,对这几种方案进行解析。于是博主战战兢兢,顶着被大家喷的风险,写了这篇文章。  文章结构  本文由以下三个部...

    首先,缓存由于其高并发和高性能的特性,已经在项目中被广泛使用。在读取缓存方面,大家没啥疑问,都是按照下图的流程来进行业务操作。

    分布式之数据库和缓存双写一致性方案解析

      但是在更新缓存方面,对于更新完数据库,是更新缓存呢,还是删除缓存。又或者是先删除缓存,再更新数据库,其实大家存在很大的争议。目前没有一篇全面的博客,对这几种方案进行解析。于是博主战战兢兢,顶着被大家喷的风险,写了这篇文章。

      文章结构

      本文由以下三个部分组成1、讲解缓存更新策略2、对每种策略进行缺点分析3、针对缺点给出改进方案

      正文

      先做一个说明,从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。这种方案下,我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力即可。也就是说如果数据库写成功,缓存更新失败,那么只要到达过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存。因此,接下来讨论的思路不依赖于给缓存设置过期时间这个方案。在这里,我们讨论三种更新策略:

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

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

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

      应该没人问我,为什么没有先更新缓存,再更新数据库这种策略。

      (1)先更新数据库,再更新缓存

      这套方案,大家是普遍反对的。为什么呢?有如下两点原因。原因一(线程安全角度)同时有请求A和请求B进行更新操作,那么会出现(1)线程A更新了数据库(2)线程B更新了数据库(3)线程B更新了缓存(4)线程A更新了缓存这就出现请求A更新缓存应该比请求B更新缓存早才对,但是因为网络等原因,B却比A更早更新了缓存。这就导致了脏数据,因此不考虑。原因二(业务场景角度)有如下两点:(1)如果你是一个写数据库场景比较多,而读数据场景比较少的业务需求,采用这种方案就会导致,数据压根还没读到,缓存就被频繁的更新,浪费性能。(2)如果你写入数据库的值,并不是直接写入缓存的,而是要经过一系列复杂的计算再写入缓存。那么,每次写入数据库后,都再次计算写入缓存的值,无疑是浪费性能的。显然,删除缓存更为适合。

      接下来讨论的就是争议最大的,先删缓存,再更新数据库。还是先更新数据库,再删缓存的问题。

      (2)先删缓存,再更新数据库

      该方案会导致不一致的原因是。同时有一个请求A进行更新操作,另一个请求B进行查询操作。那么会出现如下情形:(1)请求A进行写操作,删除缓存(2)请求B查询发现缓存不存在(3)请求B去数据库查询得到旧值(4)请求B将旧值写入缓存(5)请求A将新值写入数据库上述情况就会导致不一致的情形出现。而且,如果不采用给缓存设置过期时间策略,该数据永远都是脏数据。那么,如何解决呢?采用延时双删策略伪代码如下

      public void write(String key,Object data){

      redis.delKey(key);

      db.updateData(data);

      Thread.sleep(1000);

      redis.delKey(key);

      }

      转化为中文描述就是(1)先淘汰缓存(2)再写数据库(这两步和原来一样)(3)休眠1秒,再次淘汰缓存这么做,可以将1秒内所造成的缓存脏数据,再次删除。那么,这个1秒怎么确定的,具体该休眠多久呢?针对上面的情形,读者应该自行评估自己的项目的读数据业务逻辑的耗时。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上,加几百ms即可。这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。如果你用了mysql的读写分离架构怎么办?ok,在这种情况下,造成数据不一致的原因如下,还是两个请求,一个请求A进行更新操作,另一个请求B进行查询操作。(1)请求A进行写操作,删除缓存(2)请求A将数据写入数据库了,(3)请求B查询缓存发现,缓存没有值(4)请求B去从库查询,这时,还没有完成主从同步,因此查询到的是旧值(5)请求B将旧值写入缓存(6)数据库完成主从同步,从库变为新值上述情形,就是数据不一致的原因。还是使用双删延时策略。只是,睡眠时间修改为在主从同步的延时时间基础上,加几百ms。采用这种同步淘汰策略,吞吐量降低怎么办?ok,那就将第二次删除作为异步的。自己起一个线程,异步删除。这样,写的请求就不用沉睡一段时间后了,再返回。这么做,加大吞吐量。第二次删除,如果删除失败怎么办?这是个非常好的问题,因为第二次删除失败,就会出现如下情形。还是有两个请求,一个请求A进行更新操作,另一个请求B进行查询操作,为了方便,假设是单库:(1)请求A进行写操作,删除缓存(2)请求B查询发现缓存不存在(3)请求B去数据库查询得到旧值(4)请求B将旧值写入缓存(5)请求A将新值写入数据库(6)请求A试图去删除请求B写入对缓存值,结果失败了。ok,这也就是说。如果第二次删除缓存失败,会再次出现缓存和数据库不一致的问题。如何解决呢?具体解决方案,且看博主对第(3)种更新策略的解析。

      (3)先更新数据库,再删缓存

      首先,先说一下。老外提出了一个缓存更新套路,名为《Cache-Aside pattern》。其中就指出

      失效:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。

      命中:应用程序从cache中取数据,取到后返回。

      更新:先把数据存到数据库中,成功后,再让缓存失效。

      另外,知名社交网站facebook也在论文《Scaling Memcache at Facebook》中提出,他们用的也是先更新数据库,再删缓存的策略。

      这种情况不存在并发问题么?

      不是的。假设这会有两个请求,一个请求A做查询操作,一个请求B做更新操作,那么会有如下情形产生

      (1)缓存刚好失效

      (2)请求A查询数据库,得一个旧值

      (3)请求B将新值写入数据库

      (4)请求B删除缓存

      (5)请求A将查到的旧值写入缓存

      ok,如果发生上述情况,确实是会发生脏数据。

      然而,发生这种情况的概率又有多少呢?

      发生上述情况有一个先天性条件,就是步骤(3)的写数据库操作比步骤(2)的读数据库操作耗时更短,才有可能使得步骤(4)先于步骤(5)。可是,大家想想,数据库的读操作的速度远快于写操作的(不然做读写分离干嘛,做读写分离的意义就是因为读操作比较快,耗资源少),因此步骤(3)耗时比步骤(2)更短,这一情形很难出现。假设,有人非要抬杠,有强迫症,一定要解决怎么办?

      如何解决上述并发问题?首先,给缓存设有效时间是一种方案。其次,采用策略(2)里给出的异步延时删除策略,保证读请求完成以后,再进行删除操作。

      还有其他造成不一致的原因么?有的,这也是缓存更新策略(2)和缓存更新策略(3)都存在的一个问题,如果删缓存失败了怎么办,那不是会有不一致的情况出现么。比如一个写数据请求,然后写入数据库了,删缓存失败了,这会就出现不一致的情况了。这也是缓存更新策略(2)里留下的最后一个疑问。

      如何解决?提供一个保障的重试机制即可,这里给出两套方案。方案一:如下图所示

    分布式之数据库和缓存双写一致性方案解析

      流程如下所示(1)更新数据库数据;(2)缓存因为种种问题删除失败(3)将需要删除的key发送至消息队列(4)自己消费消息,获得需要删除的key(5)继续重试删除操作,直到成功然而,该方案有一个缺点,对业务线代码造成大量的侵入。于是有了方案二,在方案二中,启动一个订阅程序去订阅数据库的binlog,获得需要操作的数据。在应用程序中,另起一段程序,获得这个订阅程序传来的信息,进行删除缓存操作。

      方案二:

    分布式之数据库和缓存双写一致性方案解析

      流程如下图所示:(1)更新数据库数据(2)数据库会将操作信息写入binlog日志当中(3)订阅程序提取出所需要的数据以及key(4)另起一段非业务代码,获得该信息(5)尝试删除缓存操作,发现删除失败(6)将这些信息发送至消息队列(7)重新从消息队列中获得该数据,重试操作。

      备注说明:上述的订阅binlog程序在mysql中有现成的中间件叫canal,可以完成订阅binlog日志的功能。至于oracle中,博主目前不知道有没有现成中间件可以使用。另外,重试机制,博主是采用的是消息队列的方式。如果对一致性要求不是很高,直接在程序中另起一个线程,每隔一段时间去重试即可,这些大家可以灵活自由发挥,只是提供一个思路。

      总结

      本文其实是对目前互联网中已有的一致性方案,进行了一个总结。对于先删缓存,再更新数据库的更新策略,还有方案提出维护一个内存队列的方式,博主看了一下,觉得实现异常复杂,没有必要,因此没有必要在文中给出。最后,希望大家有所收获。

    展开全文
  • 事务解决的也是数据一致性的问题(业务层与数据库层面的一致性),看来这个也跟数据库的事务没有关系。 4、我们可以采用队列来实现,read的时候判断当前队列中是否存在删除操作,如果存在直接等待,如果没有直接...
  • 分布式缓存一致性问题解决方案

    千次阅读 2020-08-22 21:27:03
    该文章主要是来自于通用配置系统使用了文件缓存作为二级缓存,他的一致性如果保证的问题,目前了解到的有三种方案: ... 2.采用队列方式,将更新作为消息放入mq中进行...3.缓存同步、如何保证缓存一致性、缓存误用 ...

    该文章主要是来自于通用配置系统使用了文件缓存作为二级缓存,他的一致性如果保证的问题,目前了解到的有三种方案:

    1.服务发现(注册中心,利用类似zookeeper来协调各个缓存实例节点)

    2.采用队列方式,将更新作为消息放入mq中进行消费(新增一个线下的读binlog的异步模块)

    3.过期时间

    另外一种设计本地缓存与redis缓存的机制流程图

    主要参考以下文章

    1.分布式缓存的一致性问题

    2.聊聊轻量级本地缓存设计

    3.缓存同步、如何保证缓存一致性、缓存误用

    展开全文
  • 本地缓存一致性解决方案

    千次阅读 2019-05-20 17:35:43
    https://www.jianshu.com/p/75f415bae012
    展开全文
  • 这次就来介绍一下Redis的缓存一致性的问题。 对于缓存和数据库的更新操作,主要分为以下两种 先删除缓存,再更新数据库 先更新数据库,再删除缓存 首先可能会带来疑惑的点是,为什么这里是删除缓存而不是更新缓存...
  • 由于卡顿等原因,导致写缓存2在最前,写缓存1在后面就出现了不一致 这是暂时的脏数据问题,但是在数据稳定,缓存过期以后,又能得到最新的正确数据 2) 失效模式 数据库更新时将缓存删除 存在问题 当...
  • Redis缓存一致性问题解决方案

    千次阅读 2020-04-27 12:05:20
    每次设置缓存时都有一个过期时间,根据不同业务,过期时间也不一致,设置过期时间能保证缓存数据最终一致性问题。这样能保证在更新数据库成功,更新缓存失败,或者缓存了脏数据时,缓存过期后,能正确的读取到最新的...
  • redis缓存一致性问题解决方案

    万次阅读 2019-03-18 22:39:19
    但是引入缓存之后,随之而来的问题就是当DB数据更新时,缓存中的数据就会与db数据不一致,这时候就需要对缓存的数据进行更新或者淘汰缓存,这篇文章就是分析各种处理缓存一致性问题的解决方案。 先更新DB还是操作...
  • redis系列之数据库与缓存数据一致性解决方案

    万次阅读 多人点赞 2017-09-03 17:09:58
    redis系列之数据库与缓存数据一致性解决方案  -- 来自中华石杉老师视频 数据库与缓存读写模式策略 写完数据库后是否需要马上更新缓存还是直接删除缓存? (1)、如果写数据库的值与更新到缓存值是一样的,不...
  • Redis缓存与数据库一致性解决方案

    千次阅读 2020-11-06 15:13:04
    涉及到数据更新:数据库和缓存更新,就容易出现缓存和数据库间的数据一致性问题: 如果先删了缓存,还没有来得及写MySQL,另一个线程就来读,发现缓存空,则去数据库读取数据写入缓存,此时缓存中为脏数据 如果先写...
  • 数据库与缓存数据一致性解决方案

    千次阅读 2020-09-10 22:22:54
    数据库与缓存数据一致性解决方案数据库与缓存读写模式策略的选择为什么使用缓存功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个...
  • 解决缓存一致性问题的几种方式

    千次阅读 2020-09-09 08:05:27
    缓存一致性问题 缓存的实时同步,这种数据同步是增量、主动、强一致性 1、对数据库数据进行更新的时候淘汰缓存 2、读取数据的时候更新缓存,为了避免缓存击穿带来的雪崩问题我们需要做同步处理,控制只有一个线程去...
  • 数据库缓存最终一致性的四种方案

    千次阅读 2019-10-08 13:51:43
    缓存一致性的保证,更是在面试中被反复问到,这里进行一下总结,针对不同的要求,选择恰到好处的一致性方案。 缓存是什么 存储的速度是有区别的。缓存就是把低速存储的结果,临时保存在高速存储的技术。 如图...
  • Redis缓存数据一致性解决方案分析.docx
  • 本文由以下三个部分组成1、讲解缓存更新策略2、对每种策略进行缺点分析3、针对缺点给出改进方案先做一个说明,从理论上来说,给缓存设置过期时间,是保证最终一致性解决方案。这种方案下,我们可以对存入缓存的...
  • redis缓存与数据库一致性问题解决

    千次阅读 2020-08-24 02:29:40
    分布式缓存是现在很多分布式应用中必不可少的组件,但是用到了分布式缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题? Cache Aside Pattern ...
  • 本博文参考网上相关的博文,详细的整理下缓存数据库数据一致性的问题,并且给出基于Java的代码解决方案 关于缓存数据库数据一致性解决方案,网上有很多,但是大都是偏向理论的,且大多数使用分布式锁来实现的,...
  • 缓存的双写一致性一. 何谓双写一致性二. 解决方案2.1 先更新数据库,再更新缓存2.1.1 问题1 每秒一万次改请求,一次读请求?2.2 先删除缓存,再更新数据库2.3 先更新数据库,再删除缓存2.4 最终问题制作不易,转载都请...
  • 缓存和数据库的一致性解决方案: 1. 问题背景 2. 缓存更新策略 3. 改进方案 4. Cache Aside Pattern
  • 聊聊db和缓存一致性的5种实现方式

    千次阅读 2019-10-22 12:13:21
    数据库中,为了加快业务访问的速度,我们将数据库中的一些数据放在缓存中,那么问题来了,如何确保db和缓存中数据的一致性呢?我们列出了5种方法,大家都了解一下,然后根据业务自己选择。 方案1 获取缓存逻辑 ...
  • canal之-缓存一致性和跨服务器查询的数据异构解决方案.docx
  • 关于 Redis 的其他的一些面试问题已经写过了,比如常见的缓存穿透、雪崩、击穿、热点的问题,但是还有一个比较麻烦的问题就是如何保证缓存一致性。 对于缓存和数据库的操作,主要有以下两种方式。 先删缓存,...
  • 想起遇到过的缓存与数据库的问题和一些思考,在这里做一些系统性的分析和总结,讨论一下对数据库与缓存一致性问题及解决方案。 1,先更新数据库再更新缓存 可能出现的问题: a). A更新数据库(或发现缓存失效而...
  • 缓存和数据库一致性解决方案

    千次阅读 2019-07-05 14:16:40
    1、采用延时双删策略 在写库前后都进行redis.del(key)...具体的步骤就是:先删除缓存、再写数据库、休眠500毫秒、再次删除缓存 那么,这个500毫秒怎么确定的,具体该休眠多久呢? 需要评估自己的项目的读数据...
  • CPU多级缓存为什么需要CPU cache:CPU的频率太快了,快到主存跟不上,这样在处理器时钟周期内,CPU常常需要等待主存,浪费资源。所以cache的出现,是为了缓解CPU和内存之间速度的不匹配问题(结构:cpu-&gt;cache-...
  • 你只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题? 3 详解 一般来说,就是如果你的系统不是严格要求缓存+数据库必须一致性的话,缓存...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 162,451
精华内容 64,980
关键字:

缓存一致性解决方案