当前位置: 首页 > 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.xdnf.cn/news/1408915.html

相关文章:

  • 【了解下TJ、TC、TB、TT、TA、qJA、qJC、qJB、YJB、YJT】
  • Asible——将文件部署到受管主机和管理复杂的Play和Playbook
  • [linux仓库]解剖Linux内核:文件描述符(fd)的‘前世今生’与内核数据结构探秘
  • 编写一个用scala写的spark程序从本地读取数据,写到本地
  • 【ArcGIS微课1000例】0150:如何根据地名获取经纬度坐标
  • openssl使用SM2进行数据加密和数据解密
  • 科普:requirements.txt 和 environment.yml
  • Labview使用modbus或S7与PLC通信
  • Machine Learning HW3 report:图像分类(Hongyi Lee)
  • 《深入剖析Kafka分布式消息队列架构奥秘》之Springboot集成Kafka
  • 中级统计师-统计实务-第四章 专业统计
  • 嵌入式ARM程序高级调试技能:20.qemu arm ARM Linux 上 addr2line 的实际应用示例
  • 【重学MySQL】九十五、Linux 下 MySQL 大小写规则设置详解
  • CF每日3题(1500-1600)
  • 阿里云创建自己的博客,部署wordpress
  • 基于Matlab元胞自动机的强场电离过程模拟与ADK模型分析
  • Scikit-learn Python机器学习 - 数据集的划分
  • 网格图--Day03--网格图DFS--2658. 网格图中鱼的最大数目,1034. 边界着色,1020. 飞地的数量
  • Cartographer中的gflag与lua文件
  • 【开题答辩全过程】以 基于Java的城市公交查询系统设计与实现为例,包含答辩的问题和答案
  • 记录测试环境hertzbeat压测cpu高,oom问题排查。jvm,mat,visulavm
  • 浏览器和 node 操作文件的 api 以及区别
  • GEE 实战:Landsat 5 月度 NDVI 数据插值填补(以 8 月为例)_后附完整代码
  • Python:如何批量下载CLMS NDVI V3数据集?
  • PyQt5 K线图实现与性能优化详解
  • 神州数码之FTP/TFTP 升级 篇
  • 深入解析Linux系统中的/etc/hosts文件
  • 在Windows的wsl中如何以root登录Ubuntu
  • OpenStack 02:使用 DevStack 单节点一体化部署
  • Kafka面试精讲 Day 3:Producer生产者原理与配置