当前位置: 首页 > news >正文

Redis八股小记


如果我要求自己什么都学会,我在学习过程中就会担心其他方面的知识,最后我什么都得不到。

与其贪多求全,不如脚踏实地,把已经接触过的内容学懂学透。唯有打下坚实的基础,才能在未来逐步拓展,不至于浮于表面。


1.为什么是先写库再删缓存来保证一致性?如果在删缓存之前服务挂了怎么办?

先删除缓存再写库会怎么样?

删除缓存后,还没写库时,其他线程过来读数据 → 缓存 miss → 去数据库读到旧值 → 把旧值写回缓存 → 缓存和数据库又不一致了。

假设线程1先执行删除缓存,之后要更新数据库。但是在这之间,插入了线程2,线程2查询缓存未命中,接着查询数据库,并写入缓存,此时线程1更新数据库,那么就发生了缓存与数据库数据不一致的情况了。而且这种情况发生的概率比较大,因为查询缓存写缓存是相当快的。

先写库再删缓存?

即使删缓存失败,最多缓存里是旧值,但数据库里是最新的。下一次缓存失效或被淘汰后,会自动拉新。

删缓存前服务挂了?

订阅BinLog,异步删缓存。


2.如果并发下多个线程同时写,怎么保证缓存和数据库一致?

分布式锁:给某个业务 ID 加锁,保证同一时间只有一个线程能操作,避免并发覆盖。适合金融、库存扣减等强一致场景。

延时双删:更新数据库 → 删除缓存 → 延时几百毫秒后再删一次缓存,避免读写并发时旧值被写回,降低不一致概率。

逻辑过期:

在缓存中维护逻辑过期时间,过期后后台线程异步重建缓存,对用户返回旧值即可。适合商品详情、商铺信息这类允许短时间脏数据的场景,允许短暂不一致。

3.缓存击穿、穿透、雪崩的区别?怎么解决?

穿透:查询不存在的数据,缓存和数据库中都没有此数据,所以请求会不断打到数据库,可能导致数据库瘫痪。

可以缓存null值,对不存在的数据key的value缓存为null,这种方法很大的弊端就是内存占用和数据不一致(如果下次真的要储存当前数据,会导致缓存与数据库数据不一致)。

更好的办法是布隆过滤器,首先初始化一个比较大的数组,里面存放的是二进制0或1,全部初始化为0,当一个key来了之后,经过3次Hash计算,模数组长度得到下标,并在原来的位置改为1。这样三个数组的位置就可以标明一个key的存在,查找的过程也是这样。当然布隆过滤器也会产生误判,误判率可以自己设置,一般是5%。这个误判率是必须存在的,否则就得增加数组长度,5%的误判率大部分项目也能接受。

击穿:对于设置了过期时间的key,在某个时间Redis缓存恰好过期,恰好这时有大量对这个key的请求打过来。发现缓存过期就会查询DB,导致压垮数据库。

一般有两种方式应对。

  1. 使用互斥锁,利用setnx设置互斥锁,当操作成功时再进行load db的操作,并写入缓存,否则重试获取缓存的方法。
  2. 逻辑过期:
  • 将key写入Redis时,附带上一个expireTime字段,但不设置TTL。
  • 查询时,从Redis中取出数据后判断时间是否过期
  • 如果过期会返回旧数据,然后开新线程进行缓存重建,查询数据库将新数据写入Redis。

如果项目对强一致性要求较高就采用互斥锁,如果更多的是追求并发性就采用逻辑过期。

雪崩:大量key在同一时间过期,请求全部转发到DB,DB瞬间压力过重而雪崩。可以将缓存失效时间分开,比如可以在失效时间基础上加上随机值,比如1-5分钟随机。这样每个缓存过期时间的重复率就会降低,很难引发集体失效。


4.Redis 持久化方式有哪几种?优缺点?

Redis中提供了两种数据持久化的方式:RDB和AOF。

Redis DataBase和Append Only File。RDB是一个快照文件,会将Redis内存存储的数据写入磁盘内,当Redis实例宕机时,可以从RDB快照文件中恢复数据。

AOF是含义是追加文件,当Redis执行写命令时,都会存储到这个文件中。恢复数据时,只需要重新执行一遍里面的数据。

RDB是二进制文件,保存时体积小,所以恢复的比较快,但是可能会丢数据。

AOF恢复速度慢一些,但丢数据的风险小很多。可以在AOF文件中设置刷盘策略,比如每秒批量写入一次命令。


如果这篇文章对你有帮助,请点赞、评论、收藏,创作不易,你的支持是我创作的动力。
http://www.dtcms.com/a/359955.html

相关文章:

  • 人工智能学习:机器学习相关面试题(二)
  • 【开题答辩全过程】以 基于vue+springboot的校园疫情管理系统的设计与实现为例,包含答辩的问题和答案
  • 企业级开发模型:从软件生命周期到 Git 分支管理
  • 【C++ 】string类:深拷贝与浅拷贝解析
  • DSPFilters实现低通滤波器(QT)
  • 电力电子技术知识学习-----晶闸管
  • 前端组件拆分与管理实战:如何避免 props 地狱,写出高可维护的项目
  • 接口测试:如何定位BUG的产生原因
  • Python实现异步多线程Web服务器:从原理到实践
  • 萌宝喂养日志-我用AI做喂养记录小程序1-原型设计
  • 微服务的编程测评系统18-判题功能-Rabbitmq-用户拉黑
  • Elasticsearch面试精讲 Day 3:分片与副本策略详解
  • 【图论】 Graph.jl 概览
  • Linex进程管理
  • OC-属性关键字
  • GEE 实战:计算 Landsat8 月均 NDVI 并导出(2013-2024)_后附完整代码
  • 【pve】
  • 秋招 AI 方向 —— 华为机考
  • 【学习笔记】LLM Interview(Agent相关)
  • 计算机视觉与深度学习 | 低照度图像处理算法综述:发展、技术与趋势
  • 大数据毕业设计选题推荐-基于大数据的大气和海洋动力学数据分析与可视化系统-Spark-Hadoop-Bigdata
  • (数组的定义与使用) 本篇目标 1. 理解数组基本概念 2. 掌握数组的基本用法 3. 数组与方法互操作 4. 熟练掌握数组相关的常见问题和代码
  • 同类软件对比(三):Python vs Anaconda vs Miniconda:深入解析与选择策略
  • 2025.8.18-2025.8.24第35周:备稿演讲有进步
  • Paimon——官网阅读:Spark 引擎
  • 【图论】Graph.jl 核心函数
  • 如何通过 AI IDE 集成开发工具快速生成简易留言板系统
  • Java面试-微服务(spring cloud篇)
  • 飞牛Docker部署免费frp内网穿透
  • RK3568平台开发系列讲解:瑞芯微平台4G模块篇移植