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

golang sync.singleflight 解决热点缓存穿透问题

gosync 包中,有一个 singleflight 包,里面有一个 singleflight.go 文件,代码加注释,一共 200 行出头。内容包括以下几块儿:

  1. Group 结构体管理一组相关的函数调用工作,它包含一个互斥锁和一个 map,mapkey 是函数的名称,value 是对应的 call 结构体。
  2. call 结构体表示一个 inflight 或已完成的函数调用,包含等待组件 WaitGroup、调用结果 valerr、调用次数 dups 和通知通道 chans
  3. Do 方法接收一个 key 和函数 fn,它会先查看 map 中是否已经有这个 key 的调用在 inflight,如果有则等待并返回已有结果,如果没有则新建一个 call 并执行函数调用。
  4. DoChan 类似 Do 但返回一个 channel 来接收结果。
  5. doCall 方法包含了具体处理调用的逻辑,它会在函数调用前后添加 deferrecover panic 和区分正常 returnruntime.Goexit
  6. 如果发生 panic,会将 panicwraps 成错误返回给等待的 channel,如果是 goexit 会直接退出。正常 return 时会将结果发送到所有通知 channel
  7. Forget 方法可以忘记一个 key 的调用,下次 Do 时会重新执行函数。

这个包通过互斥锁和 map 实现了对相同 key 的函数调用去重,可以避免对已有调用的重复计算,同时通过 channel 机制可以通知调用者函数执行结果。在一些需要确保单次执行的场景中,可以使用这个包中的方法。

通过 singleflight 可以很容易实现缓存和去重的效果,避免重复计算,接下来,我们来模拟一下并发请求可能导致的缓存穿透场景,以及如何用 singleflight 包来解决这个问题:

package mainimport ("context""fmt""golang.org/x/sync/singleflight""sync/atomic""time")type Result string
// 模拟查询数据库
func find(ctx context.Context, query string) (Result, error) {return Result(fmt.Sprintf("result for %q", query)), nil
}func main() {var g singleflight.Groupconst n = 200waited := int32(n)done := make(chan struct{})key := "this is key"for i := 0; i < n; i++ {go func(j int) {v, _, shared := g.Do(key, func() (interface{}, error) {ret, err := find(context.Background(), key)return ret, err})if atomic.AddInt32(&waited, -1) == 0 {close(done)}fmt.Printf("index: %d, val: %v, shared: %v\n", j, v, shared)}(i)}select {case <-done:case <-time.After(time.Second):fmt.Println("Do hangs")}time.Sleep(time.Second * 4)
}

在这段程序中,如果重复使用查询结果,shared 会返回 true,穿透查询会返回 false

上面的设计中还有一个问题,就是在 Do 阻塞时,所有请求都会阻塞,内存可能会出现大的问题。

此时,Do 可以更换为DoChan,两者实现上完全一样,不同的是,DoChan() 通过 channel 返回结果。因此可以使用 select 语句实现超时控制

ch := g.DoChan(key, func() (interface{}, error) {ret, err := find(context.Background(), key)return ret, err
})
// Create our timeout
timeout := time.After(500 * time.Millisecond)var ret singleflight.Result
select {
case <-timeout: // Timeout elapsedfmt.Println("Timeout")return
case ret = <-ch: // Received result from channelfmt.Printf("index: %d, val: %v, shared: %v\n", j, ret.Val, ret.Shared)
}

在超时时主动返回,不阻塞。

此时又引入了另一个问题,这样的每一次的请求,并不是高可用的,成功率是无法保证的。这时候可以增加一定的请求饱和度来保证业务的最终成功率,此时一次请求还是多次请求,对于下游服务而言并没有太大区别,此时使用  singleflight  只是为了降低请求的数量级,那么可以使用 Forget() 来提高下游请求的并发。

ch := g.DoChan(key, func() (interface{}, error) {go func() {time.Sleep(10 * time.Millisecond)fmt.Printf("Deleting key: %v\n", key)g.Forget(key)}()ret, err := find(context.Background(), key)return ret, err
})

