缓存穿透,缓存雪崩,缓存击穿

article/2025/8/25 21:53:59

一,缓存穿透

原因:一个请求来访问某个数据,发现缓存中没有,直接去DB中访问。此种情况就是穿透。(正常情况下缓存跟数据库中数据都是存在,异常情况下会导致)

特点:因传递了非法的key,导致缓存跟数据库中都无法查询

方法:

1.添加参数校验,校验传递的值是否合法,再决定是否处理该请求。

2.设置缓存空值,为访问的key缓存中设置对应的nil值,这样当访问过来的发现key的value是空值值,就直接返回nil了。并设置过期时间。

3,布隆过滤器,就是利用高效的数据结构,在请求跟缓存之间设置一个布隆过滤器,请求来的时候,直接判断当前的key是否存在DB中。也能很好防止发生缓存穿透。不存在直接返回,存在的话,直接访问数据库,在刷新缓存即可。

package mainimport ("database/sql""encoding/json""errors""fmt""log""sync""time""github.com/gin-gonic/gin""github.com/go-redis/redis"_ "github.com/go-sql-driver/mysql""gorm.io/driver/mysql""gorm.io/gorm"
)type User struct {ID       int64Username string `gorm:"column:username"`Password string `gorm:"column:password"`// 时间戳CreateTime int64 `gorm:"column:createtime"`
}// 数据库操作
var DB *sql.DBfunc InitDB() error {// 初始化数据库db, err := sql.Open("mysql","root:password@tcp(127.0.0.1:3306)/my_sql?charset=utf8")if err != nil {log.Fatal(err.Error())return err}DB = dbreturn nil
}// redis
var client *redis.Clientfunc InitRedis() {cl := redis.NewClient(&redis.Options{Addr:     "127.0.0.1:6379",Password: "password",})client = cl
}var OrmDB *gorm.DB// gorm
func InitOrmDB() {dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local","root", "password", "127.0.0.1", 3306, "my_sql")// 连接 mysqldb, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})if err != nil {panic("数据库连接失败, error" + err.Error())}OrmDB = db
}// 布隆过滤器,高可用访问kv
var userMap sync.Mapfunc main() {InitOrmDB()InitRedis()r := gin.Default()router := r.Group("/user")router.POST("/add", addUser)router.GET("/get", getUser)fmt.Println("Server is running ...")r.Run(":8080")
}// add user
func addUser(c *gin.Context) {name := c.Request.FormValue("name")password := c.Request.FormValue("password")fmt.Println("++=", name, password)// 检查表是是否存在if !OrmDB.Migrator().HasTable("users") {fmt.Println("user is not exist")OrmDB.Migrator().CreateTable(&User{})}// 构建数据ur := &User{Username:   name,Password:   password,CreateTime: time.Now().Unix(),}if err := OrmDB.Create(ur).Error; err != nil {fmt.Println("插入失败", err)return}// 将数据添加到布隆过滤器userMap.Store(name, ur)c.JSON(200, gin.H{"message": "success to add a user info"})
}func getUser(c *gin.Context) {// 缓存中查询id := c.Request.FormValue("id")name := c.Request.FormValue("name")// 添加一个布隆过滤器if _, ok := userMap.Load(name); !ok {// 不存在该用户,说明非法参数,直接返回,可以避免缓存穿透fmt.Println("illlage user", name)return}// 缓存穿透,从数据库中查询,因为使用了非法参数,一般情况下,缓存跟数据库都是有数据的key := id + "_" + nameret := client.Get(key)if ret.Err() == nil {fmt.Println("cache get")c.JSON(200, gin.H{"user": ret.String()})return}fmt.Println("cache is not data,will go to db find ")// 数据库查询us := &User{}result := OrmDB.Where("username = ? AND id = ?", name, id).First(&us)if errors.Is(result.Error, gorm.ErrRecordNotFound) {// 为当前的非法key设置nil,直接返回,或者使用布隆过滤器client.Set(key, nil, time.Second*10) // 临时设置一个nil,避免后续请求大量访问dbfmt.Println("找不到记录")return} else {retUser, _ := json.Marshal(us)// 将数据重新写入到缓存retSet := client.Set(key, retUser, 0) // 设置都是不过期,仅仅测试使用if retSet.Err() != nil {fmt.Println("set cache is failed")return}c.JSON(200, gin.H{"user": retUser})}
}

