背景

      项目使用k8s + go-grpc, A服务作为客户端需要通过grpc连接B服务, B服务是通过k8s的service的nodeport方式暴露的。

     协议用的是dns协议,resolver用的是go-grpc自带的dns-resolver。

现象

      删除B服务的pod发现A服务能正常感知到,如果B服务的pod所在节点重启发现A服务并不能感知到,还是会让请求路由到宕机的pod上面。  

排查

     发现项目用的schema是dns,用的是grpc自带的dns_resolver。

    grpc客户端连接过程:

          grpc.DialContext      建立连接,返回clientconn

         getResolver(clientconn.go)    通过传入的scheme返回对应的解析器

         newCCResolverWrapper(resolver_conn_wrapper.go)  构建对应的解析器

                   调用builder提供的build方法

       

        grpc 自定义的dns_resolver.go的build方法

                启动一个watcher协程

                      watcher里面具体动作如下:

                            通过一个rn的channel接受信号,接收到rn的信号后调用lookup方法重新解析域名,解析完成后更新clientconn里面的连接状态。

                调用ResolveNow方法(真正的解析域名的动作)

         

         这里会发现grpc正常情况下可能一直都不会重新解析域名,看起来这里是一个不太合理的方式,看代码提交,19年11月之前的代码dns是会每隔30分钟重新解析一次,找到当时的提交记录如下https://github.com/grpc/grpc-go/pull/3228,而且发现里面关于dns重新解析的issue,这个issue当前仍然是处于open状态的https://github.com/grpc/grpc/issues/12295  。

 

解决方案

     自定义dns_resolver替换到grpc自带的dnsresolver,build方法里面每隔10s进行一次域名的重解析。

            

       

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