当然,这种做法依然无法保证100%的成功,如果单次的失败无法容忍,在高并发的场景下需要使用更好的处理方案,比如牺牲一部分实时性、完全使用缓存查询 + 异步更新等。

相关文章:

golang sync.singleflight 解决热点缓存穿透问题

在 go 的 sync 包中&#xff0c;有一个 singleflight 包&#xff0c;里面有一个 singleflight.go 文件&#xff0c;代码加注释&#xff0c;一共 200 行出头。内容包括以下几块儿&#xff1a; Group 结构体管理一组相关的函数调用工作,它包含一个互斥锁和一个 map,map 的 key 是…...

4、Linux驱动开发:设备-设备号设备号注册

目录 &#x1f345;点击这里查看所有博文 随着自己工作的进行&#xff0c;接触到的技术栈也越来越多。给我一个很直观的感受就是&#xff0c;某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了&#xff0c;只有经常会用到的东西才有可能真正记…...

C++(MFC)调用Python

环境&#xff1a; phyton版本&#xff1a;3.10 VS版本&#xff1a;VS2017 包含文件头&#xff1a;Python\Python310\include 包含库文件&#xff1a;Python\Python310\libs 程序运行期间&#xff0c;以下函数只需要调用一次即可&#xff0c;重复调用会导致崩溃 void Initial…...

深度学习实践——循环神经网络实践

系列实验 深度学习实践——卷积神经网络实践&#xff1a;裂缝识别 深度学习实践——循环神经网络实践 深度学习实践——模型部署优化实践 深度学习实践——模型推理优化练习 代码可见于&#xff1a; 深度学习实践——循环神经网络实践 0 概况1 架构实现1.1 RNN架构1.1.1 RNN架…...

docker简单web管理docker.io/uifd/ui-for-docker

要先pull这个镜像docker.io/uifd/ui-for-docker 这个软件默认只能使用9000端口&#xff0c;别的不行&#xff0c;因为作者在镜像制作时已加入这一层 刚下下来镜像可以通过docker history docker.io/uifd/ui-for-docker 查看到这个端口已被 设置 如果在没有设置br0网关时&…...

SpringBoot内嵌的Tomcat:

SpringBoot内嵌Tomcat源码&#xff1a; 1、调用启动类SpringbootdemoApplication中的SpringApplication.run()方法。 SpringBootApplication public class SpringbootdemoApplication {public static void main(String[] args) {SpringApplication.run(SpringbootdemoApplicat…...

企业级docker应用注意事项

现在很多企业使用容器化技术部署应用&#xff0c;绕不开的docker技术&#xff0c;在生产环境docker常用操作总结。参考&#xff1a;https://juejin.cn/post/7259275893796651069 1. 尽可能使用官方镜像 在docker hub 官方 使用后面带有 DOCKER OFFICIAL IMAGE 标签的镜像&…...

腾讯云高性能计算集群CPU服务器处理器说明

腾讯云高性能计算集群以裸金属云服务器为节点&#xff0c;通过RDMA互联&#xff0c;提供了高带宽和极低延迟的网络服务&#xff0c;能满足大规模高性能计算、人工智能、大数据推荐等应用的并行计算需求&#xff0c;腾讯云服务器网分享腾讯云服务器高性能计算集群CPU处理器说明&…...

tinkerCAD案例:23.Tinkercad 中的自定义字体

tinkerCAD案例&#xff1a;23.Tinkercad 中的自定义字体 原文 Tinkercad Projects Tinkercad has a fun shape in the Shape Generators section that allows you to upload your own font in SVG format and use it in your designs. I’ve used it for a variety of desi…...

Box-Cox 变换

Box-cox 变化公式如下&#xff1a; y ( λ ) { y λ − 1 λ λ ≠ 0 l n ( y ) λ 0 y^{(\lambda)}\left\{ \begin{aligned} \frac{y^{\lambda} - 1}{\lambda} && \lambda \ne 0 \\ ln(y) && \lambda 0 \end{aligned} \right. y(λ)⎩ ⎨ ⎧​λyλ−1​ln…...

Linux wc命令用于统计文件的行数,字符数,字节数

