赞
踩
当我们将某应用的新版本发布到 K8s 的时候,经常会出现这样一个场景:
Pod 已经运行起来了(READY=1/1,STATUS=Running),但是 Pod 中的应用(例如:springboot)还在处于启动中的阶段。此时,如果有客户端的请求被转发到了该 Pod 上,那最终的结果将会是客户端收到一个类似“连接被拒绝”的返回。
默认情况下(在我们未在 Pod 中未设置 ReadinessProbe 相关信息的时候),Kubelet 会认为 Pod 的 ReadinessProbe 探针永远返回 Success,即 Pod 一直都处于可以对外提供服务的状态,该 Pod 会立刻成为一个服务端点接收客户端的请求。由于此时内部的服务正处于启动中,所以就很有可能会出现本文开头出现的那个问题。
在原因分析当中其实已经提到了解决方案,就是利用 K8s 提供的 ReadinessProbe(就绪探针)。通过该探针是否返回 SUCCESS, Kubelet 可以知道当前 Pod 是否已经准备好接收请求了。只有已经准备好了的 Pod 才会被安排对外接客(接收请求)。
试想下,我们对「服务A」加上了 ReadinessProbe,且「服务A」有三个 Pod 副本(A1,A2,A3)正在对外提供服务。这个时候,我们重新发布一下「服务A」,若新建的副本 A4 还未准备就绪,则之前的A1,A2,A3 还将继续对外提供服务。当 A4 已经准备就绪,此时 Ta 才会替换掉 A1,A2,A3 其中一个副本。这样,就避免了出现 A4 还没准备好,就开始接客的尴尬时刻了。
到现在为止是不是一切看起来都很美好?ReadinessProbe 很完美的解决了开始提到的那个问题。
可是,但是,但可是 … 现实还是狠狠的抽了我一个嘴巴。
先看下我们系统结构的一张简单示意图:
请求的路径如下:
我们分别在 annoroad-xxx-server、springcloud-gateway、微服务A、微服务B …. 上加上了ReadinessProbe(就绪探针),这样 服务准备就绪后再对外提供服务 的目标就能实现了吗?
让我来直接公布试验后的最终结果:
之所以造成这个结果的原因是:
首先,annoroad-xxx-server、springcloud-gateway 的路由走的是 K8s 的 SVC,SVC 中的 Endpoint 描述了有关联的 Pod ,如果 Pod 的 Ready 状态变为 False,则 K8s 会自动将其从 Service 的 Endpoint 列表中删除,后续如果 Pod 的 Ready 状态又恢复了,那会将该 Pod 重新加到 Service 的 Endpoint 列表当中。所以, annoroad-xxx-server、springcloud-gateway 可以达到预期的效果。
我们再来说下从 gateway 到微服务。从 gateway 路由到 微服务A、微服务B …… 走的是 gateway 的 ribbon 路由,拉取的是 eureka 上的节点列表,也就是说只要节点已经注册到 eureka 上了,从 gateway就能路由到这个节点上了,即使这个节点在 K8s 中的还处于未就绪的状态。
为了更好的加以证明,我做了一个简单的实验,将某微服务的 ReadinessProbe 的 initialDelaySeconds 设置的时间长一点儿(模拟一直处于未就绪的状态)。然后,观察处于未就绪状态的该服务,启动完成后是否被注册到 eureka 上了,结果如下图:
从上图,我们可以看到 annoroad-alpha 的一个副本已经注册到 eureka 上了。但是在 K8s 容器内,该副本的 Ready 状态为0/1(未就绪)。此时,通过 gateway 访问该微服务(annoroad-alpha),是能够成功访问(完全绕过了 K8s 的就绪状态)。
如果想再多了解些 ReadinessProbe(就绪探针)的相关概念,可以移步到我写的另外一篇文章《Pod健康检查和服务可用性检查》
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。