原来sync.Once还能这么用

sync.Once估计大家都不陌生,官方介绍中,

Once is an object that will perform exactly one action

正是因为这个特性,Once常常被用于单例对象的初始化场景。

也正是因为这个特性,其实它还能做一些其他的事情。

缓存击穿

日常背诵八股文,我相信你们对缓存击穿这个词特别熟悉。

缓存击穿一般代指热点key缓存失效(到期|删了),同一时刻大量对热点key的并发请求。缓存找不到数据,所有请求都打入到DB层。此时,身为开发的你,明天和意外就不知道哪个先到了。

为了防止这种情况发生,针对相同key的请求,只需要一个请求(A)到达DB层取数据,其他请求等待A通知就行了。

就像这样,

29d969acc90545a5ac635f6cc56d3c7b.png
图片来源:见附录1

singleflight

Go里有很多防缓存击穿的工具,比如singleflight库。

47b05944218b705622b809c7638420c1.png 913ab940a1180909cb4bb61bdbf57bbe.png

通过上面简单的代码大概能看出,其实就是对key做了缓存。

把一个key对应call结构存储在map中。保证只有一个key真正执行fn()服务 ,其他请求则通过sync.waitGroupwait等待结果。

至于g.docall(c,key,fn)

0d466a3e58d7f2037bbb190d170115f9.png

当带着全村人希望的那个请求,获取到数据,给对应keycall赋值,最终执行done,通知等待这个key全村的村民获取数据。

代码并不复杂。

自定义singleflight

我们也可以实现一个简易版本的。

b5f8452ce1da4d7db2f5952e4bdee3e1.png

代码整体不难,主要的点在于我们是通过通道来实现通知自家兄弟取数据。

最后,让我们使用Once来达到同样的效果,不然标题不白起了嘛。

e4209a02facbf8d6d06943c43b8ac08d.png

上面核心代码都写出来了,实际开发中需要对请求资源做一些超时控制等操作。

总结

平常对Once的使用只停留在初始化工作上,而弱化了它的使用场景。对于其他工具也是一个道理,这就需要去积累和挖掘了。

附录

[1]https://medium.com/codex/caching-system-stability-766bf5fff69f

https://blog.chuie.io/posts/synconce/

给网管个星标,第一时间吸我的知识 👆

喜欢网管的文章内容和写作风格,记得把我安利给更多人。光看公众号不过瘾?可以加我的个人微信(微信号:fsg1233110)

觉得有用就点个在看  👇👇👇

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值