Redis高频八股文与解决策略

什么是Redis?

Redis是一个高性能的非关系型的键值对数据库,使用C编写实现的。与传统的数据库不同的是Redis是存在内存中的,所以读写速度非常快,每秒可以处理超过10万次的读写操作,这也是Redis常常被用作缓存的原因。

什么是缓存穿透?

缓存穿透是指用户的请求没有经过缓存而直接请求到数据库上了,比如用户请求的key在Redis中不存在,或者用户恶意伪造大量不存在的key进行请求,都可以绕过缓存,导致数据库压力太大挂掉。

如何解决缓存穿透?

  • 参数校验、屏蔽非法参数
    检验用户请求的合法性,屏蔽掉不合理的参数请求(无法彻底避免)

  • 缓存空值
    数据库查询为空,可以给缓存一个空值或默认值,防止第二次再去数据库(导致Redis缓存大量无效数据,甚至内存爆掉)

  • 布隆过滤器
    使用布隆过滤器快速判断数据是否存在,将所有可能存在的数据哈希存到一个足够大的容器中,不存在的数据被这个bitmap拦截掉(布隆过滤器存在一定误差,且不支持删除数据,可通过定期重构解决数据变更问题)

什么是缓存雪崩?

缓存雪崩是指在某一个时刻出现大规模的缓存失效的情况,大量的请求直接打在数据库上面,可能会导致数据库宕机,如果这时重启数据库并不能解决根本问题,会再次造成缓存雪崩。

为什么会造成缓存雪崩?

一般来说,造成缓存雪崩主要有两种可能

  • Redis宕机了
  • 很多key采取了相同的过期时间

如何解决缓存雪崩?

  • 为避免Redis宕机造成缓存雪崩,可以搭建Redis集群
  • 尽量不要设置相同的过期时间,例如可以在原有的过期时间加上随机数
  • 服务降级,当流量到达一定的阈值时,就直接返回“系统繁忙”之类的提示,防止过多的请求打在数据库上,这样虽然用户体验较差,但至少可以使用,避免直接把数据库搞挂

什么是缓存击穿?

缓存雪崩是大规模的key失效,而缓存击穿是一个热点的Key,有大并发集中对其进行访问,突然间这个Key失效了,导致大并发全部打在数据库上,导致数据库压力剧增,这种现象就叫做缓存击穿。

比较经典的例子是商品秒杀时,大量的用户在抢某个商品时,商品的key突然过期失效了,所有请求都到数据库上了。

如何解决缓存击穿?

  • 虑热点key不设置过期时间,避免key过期失效
  • 在数据的value上增加一个逻辑到期时间,数据查询发现过期后进行加锁,拿到锁的请求去查询数据库进行Redis更新,未抢到锁的线程可以返回过期前的默认数据,用弱一致性来避免缓存击穿

如何保证缓存与数据库双写时的数据一致性?

这是面试的高频题,需要好好掌握,这个问题是没有最优解的,只能数据一致性和性能之间找到一个最适合业务的平衡点

首先先来了解下一致性,在分布式系统中,一致性是指多副本问题中的数据一致性。一致性可以分为强一致性、弱一致性和最终一致性

  • 强一致性:当更新操作完成之后,任何多个后续进程或者线程的访问都会返回最新的更新过的值。强一致性对用户比较友好,但对系统性能影响比较大。
  • 弱一致性:系统并不保证后续进程或者线程的访问都会返回最新的更新过的值。
  • 最终一致性:也是弱一致性的一种特殊形式,系统保证在没有后续更新的前提下,系统最终返回上一次更新操作的值。
    大多数系统都是采用的最终一致性,最终一致性是指系统中所有的副本经过一段时间的异步同步之后,最终能够达到一个一致性的状态,也就是说在数据的一致性上存在一个短暂的延迟。

如果想保证缓存和数据库的数据一致性,最简单的想法就是同时更新数据库和缓存,但是这实现起来并不现实,常见的方案主要有以下几种:

  • 先更新数据库,后更新缓存
  • 先更新缓存,后更新数据库
  • 先更新数据库,后删除缓存
  • 先删除缓存,后更新数据库

乍一看,感觉第一种方案就可以实现缓存和数据库一致性,其实不然,更新缓存是个坑,一般不会有更新缓存的操作。因为很多时候缓存中存的值不是直接从数据库直接取出来放到缓存中的,而是经过一系列计算得到的缓存值,如果数据库写操作频繁,缓存也会频繁更改,所以更新缓存代价是比较大的,并且更改后的缓存也不一定会被访问就又要重新更改了,这样做无意义的性能消耗太大了。

下面介绍删除缓存的方案

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

