golang分布式缓存项目 Day6 防止缓存击穿

server/2024/11/15 4:04:07/

该项目原作者:https://github.com/geektutu/7days-golang。本文旨在记录本人做该项目时的一些疑惑解答以及部分的测试样例以便于本人复习。

1 缓存雪崩、缓存击穿与缓存穿透

概念解析

  • 缓存雪崩:缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。缓存雪崩通常因为缓存服务器宕机、缓存的 key设置了相同的过期时间等引起。
  • 缓存击穿:一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到 DB ,造成瞬时DB请求量大、压力骤增。
  • 缓存穿透:查询一个不存在的数据,因为不存在则不会写到缓存中,所以每次都会去请求 DB,如果瞬间流量过大,穿透到 DB,导致宕机。

2 singleflight介绍

singleflight 是一个非常有用的包,它提供了一种机制来抑制对某个函数的多次重复调用。这个包特别适用于避免在高并发场景下对同一资源的重复请求,比如在缓存击穿问题中,多个请求同时访问同一个资源时,singleflight 可以确保这些请求中只有一个实际执行,其他请求则等待这个结果,从而减少对后端服务的压力

核心概念
singleflight 包中定义了一个名为 Group 的结构体类型,它表示一类工作,并形成一个命名空间,在这个命名空间中,可以使用重复抑制来执行工作单元。当你调用 Do 方法时,它接收一个键(key)和一个函数(fn)。这个键是用来标识请求的唯一性,而函数则是实际要执行的操作。Do 方法首先会检查是否已经有相同的请求正在处理中。如果有,那么当前请求就会被放入一个等待队列,直到第一个请求完成并返回结果。这时,所有等待的请求都会收到相同的结果。

使用场景
singleflight 常用于以下场景:

  • 缓存击穿:在高并发的情况下,某个热点数据缓存失效后,大量的请求直接访问数据库,造成数据库的压力过大,甚至宕机的现象。使用singleflight 可以确保即使在缓存失效时,也只有一次数据库请求被执行,其他请求等待这次请求的结果 。
  • 避免重复计算:在需要进行复杂计算且结果可以被多个请求共享的场景中,singleflight 可以确保计算只执行一次,其他请求共享这个结果,从而提高效率。

基本使用
使用 singleflight 时,首先需要创建一个 Group 实例,然后通过调用 Do 方法来执行具体的函数。如果相同的键对应的函数已经
被调用,那么后续的调用将会等待第一个调用的结果,而不是重复执行函数

var g singleflight.Group// 模拟耗时操作
func getData(key string) (string, error) {// 模拟数据库查询耗时time.Sleep(2 * time.Second)return "data for " + key, nil
}func main() {// 第一次调用result1, err, shared := g.Do("key", func() (interface{}, error) {return getData("key")})if err != nil {log.Fatal(err)}fmt.Printf("Result1: %s, Shared: %v\n", result1, shared)// 第二次调用,将共享第一次调用的结果result2, err, shared := g.Do("key", func() (interface{}, error) {return getData("key")})if err != nil {log.Fatal(err)}fmt.Printf("Result2: %s, Shared: %v\n", result2, shared)
}

在这个例子中,即使 getData 函数被调用了两次,但由于 singleflight 的机制,实际的数据库查询操作只执行了一次,两次调用共享了这个结果

3 运用singleflight到geecache中

type Group struct {name      stringgetter    GettermainCache cachepeers     PeerPicker// use singleflight.Group to make sure that// each key is only fetched onceloader *singleflight.Group
}func NewGroup(name string, cacheBytes int64, getter Getter) *Group {// ...g := &Group{// ...loader:    &singleflight.Group{},}return g
}func (g *Group) load(key string) (value ByteView, err error) {// each key is only fetched once (either locally or remotely)// regardless of the number of concurrent callers.viewi, err := g.loader.Do(key, func() (interface{}, error) {if g.peers != nil {if peer, ok := g.peers.PickPeer(key); ok {if value, err = g.getFromPeer(peer, key); err == nil {return value, nil}log.Println("[GeeCache] Failed to get from peer", err)}}return g.getLocally(key)})if err == nil {return viewi.(ByteView), nil}return
}
  • 修改 geecache.go 中的 Group,添加成员变量 loader,并更新构建函数 NewGroup。
  • 修改 load 函数,将原来的 load 的逻辑,使用 g.loader.Do 包裹起来即可,这样确保了并发场景下针对相同的 key,load 过程只会调用一次。

http://www.ppmy.cn/server/141715.html

相关文章

MySQL日期时间函数大全

DAYOFWEEK(date)  返回日期date是星期几(1星期天,2星期一,……7星期六,ODBC标准) mysql> select DAYOFWEEK(1998-02-03);   -> 3 WEEKDAY(date)  返回日期date是星期几(0星期一,1星期二,……6 星期天)。 mysql> select WEEKDAY(1997-10-04 22:23:00);   -> 5…

【VBA实战】用Excel制作排序算法动画续

为什么会产生用excel来制作排序算法动画的念头,参见【VBA实战】用Excel制作排序算法动画一文。这篇文章贴出我所制作的所有排序算法动画效果和源码,供大家参考。 冒泡排序: 插入排序: 选择排序: 快速排序:…

【网络工程】计算机硬件概述

1. 计算机硬件概述 1.1 定义与组成 计算机硬件是指组成计算机系统的物理设备,包括但不限于中央处理器(CPU)、存储器、输入设备、输出设备等。这些设备共同构成了计算机的物理基础,使得计算机能够执行各种计算任务。 CPU&#x…

汽车牌照识别系统的设计与仿真(论文+源码)

1设计原理 车牌识别系统的设计是一项利用车辆的动态视频或者静态图像实现牌照区域定位车牌号码识别的技术。其硬件部分通常包括触发设备、拍摄设备、照明设备、图像收集设备、进行车牌号码识别的处理器等,其软件的关键部分包含车牌区域定位的算法、车牌字符的分割算…

Spring框架之适配器模式 (Adapter Pattern)

适配器模式(Adapter Pattern)详解 适配器模式(Adapter Pattern)是一种结构型设计模式,它的主要作用是将一个类的接口转换成客户端期望的另一个接口,使原本由于接口不兼容而无法一起工作的类可以协同工作。…

《MYSQL45讲》误删数据怎么办

对误删数据分类的话,有 1.delete 误删行 2.drop table 或者truncate table 语句误删表 3.使用drop database 误删数据库 4.使用rm命令误删整个MYSQL实例 一,误删行 一下操作前置条件是:binlog的格式是row,并且binglog_row_im…

SpringBoot(三)

最佳实践 1.SpringBoot 应用如何编写 引入场景依赖 官方文档 查看自动配置了哪些(选做) 自己分析,引入场景对应的自动配置一般都生效了配置文件中 debugtrue 开启自动配置报告。 Negative(不生效)Positive&#xff0…

ctfshow-web入门-反序列化(web260-web264)

目录 1、web260 2、web261 3、web262 4、web263 5、web264 1、web260 要求传入的内容序列化后包含指定内容即可,在 PHP 序列化中,如果键名或值包含 ctfshow_i_love_36D,那么整个序列化结果也会包含这个字符串。 payload: ?…