Linux wc命令用于计算字数。 利用wc指令我们可以计算文件的Byte数、字数、或是列数&#xff0c;若不指定文件名称、或是所给予的文件名为"-"&#xff0c;则wc指令会从标准输入设备读取数据。 语法 wc [-clw][–help][–version][文件…] 参数&#xff1a; -c或–b…...

Python读取多个栅格文件并提取像元的各波段时间序列数据与变化值

本文介绍基于Python语言&#xff0c;读取文件夹下大量栅格遥感影像文件&#xff0c;并基于给定的一个像元&#xff0c;提取该像元对应的全部遥感影像文件中&#xff0c;指定多个波段的数值&#xff1b;修改其中不在给定范围内的异常值&#xff0c;并计算像元数值在每一景遥感影…...

Linux 之 wget curl

wget 命令 wget是非交互式的文件下载器&#xff0c;可以在命令行内下载网络文件 语法&#xff1a; wget [-b] url 选项&#xff1a; -b &#xff0c;可选&#xff0c;background 后台下载&#xff0c;会将日志写入到 当前工作目录的wget-log文件 参数 url &#xff1a; 下载链…...

AngularJS 和 React区别

目录 1. 背景&#xff1a;2. 版本&#xff1a;3. 应用场景&#xff1a;4. 语法&#xff1a;5. 优缺点&#xff1a;6. 代码示例&#xff1a; AngularJS 和 React 是两个目前最为流行的前端框架之一。它们有一些共同点&#xff0c;例如都是基于 JavaScript 的开源框架&#xff0c…...

【Solr】Solr搜索引擎使用

文章目录 一、什么是Solr?二 、数据库本身就支持搜索啊,干嘛还要搞个什么solr?三、如果我们想要使用solr那么首先我们得安装它 一、什么是Solr? 其实我们大多数人都使用过Solr,也许你不会相信我说的这句话,但是事实却是如此啊 ! 每当你想买自己喜欢的东东时,你可能会打开某…...

一起学算法(选择排序篇)

距离上次更新已经很久了&#xff0c;以前都是非常认真的写笔记进行知识分享&#xff0c;但是带来的情况并不是很好&#xff0c;一度认为发博客是没有意义的&#xff0c;但是这几天想了很多&#xff0c;已经失去了当时写博客的初心了&#xff0c;但是我觉得应该做点有意义的事&a…...

智能体的主观和能动

摘要 智能体的主动性是提升智能机器的能力的关键。围绕智能体的主动性存在很多思想迷雾&#xff0c;本文继续我们以前的工作&#xff0c;试图清理这些概念上的问题。我们的讨论显示&#xff1a;要研究主动性&#xff0c;并不一定需要研究意识&#xff0c;仅需要研究主观和能动就…...

AB 压力测试

服务器配置 阿里云Ubuntu 64位 CPU1 核 内存2 GB 公网带宽1 Mbps ab -c100 -n1000 http://127.0.0.1:9501/ -n&#xff1a;在测试会话中所执行的请求个数。默认时&#xff0c;仅执行一个请求。 -c&#xff1a;一次产生的请求个数。默认是一次一个。 ab -c 100 -n 200 ht…...