二,缓存雪崩

原因:因大量的数据在同一时间内因为过期失效了,与此同时大量的请求到来,发现缓存中没有数据,都奔向DB,结果导致DB承受不了大规模的请求处理导致服务崩溃。(当然还有可能是缓存宕机)

特点:大量不同数据在缓存同一时间同时失效,并被大量请求访问至DB导致

方法:按照具体的实际情况来解决处理。

a,缓存宕机导致,那么就采用集群模式,并设置主从 + 哨兵模式,确保容灾的发生能及时供给提供服务。另外再开启持久化,宕机服务重启之后重新将数据加载出来。

b,数据过期导致,那么就采用在设置数据过期时间每个key添加随机数,确保不会再某一时间,大量的key同时失效。在这针对热数据,可以设置永不过期处理,有更新进行更新处理就可。

c.如果事先没考虑到雪崩问题,但是已经发生了。

处理方法:可采取限流 + 本地缓存进行补救,但是还得看具体情况具体对待。

三,缓存击穿

原因:因某个数据过期了,刚好此时大量请求都请求到DB上情况导致。

特点:某一数据因过期,导致访问缓存拿不到数据,击穿缓存去DB拿取。

该种情景跟雪崩有点类似。但是也有差异,雪崩是大面积缓存失效导致。击穿是一个热key在不停的被访问(刚好失效)。就会造成某一时候数据库的压力过大。

方法:

a.可以根据具体情况设置热数据不过期,定期刷新数据即可。

b,访问数据库加锁,第一个请求访问加锁,其余来访问,会被阻塞,一直到锁被释放,当后面的请求访问时,发现已经有缓存了,(因为前面访问过DB会将数据刷新到缓存中)就直接访问缓存了。但是该方法会导致性能,从而降低了吞吐量。所有要结合业务场景思考权衡利弊来做处理。


http://chatgpt.dhexx.cn/article/fATZa0Dy.shtml

相关文章

如何避免缓存穿透、缓存击穿、缓存雪崩?

如何避免缓存穿透、缓存击穿、缓存雪崩? 缓存穿透 先来看一下缓存穿透,顾名思义,是指业务请求穿过了缓存层,落到持久化存储上。在大多数场景下,我们应用缓存是为了承载前端业务请求,缓存被击穿以后&#x…

缓存穿透、缓存击穿、缓存雪崩解决方案

微信搜索【程序员囧辉】,关注这个坚持分享技术干货的程序员。 前言 ​ 我一个QPS不到10的项目,天天问我缓存穿透、缓存击穿、缓存雪崩,我是真滴难。 可能大家经常会有这种感受,但是只要是面试要问的题目,就算用不上&…

缓存穿透 缓存击穿 缓存雪崩 这三者是什么 如何处理

通常我们使用缓存中间件的方式 将数据库的热点数据缓存到Redis中 尽量去缓存中查找数据,目的就是为了减轻数据库的压力 那什么是 缓存穿透,缓存击穿 与 缓存雪崩 呢 ? 缓存穿透 当Redis中不存在某个key时,将对数据库进行查询操作 但如果数据库也不存在 就会造成每一个请求即…

应对缓存击穿的解决方法

一.什么样的数据适合缓存? 分析一个数据是否适合缓存,我们要从访问频率、读写比例、数据一致性等要求去分析. 二.什么是缓存击穿 在高并发下,多线程同时查询同一个资源,如果缓存中没有这个资源,那么这些线程都会去数据库查找,对数据库造成极大压力,缓存失去存在的意义.打个…

redis缓存击穿

缓存击穿: 缓存击穿是指,针对某个访问非常频繁的热点数据的请求,无法在缓存中进行处理,紧接着,访问该数据的大量请求,一下子都发送到了后端数据库,导致了数据库压力激增,会影响数据…

【缓存】缓存穿透、缓存击穿、缓存雪崩及其解决方案

文章目录 缓存穿透缓存击穿缓存雪崩大量数据同时过期Redis 故障宕机 总结来源 用户的数据一般都是存储于数据库,数据库的数据是落在磁盘上的,磁盘的读写速度可以说是计算机里最慢的硬件了。 当用户的请求,都访问数据库的话,请求数…

