代码编织梦想

目录

 

背景

分析

原因

总结


背景

  1. 早先的都采用基于grpc+etcd做服务注册和服务发现,都是正常的
  2. 后来有部分服务采用k8s部署,为了新旧兼容,服务会按照老方式把宿主机的ip注册到etcd上,k8s体系类使用体系类的服务发现,k8s体系外的依然使用原来的方式,互不影响
  3. 但是有服务基于k8s部署之后,发现client调用接口超时,而直接通过ip调用却是正常
  4. 且多数是发生在k8s的出现pod弹性伸缩之后

分析

  1. 服务端注册地址,从etcd来看,是正常的
  2. 服务端直接通过ip调用也正常的,所以排除服务端本身的问题
  3. etcd里面显示的地址的确会出现没有的情况,但是通过日志发现服务端lease维持的心跳却是正常的,一度觉得怀疑人生~~
  4. 后来发现是下面的原因A导致的,
  5. 解决后,发现依然有问题,O(∩_∩)O,很奇怪~
  6. 通过打开grpc日志,发现grpc的client端会收到地址列表为空的问题:balancerWrapper: got update addr from Notify:[]
  7. 但是etcd里面显示的注册地址却都是存在的,一度觉得怀疑人生~~
  8. 后来通过阅读grcp源码分析,增加日志排查 :google.golang.org/grpc/balancer.go  文件中 函数 (rr *roundRobin) watchAddrUpdates()  里面,增加 etcd watch的数据变动行为,发现了原因
  9. 通过下面的原因B的处理方式解决

原因

  1. 问题存在两个
  2. 原因A
    1. 早先服务注册:类似于

      key:service/go_server_xx/10.1.1.1:9999
      val:{"Op":0,"Addr":"10.1.1.1:9999","Metadata":null}

    2. 并且通过etcd的lease机制维持心跳

    3. 假设一个宿主机起了两个pod,也就两个服务,ser1和ser2
    4. ser1启动的时候会注册 service/go_server_xx/10.1.1.1:9999 并且绑定 lease1,并且维持lease1心跳
    5. 之后,ser2启动的时候也会注册 service/go_server_xx/10.1.1.1:9999 并且绑定 lease2,并且维持lease2心跳,住以此时这个key和lease1解绑了
    6. 当发生弹性伸缩的时候,比如ser2关闭了,此时 lease2过期,同时与其绑定的key也被删除,所以client会发生找不到地址列表的问题
    7. 但是从服务端ser1来看,依然提供服务,并且与etcd的lease1心跳也正常~~,哈哈
  3. 解决方法A
    1. 通过在key后边增加后缀解决,类似于:service/go_server_xx/lease1/10.1.1.1:9999, 这样即使一个宿主机上有多个服务,各自也会注册各自的
  4. 原因B
    1. 上述问题解决之后,还有个问题
    2. 比如同一个宿主机注册的两个服务地址

      key1:service/go_server_xx/lease1/10.1.1.1:9999
      val1:{"Op":0,"Addr":"10.1.1.1:9999","Metadata":null}
      和
      key2:service/go_server_xx/lease2/10.1.1.1:9999
      val2:{"Op":0,"Addr":"10.1.1.1:9999","Metadata":null}
      

       

    3. 在client端watch etcd变化的时候会发现两个add行为,但是 由于val中的地址是一样的,可用addrs列表里面只会保存一个 10.1.1.1:9999,另一个会跳过:
      grpclog.Infoln("grpc: The name resolver wanted to add an existing address: ", addr)
    4. 当发生弹性伸缩的时候,比如ser2关闭了
      1. watch etcd变化的时候会收到一个del行为,这个时候会删除10.1.1.1:9999
      2. 这样client可用地址列表里面就是空的了
      3. grpc的client对象收到 balancerWrapper: got update addr from Notify:[]
  5. 解决方法B:
    1. 注册的时候增加metadata做区分就可以了,类似

      key1:service/go_server_xx/lease1/10.1.1.1:9999
      val1:{"Op":0,"Addr":"10.1.1.1:9999","Metadata":lease1}
      和
      key2:service/go_server_xx/lease2/10.1.1.1:9999
      val2:{"Op":0,"Addr":"10.1.1.1:9999","Metadata":lease2}
    2. 这样增加的时候,可用地址列表里面就会增加两个元素

