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

极客兔兔Gee-Cache Day5

  • HTTPPool 既可以是服务端,也可以是客户端,这取决于特定的使用场景和上下文:

    • 作为客户端:当本地缓存没有找到需要的数据时,HTTPPool 需要作为客户端,通过 httpGetter (实现了 PeerGetter 接口)去其他的远程节点(服务端)请求数据。
    • 作为服务端:当其他节点的 HTTPPool 实例(作为客户端)请求当前节点存储的数据时,当前节点的 HTTPPool 实例则作为服务端响应这些请求。
  • HTTPPool实现了PeerPicker接口,httpGetter实现了PeerGetter接口,前者用来找到对应的远程节点(由于每个远程节点对应一个httpGetter,因此实际找到的是httpGetter),后者用来向远处节点请求数据

  • Peer.go

    • package geetype PeerPicker interface {PickPeer(key string) (peer PeerGetter, ok bool)
      }type PeerGetter interface {Get(group string, key string) ([]byte, error)
      }
      
    • PickerPeer用来找到key对应的远程节点,远程节点和PeerGetter一一对应,找到PeerGetter就找到对应的远程节点

    • PeerGetter根据groupkey向远程节点获取数据

  • url.QueryEscape()net/url包,用于将url中的特殊字符用asll码进行替换,防止丢失

  • var _ PeerGetter = (*httpGetter)(nil) :检验接口实现是否正确

  • day5需要实现http的客户端,对于缓存未命中时,需要向远程节点请求数据,此时被作为客户端,http.go中已经在day2实现了服务端的代码,需要再加上客户端

    • HTTPPool实现了上面的PeerPicker接口,实现了其需要实现的PickPeer()函数,该函数返回远程节点对应的PeerGetter,找到PeerGetter就能去访问远程节点的数据

      • // 查找PeerGetter
        func (p *HTTPPool) PickPeer(key string) (PeerGetter, bool) {p.mu.Lock()defer p.mu.Unlock()if peer := p.peers.Get(key); peer != "" && peer != p.self {return p.httpGetters[peer], true}return nil, false
        }
        var _ PeerPicker = (*HTTPPool)(nil) // 检验接口实现是否正确
        
    • ``httpGetter实现了PeerGetter接口,实现了其需要实现的Get()函数,Get()函数主要是吊桶net/http中的Get()方法,向远程节点请求数据,并使用ioutilReadAll`获取

      • func (h *httpGetter) Get(group string, key string) ([]byte, error) {u := fmt.Sprintf("%s%s%s",h.baseURL,url.QueryEscape(group),url.QueryEscape(key),)res, err := http.Get(u)if err != nil {return nil, err}defer res.Body.Close()if res.StatusCode != http.StatusOK {return nil, fmt.Errorf("error response body: %v", err)}bytes, err := ioutil.ReadAll(res.Body)if err != nil {return nil, fmt.Errorf("error response body: %v", err)}return bytes, nil
        }
        var _ PeerGetter = (*httpGetter)(nil) // 检验接口实现是否正确
        
    • HTTPPool管理客户端的所有过程,因此需要加入httpGetter属性,其是一个map[string]*httpGetter类型,通过key映射httpGetter,同时加入day4中实现的一致性哈希过程,由于这些需要实现互斥访问哈希表,因此还需要一个mutex

      • type HTTPPool struct {self     stringbasePath stringmu          sync.Mutexpeers       *consistenthash.Map    // 缓存值httpGetters map[string]*httpGetter // 每个httpGetter对应一个远程节点,在缓存未命中时向远程节点请求数据
        }
        
    • 最后,将HTTPPool集成在主流程中,即group中,group需要实现RegisterPeer()函数,将对应的HTTPPool注入,同时封装getFromPeer()方法,其中调用了之前的Get()方法,用来请求远程节点的数据,重写一下load()方法,在不存在HTTPPool时才调用getLocally(),否则调用getFromPeer

      • type Group struct {name      string // 缓存名称getter    Getter // 回调函数mainCache cache  // 缓存peers PeerPicker // 集成HTTPPool
        }
        // 将HTTPPool注入到group中
        func (g *Group) RegisterPeers(peer PeerPicker) {if g.peers != nil {panic("最多一个peerPicker")}g.peers = peer
        }// 缓存未命中 向远程节点请求
        func (g *Group) load(key string) (Value ByteView, err 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("获取Peer失败")}}// 不存在远程节点 调用回调函数return g.getLocally(key)
        }// 向远处节点请求
        func (g *Group) getFromPeer(peer PeerGetter, key string) (ByteView, error) {bytes, err := peer.Get(g.name, key)if err != nil {return ByteView{}, err}return ByteView{b: bytes}, nil}
        
    • 因此,流程如下

      •                            是
        接收 key --> 检查是否被缓存 -----> 返回缓存值 ⑴|  否                         是|-----> 是否应当从远程节点获取 -----> 与远程节点交互 --> 返回缓存值 ⑵|  否|-----> 调用`回调函数`,获取值并添加到缓存 --> 返回缓存值 ⑶
        
http://www.lryc.cn/news/455858.html

相关文章:

  • 【IPv6】IPv6地址格式及地址分类(组播、单播、任播)整理
  • Linux数据备份
  • 回到原点再出发
  • SimpleFoc以及SVPWM学习补充记录
  • 免费 Oracle 各版本 离线帮助使用和介绍
  • 刷题 二叉树
  • 操作系统 | 学习笔记 | 王道 | 4.1 文件系统基础
  • var let const 之间的区别
  • 【springboot】简易模块化开发项目整合Swagger2
  • 【Linux第五课-进程概念下】环境变量、程序地址空间
  • mysql学习教程,从入门到精通,SQL 临时表(37)
  • 算法闭关修炼百题计划(四)
  • 头歌实践教学平台 大数据编程 实训答案(二)
  • 路由交换实验指南
  • 了解网页 blob 链接
  • OpenGL笔记之事件驱动设计将相机控制类和应用程序类分离
  • 低代码时代的企业信息化:规范与标准化的重要性
  • 理解无监督学习、无监督图像分割
  • C语言— exec系列函数
  • 命名管道Linux
  • 【ios】---swift开发从入门到放弃
  • 【AUTOSAR 基础软件】PduR模块详解(通信路由)
  • [控制理论]—差分变换法与双线性变换法的基本原理和代码实现
  • 【JavaEE】——多线程常用类
  • Cilium-实战系列-(二)Cilium-Multi Networking-多网络
  • springboot自动配置
  • mock数据,不使用springboot的单元测试
  • 【pytorch】pytorch入门5:最大池化层(Pooling layers )
  • 职场上的人情世故,你知多少?这五点一定要了解
  • Python | Leetcode Python题解之第456题132模式