• B站-后台开发岗


    • 项目介绍
    • go的依赖注入,我没听说过所以没回答出来。具体可参考:谈谈 golang 下的依赖注入 - 知乎
    • Redis缓存击穿和缓存穿透的区别
    • 缓存中不存在的数据,DB中存在的数据,如何更新缓存?利用Redis分布式锁来防止大量获取相同key的请求打到DB。但是这样有什么缺点?
      • 在第一个获取分布式锁的线程刷新缓存成功之前,会导致系统等待获取缓存数据的goroutine激增。
    • 要怎么解决上述的goroutine激增问题?
      • 做超时控制,利用go singleflight的 forget 方法,如果超时,所有相关协程统一返回错误
    • go singleflight 库的使用(因为我的项目涉及到缓存模块及缓存击穿的场景)

            go singleflight库对外提供的方法:

    1. //Do方法,传入key,以及回调函数,如果key相同,fn方法只会执行一次,同步等待
    2. //返回值v:表示fn执行结果
    3. //返回值err:表示fn的返回的err
    4. //第三个返回值shared:表示是否是真实fn返回的还是从保存的map[key]返回的,也就是共享的
    5. func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) {
    6. //DoChan方法类似Do方法,只是返回的是一个chan
    7. func (g *Group) DoChan(key string, fn func() (interface{}, error)) <-chan Result {
    8. //暂时未用到:设计Forget 控制key关联的值是否失效,默认以上两个方法只要fn方法执行完成后,内部维护的fn的值也删除(即并发结束后就失效了)
    9. func (g *Group) Forget(key string) {

    背景:singleflight方法可以很好的解决缓存击穿的问题,可以避免大量的流量都会打到DB上进而引起DB压力。但是依然有可能阻塞大量请求导致系统等待获取缓存数据的goroutine激增,因此需要灵活使用 DoCall() 方法和 Forget() 方法。

      

    效果:使用singleflight能有效解决这个问题,限制对同一个键值对的多次重复请求,减少对下游如DB的瞬时流量。

      

    这个库的主要作用就是: 将一组相同的请求合并成一个请求,实际上最终只会有 第一个 请求去访问DB,在其获取到结果后,然后对剩余其他请求返回相同的结果。

    原理:请求1、2、3同时请求相同的key,singleflight机制只会让请求1访问DB,请求1返回的value不仅返回给客户端1,也作为请求2、请求3的结果返回给客户端。这里的多请求理解为多个goroutine并发执行。底层实际上是通过 go map(区分是否是相同key的请求) + lock(线程安全) + waitgroup(阻塞其他请求) 将请求1从DB获取的结果直接通过本地内存去返回给其他相同的请求,其中lock是为了并发安全

      

    总结:golang/sync/singleflight.Group.Do 和 golang/sync/singleflight.Group.DoChan 分别提供了同步和异步的调用方式,这让我们使用起来也更加灵活。

    当我们需要减少对下游的相同请求时,可以使用 golang/sync/singleflight.Group 来增加吞吐量和服务质量,不过在使用的过程中我们也需要注意以下的几个问题:

    • golang/sync/singleflight.Group.Do 和 golang/sync/singleflight.Group.DoChan 一个用于同步阻塞调用传入的函数,一个用于异步调用传入的参数并通过 Channel 接收函数的返回值;
    • golang/sync/singleflight.Group.Forget 可以通知 golang/sync/singleflight.Group 在持有的映射表中删除某个键,接下来对该键的调用就不会等待前面的函数返回了;
    • 一旦调用的函数返回了错误,所有在等待的 Goroutine 也都会接收到同样的错误;

    参考:

    • 简单介绍下localcache本地缓存?gocache?分布式缓存访问速度也很快,但是数据需要跨网络传输,所以提到本地缓存。但是本地缓存由于是占用内存资源的,所以本质上是不能无限存储的,需要加上内存淘汰策略,比如LRU...
    • 手写LRU算法?146. LRU 缓存 

    continue ~

  • 相关阅读:
    flutter中如何定义EventChannel
    小米14系列, OPPO Find N3安装谷歌服务框架,安装Play商店,Google
    项目实战 | Excel导出(三)——Excel导出样式
    朋友圈点赞功能的测试用例(待更新完)
    【Axure教程】通讯录搜索案例(字母定位+模糊搜索)
    信息学奥赛一本通:2029:【例4.15】水仙花数
    Java BufferedWriter类简介说明
    边缘计算AI智能安防监控视频平台车辆违停算法详解与应用
    python图像处理 ——图像锐化
    渗透攻击漏洞——原型链污染
  • 原文地址:https://blog.csdn.net/qq_37102984/article/details/127579195