多旋翼物流无人机节能轨迹规划(Python代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f308;3 Python代码实现 &#x1f389;4 参考文献 &#x1f4a5;1 概述 多旋翼物流无人机的节能轨迹规划是一项重要的技术&#xff0c;可以有效减少无人机的能量消耗&#xff0c;延长飞行时间&#xff0c;提高物流效率…...

Vue通过指令 命令将打包好的dist静态文件上传到腾讯云存储桶 (保存原有存储目录结构)

1、在项目根目录创建uploadToCOS.js文件 &#xff08;建议起简单的名字 方便以后上传输入命令方便&#xff09; 2、uploadToCOS.js文件代码编写 const path require(path); const fs require(fs); const COS require(cos-nodejs-sdk-v5);// 配置腾讯云COS参数 const cos n…...

论文写到一半卡壳了?师兄推荐这几个AI写作辅助软件

写论文最怕的就是卡壳&#xff0c;尤其是当思路混乱、资料繁杂、格式要求又高时&#xff0c;很容易陷入停滞。其实&#xff0c;论文写作的关键不在于苦熬&#xff0c;而在于用对工具、走对流程——不少资深教授都建议学生提前布局&#xff0c;借助 AI 工具提升效率。比如千笔AI…...

岩土工程渗流问题之有限单元法--坝基渗流、围堰、土石坝自由面、黏土垫层防渗、污染土固化后渗控

第一天 有限元编程基础知识1.有限单元法基础简介&#xff08;离散化、存储策略及方程解法、边界条件的处理&#xff09;2.编程语言Fortran及编译工具Intel Visual Fortran(IVF)简介3.Fortran/Matlab/Julia等开源代码及程序库&#xff08;geomlib/femlib&#xff09;简介4.水工…...

Gemini3.1Pro:自回归与扩散模型的路线之争

扩散语言模型与传统自回归&#xff1a;Gemini 3.1 Pro 的路线选择怎么理解&#xff1f;过去很长一段时间&#xff0c;大模型主流架构基本都围绕“传统自回归&#xff08;Autoregressive&#xff09;”展开&#xff1a;一次生成一个 token&#xff0c;靠注意力把上下文信息逐步融…...

昇腾CANN的算子“零件厂“:catlass仓库到底在生产什么

如果把昇腾NPU上的大模型算子比作一辆汽车&#xff0c;FlashAttention是发动机&#xff0c;RMSNorm是刹车片&#xff0c;RoPE是方向盘——那catlass是什么&#xff1f;是生产这些零件的模具和机床。 第一次接触昇腾CANN生态的时候&#xff0c;很容易忽略catlass。它不像ops-tr…...

Cortex-M55内存属性与缓存机制深度解析

1. Cortex-M55内存属性与缓存机制解析 在嵌入式系统开发中&#xff0c;正确配置内存属性对于系统性能和功能正确性至关重要。Cortex-M55作为Armv8-M架构的处理器&#xff0c;通过内存保护单元(MPU)和内存属性间接寄存器(MAIR_ATTR)提供了灵活的内存属性配置能力。本文将深入剖析…...

博德之门3 2026最新免费下载 一键转存 永久更新 (看到速转存 资源随时走丢)

下载链接 电子角色扮演游戏的范式革新&#xff1a;博德之门3的技术架构与玩法机制剖析 在现代电子游戏工业中&#xff0c;古典角色扮演游戏&#xff08;CRPG&#xff09;曾因其高昂的学习门槛与繁复的规则体系&#xff0c;一度被视为分众市场的垂类产品。然而&#xff0c;2023…...

【VibeCoding系列教程01】2026年最狠的职场外挂:我靠“说话“让AI替我加班,同事以为我开了挂

你们发现没有&#xff0c;现在这个世界越来越离谱了。前两天我朋友问我&#xff0c;说老哥&#xff0c;我想做个网站&#xff0c;得学多久&#xff1f;我说&#xff0c;搁以前&#xff0c;你得先学HTML、CSS、JavaScript&#xff0c;再学框架、学部署&#xff0c;顺利的话&…...

如何用Playnite打造你的终极游戏库:统一管理Steam、Epic、GOG等20+平台游戏

如何用Playnite打造你的终极游戏库&#xff1a;统一管理Steam、Epic、GOG等20平台游戏 【免费下载链接】Playnite Video game library manager with support for wide range of 3rd party libraries and game emulation support, providing one unified interface for your gam…...

为Claude Code配置Taotoken密钥与模型解决访问限制

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 为Claude Code配置Taotoken密钥与模型解决访问限制 Claude Code 作为一款高效的编程助手&#xff0c;其原生服务有时会因地域或配额…...

如何在Windows上让DualShock 3控制器重获新生?DsHidMini虚拟HID驱动技术解析

如何在Windows上让DualShock 3控制器重获新生&#xff1f;DsHidMini虚拟HID驱动技术解析 【免费下载链接】DsHidMini Virtual HID Mini-user-mode-driver for Sony DualShock 3 Controllers 项目地址: https://gitcode.com/gh_mirrors/ds/DsHidMini 在Windows平台使用索…...