这种方案也存在一个问题,如果更新数据库成功了,删除缓存时没有成功,那么后面每次读取缓存时都是错误的数据。
解决这个问题的办法是删除重试机制,常见的方案有利用消息队列和数据库的日志
但这个方案也有一些缺点,比如系统复杂度高,对业务代码入侵严重,这时可以采用订阅数据库日志的方法删除缓存。

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

这种方案也存在一些问题,比如在并发环境下,有两个请求A和B,A是更新操作,B是查询操作,假设A请求先执行,会先删除缓存中的数据,然后去更新数据库,B请求查询缓存发现为空,会去查询数据库,并把这个值放到缓存中,在B查询数据库时A还没有完全更新成功,所以B查询并放到缓存中的是旧的值,并且以后每次查询缓存中的值都是错误的旧值。

这种情况的解决方法通常是采用延迟双删,就是为保证A操作已经完成,最后再删除一次缓存

逻辑很简单,删除缓存后,休眠一会儿再删除一次缓存,虽然逻辑看起来简单,但实现起来并不容易,问题就出在延迟时间设置多少合适,延迟时间一般大于B操作读取数据库+写入缓存的时间,这个只能是估算,一般可以考虑读业务逻辑数据的耗时 + 几百毫秒。

在实际应用中,还是先更新数据库后删除缓存这种方案用的多些,因为延迟双删这个操作的颗粒度过于庞大,不太适合实际开发。

需要注意的是,无论哪种方案,如果数据库采取读写分离+主从复制延迟的话,即使采用先更新数据库后删除缓存也会出现类似先删除缓存后更新数据库中出现的问题,举个例子

  1. A操作更新主库后,删除了缓存
  2. B操作查询缓存没有查到数据,查询从库拿到旧值
  3. 主库将新值同步到从库
  4. B操作将拿到的旧值写入缓存

这就造成了缓存中的是旧值,数据库中的是新值,解决方法还是上面说的延迟双删,延迟时间要大于主从复制的时间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/757054.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity Toggle处理状态变化事件

Toggle处理状态变化事件,有两个方法。 法一、通过Inspector面板设置 实现步骤: 在Inspector面板中找到Toggle组件的"On Value Changed"事件。单击""按钮添加一个新的监听器。拖动一个目标对象到"None (Object)"字段&am…

研究人员发现 OpenAI ChatGPT、Google Gemini 的漏洞

自 OpenAI 推出 ChatGPT 以来,生成式 AI 聊天机器人的数量及其在企业中的采用率在一年多时间里呈爆炸式增长,但网络安全专业人士的担忧也随之增加,他们不仅担心威胁组织对新兴技术的使用,还担心大型网络的安全性及模型&#xff08…

点云预处理——滤波、旋转和平移等处理

目录 一、环境配置 二、步骤 一、环境配置 安装好ubuntu系统和ROS环境 操作系统: Ubuntu 20.04 wget http://fishros.com/install -O fishros && . fishros 二、步骤 打开终端,并在终端命令行输入以下指令: git clone https://gitee.com/wccworld/…

MNN Session 创建执行器(六)

系列文章目录 MNN createFromBuffer(一) MNN createRuntime(二) MNN createSession 之 Schedule(三) MNN createSession 之创建流水线后端(四) MNN Session::resize 之流水线编码&am…

MFC界面美化第三篇----自绘按钮(重绘按钮)

1.前言 最近发现读者对我的mfc美化的专栏比较感兴趣,因此在这里进行续写,这里我会计划写几个连续的篇章,包括对MFC按钮的美化,菜单栏的美化,标题栏的美化,list列表的美化,直到最后形成一个完整…

中小企业Java/SpringBoot体系技术抽象沉淀

目录 1. 起因 2. 参考 3.总结: 1. 起因 企业开发的过程中会逐渐沉淀自己的一些公共starter&方法等;建议可以整合开源项目与自身沉淀的一些做一个统一的parent包 2. 参考 内容参考内容框架包,基础core包,统一返回&#x…

详解Redis的持久化RDB和AOF

Redis的持久化是将内存中的数据同步到硬盘的过程 具体来说,Redis支持两种主要的持久化方式:RDB 和 AOF。 RDB(Redis Database) 简介 默认持久化方式 RDB会将内存中的数据快照保存到磁盘上的一个二进制文件中。这个文件包含了…

创建React+Ts项目

1.创建脚手架 create-react-app 项目名称 --template typescript 2.配置路径别名 配置路径别名---React_h5 路径别名设置-CSDN博客 3.添加组件库 npm i antd --save App.tsx 文件 引用 ant design react import React from react;import { Button } from antd;function …

NLP---Bert分词

