| 
                         经排查,TGW的监控检测模块定期向所有的RS发送心跳包,但是TGW监控检测模块只能收到A服务器的回包,因此TGW认为只有A节点是存活状态,所有的请求数据包最终就由TGW转发到A服务器上了,这就是负载均衡策略失效的根本原因。 
这里还有一个现象是为什么etcd集群中只有一个节点的负载很高呢? 
五个节点的etcd集群中只有一个节点负载很高,其他正常,通过查看A服务器的API  Server的log,可以看到的大量的读请求都固定发送到了同一个etcd节点。 
对于这个现象,可以看下API Server访问后端存储的源码,目前线上Kubernetes基于v1.7.12的源码编译运行,API  Server访问etcd是在内部初始化一个etcd client端,然后通过etcd client端发送请求到etcd server端。etcd  client端有v2和v3两个版本。线上API Server使用的是v2版本客户端。主要代码如下: 
- //初始化etcd工作 
 - func New(cfg Config) (Client, error) { 
 - c := &httpClusterClient{//返回一个http类型的client 
 - clientFactory: newHTTPClientFactory(cfg.transport(), cfg.checkRedirect(), cfg.HeaderTimeoutPerRequest), 
 - rand:          rand.New(rand.NewSource(int64(time.Now().Nanosecond()))),//传入一个当前时间的随机种子 
 - selectionMode: cfg.SelectionMode, 
 - } 
 -  
 - if err := c.SetEndpoints(cfg.Endpoints); err != nil { 
 - return nil, err 
 - } 
 - return c, nil 
 - } 
 - //对etcd列表进行打乱 
 - func (c *httpClusterClient) SetEndpoints(eps []string) error { 
 - ... 
 - neps, err := c.parseEndpoints(eps) 
 - c.Lock() 
 - defer c.Unlock() 
 - c.endpoints = shuffleEndpoints(c.rand, neps)//打乱etcd列表 
 - c.pinned = 0 
 - ... 
 - return nil 
 - } 
 -  
 - func shuffleEndpoints(r *rand.Rand, eps []url.URL) []url.URL { 
 - p := r.Perm(len(eps))//rank库的Perm方法可以返回[0,n)之间的随机乱序数组 
 - neps := make([]url.URL, len(eps)) 
 - for i, k := range p { 
 - neps[i] = eps[k] 
 - } 
 - return neps 
 - }  
 
  
可以看到在初始化etcd客户端时候会传入一个当前时间的随机种子去打乱所有Endpoints(etcd节点)的顺序。 
对于etcd的操作都是通过API Server内部的etcd客户端发送http请求到etcd Server端,最主要是调用如下方法: 
- func (c *httpClusterClient) Do(ctx context.Context, act httpAction) (*http.Response, []byte, error) { 
 - ... 
 - for i := pinned; i < leps+pinned; i++ { 
 - k := i % leps 
 - hc := c.clientFactory(eps[k]) 
 - resp, body, err = hc.Do(ctx, action) 
 - ... 
 - if resp.StatusCode/100 == 5 { 
 -   switch resp.StatusCode { 
 -   case http.StatusInternalServerError, http.StatusServiceUnavailable: 
 -     cerr.Errors = ... 
 -   default: 
 -     cerr.Errors = ... 
 -   } 
 -   ... 
 -   continue 
 - } 
 - if k != pinned { 
 -   c.Lock() 
 -   c.pinned = k 
 -   c.Unlock() 
 - } 
 - return resp, body, nil 
 - } 
 - return nil, nil, cerr 
 - }  
 
  
该方法表明每次请求时候,会从pinned节点开始尝试发送请求,如果发送请求异常,则按照初始化时候打乱顺序的下一个节点(pinned++)开始尝试发送数据。如此看来,如果API  Server使用了某个endpoint发送数据,除非用坏了这个节点,否则会一直使用该节点(pinned)发送数据。这就说明了,没有异常情况下,一个API  Server就对应往一个固定的etcd发送请求。 
对于etcd集群,如果是写请求的话,follower节点会把请求先转发给leader节点处理,然后leader再转发给follower同步。那么5个节点CPU负载不会这么不均衡,但是根据2.1排查API  Server日志看到这里是大量的读请求,相对于写请求,读请求是所有follower节点都能对外提供的。也就是大量请求由于负载均衡策略失效都转发到A服务器,A再把查询请求都打到其中一个固定的etcd,导致该节点忙于处理etcd查询请求,负载就会飙高。                         (编辑:泰州站长网) 
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! 
                     |