Redis 缓存击穿,缓存穿透,缓存雪崩原因+解决方案

一、前言 在我们日常的开发中,无不都是使用数据库来进行数据的存储,由于一般的系统任务中通常不会存在高并发的情况,所以这样看起来并没有什么问题,可是一旦涉及大数据量的需求,比如一些商品抢购的情景,或者…

Redis缓存击穿、雪崩、穿透!(超详细)

缓存的击穿、穿透和雪崩应该是再熟悉不过的词了,也是面试常问的高频试题。 不过,对于这三大缓存的问题,有很多人背过了解决方案,却少有人能把思路给理清的。 而且,网络上仍然充斥着,大量不太靠谱的解决方案…

缓存穿透、缓存击穿、缓存雪崩如何应对

参考连接:redis避免缓存穿透为什么缓存空对象而不是null? - 知乎 缓存穿透:key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。比如用一个不存在的…

缓存穿透、缓存击穿、缓存雪崩区别和解决方案

一、缓存处理流程 前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果。 二、缓存穿透 描述: …

缓存穿透,缓存雪崩,缓存击穿的超详解

文章目录 1、缓存穿透问题的解决思路2、缓存雪崩问题及解决思路3、缓存击穿问题及解决思路 1、缓存穿透问题的解决思路 缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库,失去了缓存的…

redis 缓存穿透,缓存击穿,缓存雪崩

虽然我们在使用 redis 缓存的时候非常的爽,它大大的提高了我们应用程序的性能和效率,尤其是数据查询方面,咱们不用直接去持久化的数据库中查询数据,而是到内存中查询数据即可 事物总是有两面的,用的爽的同时&#xff…

缓存穿透、缓存击穿、缓存雪崩的理解和解决方案

目录 一、缓存穿透 二、缓存击穿 三:缓存雪崩 在生产环境中,会因为很多的原因造成访问请求绕过了缓存,都需要访问数据库持久层,虽然对Redsi缓存服务器不会造成影响,但是数据库的负载就会增大,使缓存的作…

详解缓存穿透、缓存雪崩、缓存击穿

背景 在现代软件架构中,缓存的应用已经非常普及。缓存的使用在面试和实践中都是避不开的硬技能、硬知识,如果你说还不太熟悉缓存的使用,可能都不好意思说自己是程序员。 这篇文章,带大家进一步学习在缓存使用中不得不考虑三个特…

【Redis】缓存击穿问题及其解决方案

【Redis】缓存击穿问题及其解决方案 文章目录 【Redis】缓存击穿问题及其解决方案1. 缓存击穿概念2. 解决方案2.1 互斥锁2.1.1 互斥锁的优缺点2.1.2 互斥锁的代码实现 2.2 逻辑过期2.2.1 逻辑过期的优缺点2.2.2 逻辑过期的代码实现 1. 缓存击穿概念 缓存击穿:缓存击…

Redis 缓存穿透、缓存击穿、缓存雪崩

文章目录 一、缓存穿透1. 概念2. 解决方案 二、缓存击穿1. 概念2. 解决方案 三、缓存雪崩1. 概念2. 解决方案 一、缓存穿透 1. 概念 key 对应的数据在redis中并不存在,每次针对此 key的请求从缓存获取不到,请求转发到数据库,访问量大了可能…

Redis中的缓存穿透、雪崩、击穿的原因以及解决方案(详解)

一、概述 ① 缓存穿透:大量请求根本不存在的key(下文详解) ② 缓存雪崩:redis中大量key集体过期(下文详解) ③ 缓存击穿:redis中一个热点key过期(大量用户访问该热点key,…

Redis——缓存击穿、穿透、雪崩

1、缓存穿透: (1)问题描述:key对应的数据并不存在,每次请求访问key时,缓存中查找不到,请求都会直接访问到数据库中去,请求量超出数据库时,便会导致数据库崩溃。如一个用…

ping端口

1.ping端口: telnet 62.78.63.209 10105 2.如果提示telnet不是内部或外部命令… 则:右击“此电脑”–>选择“控制面板主页”,单击“程序”,如图: 3.完成。

windows下ping端口

上图的操作完成以后 进入dos控制台 输入telnet ip地址 端口号 回车 标识已ping通 ping不通是这种提示 转载于:https://www.cnblogs.com/shianliang/p/8639392.html