高并发下的数据库与缓存一致性问题

引言

在互联网业务中,传统的直接访问数据库方式,主要是通过数据分片,一写多读的方式去抗住数据流量,但是随着数据量的激增,并且大多数都是读多写少的场景 ,仅仅依靠数据库查询,成本高,效率低,且稳定性远远不够。因此,在架构设计中,常采用增加缓存层来提高系统的响应能力,提升数据读写性能、减少数据库访问压力,从而提升业务的稳定性和访问体验。
引入缓存又带来了新的问题,那就是数据库与缓存一致性的问题,该问题不局限于语言,是个公共问题,尤其在高并发的情况下很容易出现该问题。

使用数据库缓存的场景一般可以分为读操作和写操作。

  • 读操作
    • 命中缓存(cache hit):当客户端从缓存中读取到数据时,可以直接返回。
    • 未命中缓存(cache miss):当读取的数据不在缓存时,需要从数据库中读取数据并写入缓存。
    • 缓存的命中率 = 命中缓存请求个数/总缓存访问请求个数 = hit / (hit+miss),缓存的命中率是衡量缓存效果的重要指标,命中率越大,对后端数据库的压力越小。
  • 写操作
    • 缓存与数据库中的数据都需要被修改,因为要涉及缓存和数据库两个点的数据修改,且无法满足原子性,需要重点考虑数据一致性的问题,这也是数据库缓存使用的难点和重点。

常见的解决方

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

  • 我们先来分析一下此种方案的问题
    • 初始缓存为0,数据库为0,A更新缓存为1
    • A更新数据库失败,此时数据库中数据为0,缓存中数据为0
    • 出现脏数据情况

异步回写:在处理写请求的时候,先只更新缓存,对于数据库的更新是使用批量异步更新的方式去处理的,这种方式,由于前面的更新操作只发生在缓存中,因此对于缓存的高可用要求比较高,但由于读写操作都在缓存中处理,大大提升了响应速度

  • 使用场景
    比较适用于写入较多的极端场景,例如:电商秒杀系统

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

  • 分析一下此种方案的问题
    • 初始缓存为0,数据库为0
    • A请求更新数据,更新数据库中数据为1
    • B请求更新数据,更新数据库中数据为2,此时数据库中数据为2
    • B更新缓存中数据为2,A由于网络延迟此时才更新缓存中的数据,更新缓存中数据为1
    • 出现数据库与缓存不一致情况
  • 更新缓存失败也会造成数据库与缓存不一致情况出现

直写模式:这种模式优点在于读请求过程十分简单,不需要进行数据库查询操作,不管是先更新数据库,再更新缓存,还是先更新缓存再更新数据库,都会由于线程竞争原因出现数据库与缓存不一致的情况。

解决方:可以将数据库更新与缓存的更新放在同一个事务中处理,线程竞争导致的不一致情况通过分布式锁解决,保证对缓存和数据库的操作仅能由同一个线程完成。对于没有拿到锁的线程,一是通过锁的timeout时间进行控制,二是将请求暂存在消息队列中顺序消费。

  • 使用场景
    适合写操作较多,并且对一致性要求较高的场景

上述两种方案,都是去更新缓存,主要是为了写操作较多的场景,针对于读操作较多的场景,可以使用删除缓存的形式去处理,这样处理的好处

  • 性能方面:假设缓存不是从数据库中读取出后就直接写进去的,而是需要复杂的计算后才能得出需要写入缓存的结果,此时每次更新数据的操作都去更新缓存在不需要读取该缓存的时候是不必要的,我们可以删除缓存,在读操作的时候再进行缓存的写入,这样可以大大提高性能
  • 分析:删除与更新在实际上的区别就是一次cache miss

删除缓存,再写入数据库

  • 分析一下此种方案的问题

解决方:使用延时删除策略,即更新数据库后再对缓存进行删除操作,延时时间根据读操作并写缓存的耗时决定

疑问:延时双删与先更新数据库删除缓存的区别以及优势在哪

个人理解:延时双删由于先删除缓存中的数据,可以保证在删除缓存与更新数据库的过程中一定获取的为最新的数据。同时对于先更新数据库再更新缓存中必出现的短暂缓存不一致情况,此时延时双删这阶段出现缓存不一致概率会有所降低。

但是由于我们讨论的场景为高并发的场景下,在读操作比较多的时候,在删除缓存与更新数据库间出现数据查询的概率还是很高的,因此此时延时双删的方案的问题就又变回了先更新再删除缓存的问题。同时也引入了延时的时间确定性麻烦,不建议盲目使用延时双删策略

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

此方案中更新数据库删除缓存的短暂数据库不一致情况可忽略,主要处理删除缓存失败的情况

解决方:主要是针对上述删除缓存失败的情况,为此使用补偿机制

总结

从上述分析来看,不管哪种方式可能都存在一定的不一致情况出现,需要针对不同的场景进行不同的设计,同时在缓存的处理上面可以使用分布式锁的机制去处理,也可以避免缓存不一致情况,但是此种方式会影响系统的吞吐量,在使用缓存的时候要使用过期时间去处理。

在读多写少的场景中,建议使用先更新数据库,再删除缓存的方式进行处理,再写多且对数据一致性要求比较高的场景中,可以使用先更新数据库,再更新缓存的方式处理,面对一些极端写场景,可以使用先更新缓存,然后异步写入数据库的方式处理。

相关文章

显卡天梯图2024最新版,显卡是电脑进行图形处理的重要设备,...
初始化电脑时出现问题怎么办,可以使用win系统的安装介质,连...
todesk远程开机怎么设置,两台电脑要在同一局域网内,然后需...
油猴谷歌插件怎么安装,可以通过谷歌应用商店进行安装,需要...
虚拟内存这个名词想必很多人都听说过,我们在使用电脑的时候...