浅谈高校网站群的建设,群晖wordpress外网,安徽手机版建站系统,网页怎么建设HTTPPool 既可以是服务端#xff0c;也可以是客户端#xff0c;这取决于特定的使用场景和上下文#xff1a; 作为客户端#xff1a;当本地缓存没有找到需要的数据时#xff0c;HTTPPool 需要作为客户端#xff0c;通过 httpGetter #xff08;实现了 PeerGetter 接口也可以是客户端这取决于特定的使用场景和上下文 作为客户端当本地缓存没有找到需要的数据时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根据group和key向远程节点获取数据 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()方法向远程节点请求数据并使用ioutil的ReadAll获取 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 -- 检查是否被缓存 ----- 返回缓存值 ⑴| 否 是|----- 是否应当从远程节点获取 ----- 与远程节点交互 -- 返回缓存值 ⑵| 否|----- 调用回调函数获取值并添加到缓存 -- 返回缓存值 ⑶