peerRt(RoundTripper类型)主要负责实现etcdserver的网络请求等功能,用于向集群其他节点发送version或lease服务请求。我们知道其是在ETCD数据库源码分析——etcdserver bootstrap初始化中的第二步进行初始化的。如何使用它呢?
如server/etcdserver/cluster_util.go的promoteMemberHTTP所示,使用peerRt创建http客户端,然后构造请求Url和指定请求方法为POST,创建http Request结构体,调用http客户端的do函数向服务端进行请求,并获取其响应。
func promoteMemberHTTP(ctx context.Context, url string, id uint64, peerRt http.RoundTripper) ([]*membership.Member, error) {
cc := &http.Client{Transport: peerRt} // 使用peerRt创建http客户端
// TODO: refactor member http handler code cannot import etcdhttp, so manually construct url
requestUrl := url + "/members/promote/" + fmt.Sprintf("%d", id)
req, err := http.NewRequest("POST", requestUrl, nil)
if err != nil { return nil, err }
req = req.WithContext(ctx)
resp, err := cc.Do(req)
if err != nil { return nil, err }
defer resp.Body.Close()
b, err := io.ReadAll(resp.Body)
if err != nil { return nil, err }
// 处理请求超时
if resp.StatusCode == http.StatusRequestTimeout { return nil, errors.ErrTimeout }
if resp.StatusCode == http.StatusPreconditionFailed {
// both ErrMemberNotLearner and ErrLearnerNotReady have same http status code
if strings.Contains(string(b), errors.ErrLearnerNotReady.Error()) { return nil, errors.ErrLearnerNotReady }
if strings.Contains(string(b), membership.ErrMemberNotLearner.Error()) { return nil, membership.ErrMemberNotLearner }
return nil, fmt.Errorf("member promote: unknown error(%s)", string(b))
}
if resp.StatusCode == http.StatusNotFound { return nil, membership.ErrIDNotFound }
// 其他类型的错误
if resp.StatusCode != http.StatusOK { // all other types of errors
return nil, fmt.Errorf("member promote: unknown error(%s)", string(b))
}
var membs []*membership.Member
if err := json.Unmarshal(b, &membs); err != nil { return nil, err } // 反序列化请求响应内容
return membs, nil
}
如下server/etcdserver/adapters.go中的GetMembersVersions也是使用peerRt获取MembersVersions。
func (s *serverVersionAdapter) GetMembersVersions() map[string]*version.Versions {
return getMembersVersions(s.lg, s.cluster, s.MemberId(), s.peerRt, s.Cfg.ReqTimeout())
}