sync.Once估计大家都不陌生。在官方的介绍中,Once是一个只会执行一个动作的对象。正是由于这个特性,Once经常被用于单例对象。初始化场景。也正是因为这个特性,它其实可以做一些其他的事情。缓存击穿天天背八股文,相信大家对缓存击穿这个词已经很熟悉了。缓存击穿一般是指热点key缓存失效(expiration|deletion),同时大量并发请求热点key。缓存找不到数据,所有请求都发送到DB层。此时,作为开发人员,你不知道哪个先来,明天还是意外。为了防止这种情况发生,对于同一个key的请求,只有一个请求(A)需要到达DB层去取数据,其他请求只需要等待A的通知即可。就这样,图片来源:[1]singleflightGo有很多防缓存崩溃的工具,比如singleflight库。从上面的简单代码可以看出,实际上缓存了key。在映射中存储与调用结构对应的键。保证只有一个key真正执行fn()服务,其他请求通过sync.waitGroup的wait等待结果。至于g.docall(c,key,fn),当以全村想要的request获取到数据时,给key对应的call赋值,最后执行done,通知等待的村民获取数据的关键。代码并不复杂。我们还可以实现自定义单次飞行的简单版本。代码整体不难,重点是我们通过channel通知兄弟们去取数据。最后我们用Once来达到同样的效果,不然标题不是白写的。以上核心代码都写出来了。在实际开发中,需要对请求的资源进行一些超时控制等操作。总结Once平时的使用只停留在初始化工作,弱化了它的使用场景。其他工具也是如此,需要积累和挖掘。附录[1]https://medium.com/codex/caching-system-stability-766bf5fff69fhttps://blog.chuie.io/posts/synconce/