总结

etcd+grpc的一整套机制(服务注册&服务发现等)是好的

k8s的那一套机制也是好的

但是两者结合使用,就得注意很多地方,要不然会出现很多蛋疼的问题提

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/liangzhiyang/article/details/103280989

基于CentOS 搭建gRPC框架-爱代码爱编程

1. 简介 RPC(remote procedure call 远程过程调用)框架实际是提供了一套机制,使得应用程序之间可以进行通信,而且也遵从server/client模型。使用的时候客户端调用server端提供的接口就像是调用本地的函数一样。 gRPC(google RPC)是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。

gRPC测试-爱代码爱编程

参考文献: 示例及博客链接优先推荐:带pom的简单示例官网demoIntellij IDEA中使用Protobuf的正确姿势 github: https://github.com/whbing/grpc-java/tree/v1.20.0/examples # 改动点 master分支 将pom中的改为 <grpc.version>

gRPC (NodeJS)-爱代码爱编程

Github地址(Nodejs 版本):https://github.com/changbaihe/GrpcDemo 一、编写pb文件(.proto),例:chat.proto   注:1.protocol buffers 维基百科:https://zh.wikipedia.org/wiki/Protocol_Buffers     2.protoc

golang grpc keepalive-爱代码爱编程

最近遇到 grpc 客户端报错 rpc error: code = Unavailable desc = transport is closing,原因是连接长时间没有使用,被服务端断开,这种情况通过简单粗暴的重试策略可以解决,更加优雅的解决方案是增加保持连接策略 服务端 var kaep = keepalive.EnforcementPolicy{

gRPC初试-爱代码爱编程

本文参照官网文档https://grpc.io/docs/tutorials/basic/java/,主要介绍gRPC的demo搭建。 我从https://github.com/grpc/grpc-java.git拷贝了grpc-java项目到本地,参考了examples文件夹下的代码,由于这个项目是gradle构建,不太熟悉gradle的我新建了一个项

使用 protoc 编译 .proto 文件时使用的 -I 的参数是代表什么-爱代码爱编程

首先,我们可以在终端运行以下命令 protoc --help 我们发现其实参数 -IPATH 就是代表 -I,所有这个参数就是代表: -I(-IPATH)指定要在其中搜索导入(import)的目录。可指定多次,目录将按顺序搜索。如果没有给出,则使用当前工作目录。 如:protoc -I=$GOPATH/src --go_out=. hello

SpringBoot Web项目打包后快速生成Windows下服务注册、卸载、服务运行停止、控制台运行等小程序-爱代码爱编程

SpringBoot Web项目打包后快速生成Windows下服务注册、卸载、服务运行停止、控制台运行等小程序 公司项目大部分都是以Spring Boot 搭建的Web 项目,且大部分部署在Windos Server 上进行运行,有的项目要求以服务方式注册并开机自启。 当然,网上是有注册服务解决方案的,但是为了以后使用方便,我把打包后生成

记Zookeeper3.5.6单机安装配置及简单使用-爱代码爱编程

zookeeper简介 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。 ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高

微服务为什么一定要zookeeper-爱代码爱编程

微服务中 Zookeeper 的应用及原理 一、背景 二、Zookeeper 的特性 1. 树状目录结构 2. 持久节点 (Persistent) 3. 持久有序节点 (Persistent_sequential) 4. 临时节点 (Ephemeral) 5. 临时有序节点 (Ephemeral_sequential) 6. 节点监

Spring Cloud微服务架构——Eureka服务注册-爱代码爱编程

上篇文章的图再放一次,多看,多理解,熟记于心。 创建“服务提供方” 上一篇文章已经创建好了商场(Eureka注册中心),文章地址:Spring Cloud微服务架构——Eureka注册中心,现在我们可以让商家入驻商场了,即服务注册。 快速构建一个Spring Boot工程,方法可以参考上篇文章。 修改pom.xml文件,引入Spring Clo