1、通过jenkins的kubctl向Rancher发布镜像时。第一步在Rancher容器内设置健康检查。通过K8S健康检查,以双服务node为例:能达到先启动一个新服务,再停掉第一个旧服务;然后会自动启动第二个新服务,再停掉一个旧服务。

具体健康检查如下:

 2、设置健康检查以后,我们再发版过程中,通过jmeter实时对服务进行测试,发现有失败的服务。其中有一些服务报timeout。我们想到ribbon的重试机制。但是发现timeout在单服务超时时间内就直接报错了。由此推测重试没生效。

经过修改gateway的配置文件:retryable要设置为true, MaxAutoRetriesNextServer为重试次数。

zuul:
  retryable: true
  ribbon-isolation-strategy: thread
  thread-pool:
    use-separate-thread-pools: true
ribbon:
  okhttp:
    enabled: true
  MaxTotalConnections: 500
  MaxConnectionsPerHost: 2000
  #Http请求中的socketTimeout
  ReadTimeout: 3000
  #Http请求中的connectTimeout
  ConnectTimeout: 3000
  # 切换实例的重试次数
  MaxAutoRetriesNextServer: 1
  # 对当前实例的重试次数
  MaxAutoRetries: 0

同时,gateway代码中要引入包:

<dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>

3、经过设置ribbon重试。发现没有再出现timeout的错误。但是依然在版本切换中有一些服务在70~80ms就报错。报错体现微服务的代码层面。我们怀疑是注册中心没有实时刷新的原因。于是我们在k8s的钩子prestop中主动调微服务api,向registry发起服务下线的请求。

 4、服务在强停止之前,会先向注册中心发起下线请求。然后让服务在停服之前先sleep 10秒。通过测试发现,服务下线前,注册中心确实down了对应的微服务,但是jmeter测试仍然有报错。我们猜想registry可能有缓存。

5、于是我们禁用了registry的缓存。

6、同时,我们调整了gateway拉取registry路由列表的时长为5s,默认是30s。

 

 7、此刻再用jmeter调用。发现不再出现服务失败的情况。且能实现优雅停服发版。

8、为什么仍然会有偶发的调用失败?

首先,k8s停node时,由于微服务上报心跳时间是5s,虽然registry设置了过期时间是5s,但是cache的存在,导致注册中心并没有实时刷新。依然有新的请求调动过来。

9、为什么要主动上报registry?

 如果不在k8s中实时的curl api通知registry下线服务。在k8s sleep的10秒钟内,微服务心跳每5秒自动上报的状态仍然是up。

10、那为什么k8s通知了registry下线服务后仍然要sleep 10秒呢?

(1)我们要给gateway拉取registry的间隔5秒留时间。(注意:gateway默认不是5秒)

(3)如果刚好4.99秒时,有请求过来,gateway没刷新,依然调用到了旧微服务上,此时需要给该请求在旧服务上留有执行时间。我们的单请求的执行时间都在毫秒级,只要大于5秒,时间依情况而定。

Logo

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

更多推荐