目录&#xff1a; Q&#xff1a;bert分词步骤1&#xff1a;构建N * N 的相关性矩阵&#xff0c;计算相邻两个字的相关性&#xff0c;低的话&#xff08;<阈值&#xff09;就切割。2&#xff1a;将A词进行mask计算出A的embedding&#xff0c;然后将AB两个词一起mask&#xff…

4.线性数据结构——3.栈及例题

标准库的栈 定义&#xff1a;stack<typename> myStack;大小&#xff1a;size()压栈&#xff1a;push()弹栈&#xff1a;pop()栈顶&#xff1a;top()判空&#xff1a;empty() #include <cstdio> #include <string> #include <map> #include <algor…

视觉信息处理和FPGA实现第5次作业-Matlab实现图像逆时针旋转90度

一、Matlab2022a安装 链接&#xff1a;https://pan.quark.cn/s/6e177bc7c11d 提取码&#xff1a;dKNN 二、Matlab使用 2.1 新建一个脚本文件&#xff08;.m文件&#xff09; 2.2 另存为到便于归档的地方 考虑到.m文件如果不是全英文路径&#xff0c;也有可能会出问题&#…

Linux 服务升级:MySQL 主从(半同步复制) 平滑升级

目录 一、实验 1.环境 2.Mysql-shell 检查工具兼容性 3.逻辑备份MySQL数据 4.备份MySQL 数据目录、安装目录、配置文件 5.MySQL 升级 6.master节点 使用systemd管理mysql8 7. slave1 节点升级 8. slave2 节点升级 9.半同步设置 二、问题 1.mysqldump备份报错 2.Inn…

Docker部署dart-frog服务

参考&#xff1a; dart-frog官网&#xff1a;https://dartfrog.vgv.dev/docs/overview 使用 Dart Frog 体验 Dart 服务端开发 - 简书 打包项目 按照demo新增项目后&#xff0c;执行&#xff1a; dart_frog build 等待build后生成 build 文件夹&#xff0c;这个文件夹就是需要…

【爬虫】专栏文章索引

为了方便 快速定位 和 便于文章间的相互引用等 作为一个快速准确的导航工具 爬虫 目录&#xff1a; &#xff08;一&#xff09;web自动化和接口自动化 &#xff08;二&#xff09;实战-爬取Boss直聘信息数据

详细分析Python模块中的雪花算法(附模板)

目录 前言1. 基本知识2. 模板3. Demo 前言 分布式ID的生成推荐阅读&#xff1a;分布式ID生成方法的超详细分析&#xff08;全&#xff09; 1. 基本知识 Snowflake 算法是一种用于生成全局唯一 ID 的分布式算法&#xff0c;最初由 Twitter 设计并开源 它被设计用于解决分布式…

使用甘特图实现高效时间规划

甘特图虽然看似简单,却蕴含着规划时间的奥秘。它将复杂的工序分解成逻辑严密的任务链条,每个短小的条形图块都清晰地道出一个任务的起始、持续和终止。就像指挥家挥舞手中的棒,每个动作都精确拍着节奏,确保各个乐手分工合作、行云流水。择一个好用的甘特图制作工具,会让你事半功…

C#,图论与图算法,有向图(Graph)之环(Cycle)判断的颜色算法与源代码

1 检查该图是否包含循环 给定一个有向图,检查该图是否包含循环。如果给定的图形至少包含一个循环,则函数应返回true,否则返回false。 方法:深度优先遍历可用于检测图中的循环。连接图的DFS生成树。只有当图中存在后缘时,图中才存在循环。后边是从节点到自身(自循环)或…

Linux umount命令教程:如何安全地卸载文件系统(附实例详解和注意事项)

Linux umount命令介绍 umount命令在Linux和UNIX操作系统中用于卸载已挂载的文件系统。它通过从Linux默认文件系统的挂载点删除连接&#xff0c;使外部设备或目录不再是Linux文件系统层次结构的一部分。这个命令确保任何正在进行的文件操作都已完成&#xff0c;防止数据损坏或丢…

.NET 异步编程(异步方法、异步委托、CancellationToken、WhenAll、yield)

文章目录 异步方法异步委托async方法缺点CancellationTokenWhenAllyield 异步方法 “异步方法”&#xff1a;用async关键字修饰的方法 异步方法的返回值一般是Task<T>&#xff0c;T是真正的返回值类型&#xff0c;Task<int>。惯例&#xff1a;异步方法名字以 Asy…

ClickHouse列式存储基础笔记

一、基础概念 ClickHouse是俄罗斯Yandex在2016年开源&#xff0c;使用C编写的列式存储数据库&#xff0c;近几年在OLAP领域大范围应用。国内&#xff1a;阿里、字节、腾讯 、虎牙、青云、新浪等在使用&#xff1b;国外&#xff1a;优步、Ebay、Spotify、思科等在使用. 官网&a…