精华内容
下载资源
问答
  • 缓存一致性
    千次阅读
    2021-11-15 16:19:14

    场景再现

    场景:
      服务器有2个线程t1、t2在跑。都对 x=1 分别+1,期望最终结果:x = 3

    问题分析:
      首先会将 x=1 加载到主内存中,然后 t1线程,会获取到 x=1 的内存地址,然后在寄存器、CPU缓存(L1、L2、L3)中是否存在(L1最优先,L2中如果有,则copy一份到L1,最后加载到寄存器进行计算),如果都没有则会去主内存中获取,然后一次加载,并copy到L3→L2→L1,最后写入寄存器进行计算,一级一级进行缓存。

    实际结果:
      同一时刻两

    更多相关内容
  • 关于缓存一致性问题的思考

    千次阅读 2022-04-08 17:36:17
    缓存一致性问题是实际工作中很少很少遇见但面试过程中经常出现的一个问题。本文主要谈一下自己对缓存一致性问题的一些思考,而不是面试科普文。

    一、引言

    缓存一致性问题是实际工作中很少很少遇见但面试过程中经常出现的一个问题。本文主要谈一下自己对缓存一致性问题的一些思考,而不是面试科普文。

    二、双写一致性问题

    根据 CAP 原理,分布式系统在可用性、一致性和分区容错性上无法兼得,通常由于分区容错无法避免,所以一致性和可用性难以同时成立。

    常见的redis+mysql的场景也是一个典型的分布式场景。
    如果需要保证两者数据的强一致性,那么就需要加分布式锁和全局事务,导致读写并发降低;
    如果需要保证两者的数据可用性,那么在redis和mysql的数据同步过程中,就必然存在数据的不一致问题。
    数据可用性简单来说就是在数据不一致的情况下还可以被查询到,对外提供服务

    持久化层和缓存层的一致性问题也通常被称为双写一致性问题,“双写”意为数据既在数据库中保存一份,也在缓存中保存一份。对于一致性来说,包含强一致性和弱一致性,强一致性保证写入后立即可以读取,弱一致性则不保证立即可以读取写入后的值,而是尽可能的保证在经过一定时间后可以读取到,在弱一致性中应用最为广泛的模型则是最终一致性模型,即保证在一定时间之后写入和读取达到一致的状态。对于应用缓存的大部分场景来说,追求的则是最终一致性,少部分对数据一致性要求极高的场景则会追求强一致性。

    这里我个人认为,过分追求缓存和数据库的强一致性是非常不明智的,首先是技术实现复杂,难度大,给项目增加了额外的风险,而且会导致并发性能降低。
    本来引入缓存是为了提高并发,现在由于要保证强一致性,增加分布式事务和分布式锁,反而会导致并发降低,那么就失去了引入缓存的意义。

    三、缓存的典型使用方式

    Cache-Aside 是应用最为广泛的一种缓存策略。下面的图示展示了它的读写流程,来看看它是如何保证最终一致性的。

    1. 在读请求中,首先请求缓存,若缓存命中( cache hit ),则直接返回缓存中的数据;若缓存未命中( cache miss ),则查询数据库并将查询结果更新至缓存,然后返回查询出的数据( demand-filled look-aside )。
    2. 在写请求中,先更新数据库,再删除缓存(write-invalidate)。
      在这里插入图片描述

    四、常见缓存使用的问题

    1、为什么是删除,而不是更新缓存?
    我们以先更新数据库,再删除缓存来举例。
    如果是更新的话,那就是先更新数据库,再更新缓存。

    举个例子:如果数据库1小时内更新了1000次,那么缓存也要更新1000次,但是这个缓存可能在1小时内只被读取了1次,那么这1000次的更新有必要吗?

    反过来,如果是删除的话,就算数据库更新了1000次,那么也只是做了1次缓存删除,只有当缓存真正被读取的时候才去数据库加载。

    2、先删除缓存,再更新数据库的问题?
    如果先删除缓存再更新数据库,那么在执行删除缓存到更新数据库的中间时间,如果出现查询请求,就会将数据库中的旧值保存到缓存中,从而导致缓存和数据库的数据不一致。
    实际项目中,往往查询请求的并发会高于更新请求。
    (删除缓存 + 更新数据库)的过程中出现(查询数据库+更新旧值到缓存)的概率极大
    所以一般不会采用先删除缓存,再更新数据库的方式。

    在这里插入图片描述

    3、先更新数据库,再删除缓存的问题?
    如果采用先更新数据库再删除缓存,比如更新请求A,那么除非这时出现像查询请求B的情况,刚好在更新之前查询到数据库的旧值,还没来的急更新到缓存,请求A就执行完成了更新数据库和删除缓存的操作。这样请求B中完成缓存更新后,就导致缓存和数据库的数据不一致了。
    但是实际过程中,数据库的查询请求一般都比更新请求快。
    (查询数据库+更新缓存的时间间隔)往往都是小于(更新数据库+删除缓存的耗时),
    并且由于更新请求A没有先删除缓存,查询请求B大概率会命中缓存(缓存过期丢失除外),而不会去查库更新缓存。
    所以采用先更新数据库再删除缓存的处理方式出现缓存不一致情况的概率极低

    在这里插入图片描述

    四、如何保证缓存的最终一致性

    1、设置缓存的过期时间

    每次放入缓存的时候,设置一个过期时间,比如5分钟,以后的操作只修改数据库,不操作缓存,等待缓存超时后从数据库重新读取。

    如果对于一致性要求不是很高的情况,可以采用这种方案。

    这个方案还会有另外一个问题,就是如果数据更新的特别频繁,不一致性的问题就很大了。

    在实际生产中,我们有一些活动的缓存数据是使用这种方式处理的。

    因为活动并不频繁发生改变,而且对于活动来说,短暂的不一致性并不会有什么大的问题。

    2、延迟双删

    延时双删的方案的思路是,为了避免更新数据库的时候,其他线程从数据库中读取到旧的数据更新到缓存中,需要在更新完数据库之后,再sleep一段时间,然后再次删除缓存。

    sleep的时间要对业务读写缓存的时间做出评估,sleep时间大于读写缓存的时间即可。

    流程如下:

    1. 线程1删除缓存,然后去更新数据库
    2. 线程2来读缓存,发现缓存已经被删除,所以直接从数据库中读取,这时候由于线程1还没有更新完成,所以读到的是旧值,然后把旧值写入缓存
    3. 线程1根据估算的时间sleep,由于sleep的时间大于线程2读数据+写缓存的时间,所以缓存被再次删除。
    4. 如果还有其他线程来读取缓存的话,就会再次从数据库中读取到最新值。

    在这里插入图片描述
    在这里插入图片描述

    延时双删常用步骤有 4 个,参考下面伪代码:

    @Transactional(rollbackFor = Exception.class)
    void  update_data(String key,Order obj){
        del_cache(key)     # 删除 redis 缓存数据。
        update_db(obj)     # 更新数据库数据。
        logic_sleep(_time) # 当前逻辑延时执行。
        del_cache(key)     # 删除 redis 缓存数据。
    }
    

    大家认为上面的这个伪代码正确吗?
    1、由于有更新数据的操作,这里添加了事务控制,使用的是方法级别的事务注解@Transactional,这就导致更新数据库的方法update_db(obj)只有在方法执行完成才会执行commit操作,提交数据库的更新。虽然代码看上去是在更新数据库后延迟执行的第二次删除缓存的操作,但是实际上两次缓存都是在更新操作前执行的。

    2、那如果将事务控制在update_db方法中呢?
    这就会导致删除缓存操作如果执行失败,数据库的更新操作不能回滚,缓存中仍然是旧的数据。这里就涉及到一个分布式事务的问题,暂时不展开讨论,默认删除缓存操作一定成功。

    3、延迟双删中,在更新数据库操作前,执行的第一次删除缓存操作的意义在哪?
    只要第一次删除缓存的操作和更新数据库操作之间,有其他查询请求未命中缓存,就会查询到数据库的旧值,并更新到缓存中。
    而删除缓存的速度是非常快的,所以在延迟双删过程中,第一次缓存删除操作,基本没什么作用。

    缓存的意义就是为了提高查询速度,如果数据库值的更新操作都没有完成,这时候的提前执行缓存删除操作毫无意义。
    在这里插入图片描述

    4、为什么要进行延迟删除?
    进行延时删除的核心原因是为了让更新数据库操作之前进行的查询请求先完成缓存更新操作。
    也就是等缓存的更新操作都执行完毕后,再执行缓存删除操作,从而保证数据的最终一致性。
    在这里插入图片描述
    5、延时删除会不会降低更新操作的并发能力?
    这里的一个优化方法是更新数据库完成后,调用一个异步方法,再该方法内部进行延时等待+删除缓存的操作,这样就可以保障更新操作的并发响应速度。

    说明
    延迟双删应该是网上解决缓存一致性问题看到的最多的解决方案。
    但有很多细节痛点都没有仔细考虑。
    比如最基本的一条,如何保证先完成数据库的更新操作(进行了commit),在执行删除缓存的操作?是不是有很多人犯了伪代码中同样的错误。

    3、采用消息队列

    先更新数据库,成功后往消息队列发消息,消费到消息后再删除缓存,借助消息队列的重试机制来实现,达到最终一致性的效果。
    在这里插入图片描述
    这个解决方案其实问题更多。
    1、引入消息中间件之后,问题更复杂了,怎么保证消息不丢失更麻烦
    2、就算更新数据库和删除缓存都没有发生问题,消息的延迟也会带来短暂的不一致性,不过这个延迟相对来说还是可以接受的

    4、基于数据库日志( MySQL binlog )增量解析、订阅和消费

    鉴于上述方案对业务代码具有一定入侵性,所以需要一种更加优雅的解决方案,让缓存删除失败的补偿机制运行在背后,尽量少的耦合于业务代码。一个简单的思路是通过后台任务使用更新时间戳或者版本作为对比获取数据库的增量数据更新至缓存中,这种方式在小规模数据的场景可以起到一定作用,但其扩展性、稳定性都有所欠缺。

    一个相对成熟的方案是基于 MySQL 数据库增量日志进行解析和消费,这里较为流行的是阿里巴巴开源的作为 MySQL binlog 增量获取和解析的组件 canal (类似的开源组件还有 Maxwell、Databus 等)。canal sever 模拟 MySQL slave 的交互协议,伪装为 MySQL slave ,向 MySQL master 发送 dump 协议,MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 canal sever ),canal sever 解析 binary log 对象(原始为 byte 流),可由 canal client 拉取进行消费,同时 canal server 也默认支持将变更记录投递到 MQ 系统中,主动推送给其他系统进行消费。在 ack 机制的加持下,不管是推送还是拉取,都可以有效的保证数据按照预期被消费。当前版本的 canal 支持的 MQ 有 kafka 或者 RocketMQ 。另外, canal 依赖 zookeeper 作为分布式协调组件来实现 HA ,canal 的 HA 分为两个部分:

    为了减少对 MySQL dump 的请求压力,不同 canal server 上的 instance 要求同一时间只能有一个处于运行状态,其他的 instance 处于 standby 状态;
    为了保证有序性,对于一个 instance 在同一时间只能由一个 canal client 进行 get/ack 等动作;

    在这里插入图片描述

    五、不用过分放大缓存不一致问题

    真的不用过分放大缓存不一致的问题。

    遇到技术问题,首先应该评估他会带来什么负面影响,是否有必要解决,解决方案的投入和收益

    在我看来缓存一致性问题更多的情况下只是一个面试问题,完全算不上是技术问题,更谈不上是什么业务问题。

    核心关键点:

    • 业务操作尽量不使用缓存数据
    • 查询操作中才考虑使用缓存数据

    把握住这两个关键点,这样就能保证业务操作不受缓存一致性问题的影响,保证所有业务操作正常进行。
    而大部分系统对查询操作的数据的实时性要求和感知其实并不是明显。
    再简单给缓存数据设置一下过期时间,就能满足大多数场景下数据查询的实时性要求。
    完全没有必要把问题搞的过分复杂化。针对那些实时性要求高且变更频率快的数据,完全没有必要添加缓存,直接查数据库反而是更好的方式。

    在这里插入图片描述


    六、总结

    1、介绍了缓存一致性问题是怎么产生的。
    2、缓存一致性问题本质上是数据库和缓存之间数据的最终一致性问题。通常可以采用以下办法实现缓存的最终一致性:

    • 添加缓存过期时间
    • 延迟删除
    • 消息队列
    • 监听数据库binlog更新缓存

    3、不用过分放大缓存不一致的问题,把握关键点:业务操作中避免使用缓存,保证业务功能不受缓存不一致的影响;查询操作添加缓存提高响应速度。大部分系统对查询数据的实时性要求一般都能接受一定的容忍度。
    针对更新频繁又要保证较高的数据一致性的场景,最好重新考虑使用缓存的必要性。

    4、最推荐的组合方式是:添加缓存过期时间 + 延迟删除。实现简单能满足大部分项目需求。

    展开全文
  • 多处理器缓存一致性方案的系统可靠性分析
  • 嵌入开发语言(c#&java)的基于缓存一致性的分布式事务框架源码嵌入开发语言(c#&java)的基于缓存一致性的分布式事务框架源码嵌入开发语言(c#&java)的基于缓存一致性的分布式事务框架源码嵌入开发语言(c#&java)的基于...
  • canal之-缓存一致性和跨服务器查询的数据异构解决方案.docx
  • 缓存一致性

    千次阅读 2022-04-27 21:43:44
    <一>删除与修改数据,这两种操作都需要删除缓存(确保旧数据被清理掉)会导致如下问题: 如下的a,b表示两个线程,其中a:写线程,b:读线程,↑表示线程切换 **并发环境下: ...故而导致数据不一致)[该情...

    <一> 缓存一致性
    如下的a,b表示两个线程,其中a:写线程,b:读线程,↑表示线程切换
    **并发环境下:

     缓存失效跟不失效两种情景导致数据不一致问题:
      1.1<缓存数据失效过期>
        a线程更新数据库数据,并且之后将数据从缓存中删除,(修改数据库之前,b线程从数据库中读取到了旧的数据,此时a线程更新数据库之后,会删除缓存[此时缓存已经因过期没数据],之后b线程因从数据库读到了旧数据,会将数据重新写入到缓存中(此时写入的是旧数据,故而导致数据不一致)[该情况一般只会发生在读操时间 大于写时间,发生几率很小],另外或者说使用的数据库为主从分离的情况下,当主数据库还未同步到从数据库时,读线程进行了读取旧数据。
       1.1.1<模拟线程a,b执行流程:>

        a-----------------更新数据-------删除缓存------------------->
                        ↑                         ↓   
        b--数据库读数据------------------------------更新写缓存----->

      1.2<缓存数据未过期>
           读线程再写线程更新完数据且删除缓存之间那段时间读取的数据都是旧数据
        1.2.1<模拟线程a,b执行流程:>

        a-------更新数据----------------------------删除缓存------->
                         ↓                       ↑   
        b-------------------b线程读取的都是旧数据------------------->

    1.3<如下两种先后顺序操作导致数据不一致问题>

    A.先更新数据库,删除缓存,导致数据不一致问题

    // X表示更新数据库不成功
    
     a---删除缓存----更新数据库---X------------------------->
      				  	         ⬇             
     b-----------------------------b线程从数据库读取旧数据----->


    解决方法:
     <1>.延迟双删
      延迟:
       就是在更新数据库之后,人为的延迟删除缓存的时间,即便在上1.1.1种b写入了旧数据,之后延迟删除也会将缓存的旧数据删除掉,解决了写入旧数据问题,如下图:
       <模拟执行流程:>

     a----------------更新数据-----------------------sleep-延迟删除缓存---->
                    ↑           ↓               ↑  
     b--读数据库数据----------------更新写缓存-------------------->

    双删:
       删除两次,再更新数据库之前先进行一次删除缓存,删除之前可能存在的旧数据。避免了修改数据库到第二次读取缓存中间这段时间可能读取存在的旧数据。解决了如上1.2.1所遇到的问题。
       <模拟执行流程:>

     a----删除缓存-----更新数据-------------------------------------sleep--延迟删除缓存------->
        ↑                      ↓                             ↑           
     b--------------------------b因缓存无数据,读数据库----更新缓存---------------------->

    Sleep,由于 Sleep 的时间大于线程b读数据+写缓存的时间,所以缓存被再次删除。 

    注:设置缓存过期时间:目的是保证数据最终一致性,所有的血操作以数据库为准,只要缓存达到了过期时间,后面数据自动回通过数据库查询最终回滚到缓存.

    B.更新数据库,再删除缓存,导致数据不一致

    // X表示缓存删除不成功
    
     a--更新数据库----删除缓存---X---------------------->
      				  	         ↓          
     b-----------------------------b线程从数据库读取旧数据----->


    解决方法:
         增加一个消息队列,在延迟删除的时候,将需要需要删除的key扔到队列中,通过队列消费来进行缓存的删除,另外需要设置重试机制,确保数据最终删除。该方法又个缺点,那就是业务层代码,会增加对应的队列相关的代码.这样低业务代码入侵比较大。可以通过订阅程序订阅数据库写入操作是写的binlog,一旦有数据写入成功,订阅程序感知到数据的变化,主动通过binlog的操作,来处理删除缓存的处理。

     <总结>
      为什么删除,而不是更新操作?
       举例说明: 更新数据库n次,同样缓存也需要更新n次,但是再次过程中,数据读取只读了一次缓存(那么,之前的n次更新缓存都是无用功),反之,直接删除掉,当真正读取数据的时候,会从数据库读取,再次写入缓存即可。
      删除缓存两种方式:
       先删除缓存,再更新数据库,解决方法使用延迟双删策略。
       先更新数据,再删除缓存,通过队列orbinlog同步,推荐使用binlog操作,针对要求不是很高的场景,只设置超时时间就可以了。

    展开全文
  • 缓存一致性协议

    2021-08-16 15:07:04
    缓存一致性协议 在执行程序时,每一条指令都是在CPU中执行的,执行指令过程中会包含读取与写入的操作。一般来说程序运行过程中的临时数据都存放在主存(即内存)中,由于CPU执行速度很快,但每次从内存读取数据和向...

    缓存一致性协议

    在执行程序时,每一条指令都是在CPU中执行的,执行指令过程中会包含读取与写入的操作。一般来说程序运行过程中的临时数据都存放在主存(即内存)中,由于CPU执行速度很快,但每次从内存读取数据和向内存写入数据的过程与CPU执行指令速度比起来要慢的多,若是每次对数据的操作都与内存进行交互的话,会大大降低指令执行的速度,为了提升性能,CPU中出现了高速缓存(cache,现在一般都有三级缓存)!

    CPU有了高速缓存之后,但程序在运行时,会将运算需要的数据从主存中复制一份到CPU的高速缓存中,接着进行读取与写入操作即就从其高速缓存中进行,当运算结束后,会将高速缓存中的数据刷新到主存中。
    举例执行i=i+1,该条指令在单线程中并不会有问题,但是在多线程中就会出现线程安全问题!

    问题描述:由于是多线程,可能多个线程会同时拷贝一份主存中的对应变量,接着在线程中不断对对应自己线程的副本进行读取写入操作,当多个线程执行完之后,重新刷新高速缓存中的值到主存,这时候就会出现缓存不一致问题!

    解决缓存不一致问题方法:硬件层面提供方法

    **通过在总线加LOCK#锁的方式。但是锁的是IO总线。这就变成串行肯定有性能问题。
    在这里插入图片描述

    后来引入锁缓存行。CacheLine: 64byte(64bit机)为一个缓存行,8个缓存行为一个内存块。如果锁的数据超过缓存行这个锁也会失效。锁缓存行有一套协议叫缓存一致性协议。

    就是定义这个缓存行的锁如何有效。缓存一致性协议的实现很有很多比如:MESI,MSI,MOESI等。

    大部分系统都会实现MESI。

    MESI协议 规定每条缓存都有一个状态位(额外两位表示),该状态位可对应四种状态:
    ①修改态(Modified):此缓存被修改过,与主存数据不一致,为此缓存专有。
    ②专有态(Exclusive):此缓存与主内存一致,但是其他CPU中没有。
    ③共享态(Shared):此缓存与主内存一致,但也出现在其他缓存中。
    ④无效态(Invalid):此缓存无效,需要从主内存重新读取

    在MESI协议下。Thread1和Thread2读取i=0就变成下面的这个流程。
    (1)Thread1从主存中读取i=0,数据存在高速缓存中,这时候的状态为E(独占),在缓存行有监听机制,可以监听到缓存的主存的数据被其它CPU也读取了。
    (2)Thread2从主存中读取i=0,数据存在高速缓存中,这个时候监听机制知道有两个核读取到了i=0数据,它们在缓存中的状态变成了S(共享)。
    (3)Thread1把数据i=0从缓存读取到寄存器进行修改操作i=1,缓存行的数据被修改后状态变成M,监听到数据被修改后Thread2中的数据状态变成I。
    (4)缓存一致性协议会保证这个修改了的数据立马刷回主存,而不是等待某个时间点再刷回主存,因为Thread2中的数据失效了需要从主存中再次读取数据,为了减少CPU等待时间,Thread1需要立即刷回主存而且能保证刷回主存是原子性的。

    说明:这仅仅是CPU硬件层面的,对于Java的话需要去知晓对应的Java内存模型(JMM)对应的规范说明。
    ————————————————
    原文链接:https://blog.csdn.net/cl939974883/article/details/115497264

    volatile和MESI协议之间的关系

    首先强调一点,volatile和mesi这两个东西没有半点关系。mesi是缓存一致性的一种实现手段,多核CPU为了保证缓存数据的一致性,通常有两种实现手段,一种是总线锁,另一种是缓存锁。总线锁性能消耗大,缓存锁则一般通过缓存一致性来实现。因此我们知道mesi是CPU硬件级别的。 volatile是JAVA的一种关键字,实现了两个功能: 1.可见性 2.禁止乱序。 禁止乱序,在JVM层面使用内存屏障来实现,汇编级别通过lock #指令来实现。

    问题:既然CPU有了MESI协议可以保证cache的一致性,那么为什么还需要volatile这个关键词来保证可见性(内存屏障)?或者是只有加了volatile的变量在多核cpu执行的时候才会触发缓存一致性协议?

    两个解释结论:

    多核情况下,所有的cpu操作都会涉及缓存一致性的校验,只不过该协议是弱一致性,不能保证一个线程修改变量后,其他线程立马可见,也就是说虽然其他CPU状态已经置为无效,但是当前CPU可能将数据修改之后又去做其他事情,没有来得及将修改后的变量刷新回主存,而如果此时其他CPU需要使用该变量,则又会从主存中读取到旧的值。而volatile则可以保证可见性,即立即刷新回主存,修改操作和写回操作必须是一个原子操作;
    正常情况下,系统操作并不会进行缓存一致性的校验,只有变量被volatile修饰了,该变量所在的缓存行才被赋予缓存一致性的校验功能。

    我们再来看一下另一位大N的解释:

    首先,volatile是java语言层面给出的保证,MSEI协议是多核cpu保证cache一致性(后面会细说这个一致性)的一种方法,中间隔的还很远,我们可以先来做几个假设:

    回到远古时候 那个时候cpu只有单核,或者是多核但是保证sequence consistency[1],当然也无所谓有没有MESI协议了。那这个时候,我们需要java语言层面的volatile的支持吗?当然是需要的,因为在语言层面编译器和虚拟机为了做性能优化,可能会存在指令重排的可能,而volatile给我们提供了一种能力,我们可以告诉编译器,什么可以重排,什么不可以。
    那好 假设更进一步,假设java语言层面不会对指令做任何的优化重排,那在多核cpu的场景下,我们还需要volatile关键字吗?答案仍然是需要的。因为 MESI只是保证了多核cpu的独占cache之间的一致性,但是cpu的并不是直接把数据写入L1 cache的,中间还可能有store buffer。有些arm和power架构的cpu还可能有load buffer或者invalid queue等等。因此,有MESI协议远远不够。
    再接着 让我们再做一个更大胆的假设。假设cpu中这类store buffer/invalid queue等等都不存在了,cpu是数据是直接写入cache的,读取也是直接从cache读的,那还需要volatile关键字吗?你猜的没错,还需要的。原因就在这个“一致性”上。consistency和coherence都可以被翻译为一致性,但是MSEI协议这里保证的仅仅coherence而不是consistency。那consistency和cohence有什么区别呢?下面取自wiki[2]的一段话:
    Coherence deals with maintaining a global order in which writes to a single location or single variable are seen by all processors. Consistency deals with the ordering of operations to multiple locations with respect to all processors.

    因此,MESI协议最多只是保证了对于一个变量,在多个核上的读写顺序,对于多个变量而言是没有任何保证的。很遗憾,还是需要volatile~~

    好的,到了现在这步,我们再来做最后一个假设,假设cpu写cache都是按照指令顺序fifo写的,那现在可以抛弃volatile了吧?你觉得呢?我都写到标题4了,那肯定不行啊!因为对于arm和power这个weak consistency[3]的架构的cpu来说,它们只会保证指令之间有比如控制依赖,数据依赖,地址依赖等等依赖关系的指令间提交的先后顺序,而对于完全没有依赖关系的指令,比如x=1;y=2,它们是不会保证执行提交的顺序的,除非你使用了volatile,java把volatile编译成arm和power能够识别的barrier指令,这个时候才是按顺序的。

    引用:https://www.zhihu.com/question/296949412/answer/747494794

    展开全文
  • 缓存一致性问题解决方案

    千次阅读 2022-04-07 11:26:30
    通常情况下,我们使用缓存的主要目的是为了提升查询的性能。大多数情况下,是这样使用缓存的: 当数据库有数据更新时,在很长的一段时间内(决定于缓存的...缓存一致性问题没有绝对可靠的方案,我们只能让两者尽量接
  • VISU:一种基于自更新的简单有效的缓存一致性协议
  • 数据库缓存一致性解决方案

    千次阅读 2022-04-06 13:03:31
    最近在面试的过程中,有遇到面试官问我这个问题,觉得还是有必要看一下,那就是缓存与数据库的一致性问题 在自己开发单体应用的时候,往往是一个后端服务加一个数据库服务就ok了,但是,在实际开发中,还需要根据...
  • 这次就来介绍一下Redis的缓存一致性的问题。 对于缓存和数据库的更新操作,主要分为以下两种 先删除缓存,再更新数据库 先更新数据库,再删除缓存 首先可能会带来疑惑的点是,为什么这里是删除缓存而不是更新缓存...
  • 分布式缓存一致性(Redis、MySQL)

    千次阅读 2020-07-20 01:14:05
    文章目录分布式——缓存一致性(Redis、MySQL)1. 前言2. 常见方案的问题点2.1 先更新数据库,再更新缓存2.2 先删除缓存,再更新数据库2.3 先更新数据库,再删除缓存3. 维护一致性3.1 设置缓存过期时间3.2 利用消息...
  • Redis实现缓存一致性的原理深度解析

    千次阅读 2021-10-09 11:22:02
    详细介绍了Redis实现缓存一致性的三种方式,以及他们的优缺点。
  • 缓存一致性的解释

    千次阅读 2020-01-12 11:01:40
    那今天讲的是缓存一致性,首先要理解我说的缓存是什么意思,大家可以看下下面的图,这个很常见的图就是说现在我们买电脑的时候经常听说的参数cpu L1 L2 L3三级缓存,然后一般是CPU的每个核都有自己的L1级缓存,然后...
  • 缓存一致性解决方案

    千次阅读 2021-06-07 13:40:49
    1)先删除缓存 2)再写数据库 3)休眠500毫秒(根据具体的业务时间来定) 4)再次删除缓存。 那么,这个500毫秒怎么确定的,具体该休眠多久呢? 需要评估自己的项目的读数据业务逻辑的耗时。这么做的目的,就是...
  • Canal实现缓存一致性

    2021-03-31 23:47:36
    上面我们虽然实现了多级缓存架构,但是问题也出现了,如果数据库中数据发生变更,如何更新Redis缓存呢?如何更新Nginx缓存呢? 我们可以使用阿里巴巴的技术解决方案Canal来实现,通过Canal监听数据库变更,并实时...
  • 缓存一致性协议(MESI) - 简书存储器层次结构中,最快速的就是cpu一级别 在目前主流的计算机中,cpu执行计算的主要流程如图所示: 数据加载的流程如下: 将程序和数据从硬盘加载到内存中将程序和数据从内存加......
  • 如何保证缓存一致性?

    千次阅读 2022-01-18 15:28:02
    缓存可以提高数据查询的效率,较低数据库的压力,但使用缓存的过程中,需要注意缓存一致性问题。 先更新缓存,再更新数据库 假设2个并发线程A和B,均为写线程,其执行顺序如下: 线程A更新缓存值为v1; 线程B更新...
  • 如何保证缓存一致性

    2021-06-11 15:23:23
    目前有四种更新缓存的策略 1.先更新数据库,再更新缓存 2.先更新数据库,再更新缓存 3.先淘汰缓存,再更新数据库 4.先更新数据库,再淘汰缓存 1.先更新数据库,再更新缓存 2.先更新数据库,再更新缓存 对于上述两...
  • java缓存一致性问题及解决方案:使用缓存,肯定会存在一致性问题; 读取缓存步骤一般没有什么问题,但是一旦涉及到数据更新:数据库和缓存更新,就容 易出现缓存(Redis)和数据库(MySQL)间的数据一致性问题。 ...
  • volatile与缓存一致性

    2021-01-27 15:25:39
    最近在深入分析volatile关键字的实现原理,内存屏障、缓存一致性、store buffer、invalid queue等知识看了不少,但接触的资料比较零散,无法完整的把相关内容串联起来,所以抽空做些整理,也算对这段时间的学习做一...
  • CPU多级缓存结构 现代CPU分为物理核和逻辑核,比如我们日常办公电脑常见的4核8线程,就是指的4个物理核、8个逻辑核。超线程的技术使得一个物理核可以同时做两件事,也就是执行两个线程,但是能真正执行两个线程的...
  • 关于 Redis 的其他的一些面试问题已经写过了,比如常见的缓存穿透、雪崩、击穿、热点的问题,但是还有一个比较麻烦的问题就是如何保证缓存一致性。 对于缓存和数据库的操作,主要有以下两种方式。 先删缓存,...
  • 数据库和redis缓存一致性

    千次阅读 2022-04-22 14:57:46
    如果在高并发修改的场景,会存在redis和MySQL数据不同步的问题。 比如,修改某个商品的价格, ...先修改MySQL商品价格,再删缓存,MySQL价格修改了,缓存删除失败了,就会导致不一致的情况。 解决方案: 延时双删
  • cpu cache已经发展到了三级缓存结构,基本上现在买的个人电脑都是L3结构。 1. cache的意义     为什么需要CPU cache?因为CPU的频率太快了,快到主存跟不上,这样在处理器时钟周期内,CPU常常需要等待...
  • CPU缓存一致性协议:MESI

    千次阅读 2022-03-26 20:10:40
    今天在看《架构解密》的时候,看到一段介绍CPU缓存一致性的介绍,文章详细解析了Intel多核处理器是如何解决数据一致性问题的,这本书在2020年看过一遍,现在又拿出来学习,感觉要学习的知识还有很多,关于CPU的多核...
  • MESI高速缓存一致性协议

    千次阅读 2022-01-25 15:15:12
    MESI高速缓存一致性协议
  • 缓存一致性问题也是使用缓存中比较经典的问题之一。使用缓存,涉及数据库和缓存两部分数据的维护,既然是两个组件的数据,那么必然有数据一致性问题。常用的解决方案有三种,分别是设置过期时间,先更新数据库,再删...
  • 缓存一致性(Cache Coherence) 与内存一致性不同,缓存一致性是作为支持内存一致性模型的一部分。缓存一致性试图使共享内存系统的缓存(cache)数据与内存保持一致。也就是说内存一致性是从多核心的视角来看共享...
  • 首先要说明的是,接下来无论是哪种方案都只能保证最终一致,无法做到强一致性。 方案一:先更新数据库,再更新缓存 异常场景:线程A比线程B先更新,但是由于网络等原因导致线程B先更新了缓存。然后A再把旧值更新到...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 453,807
精华内容 181,522
关键字:

缓存一致性