前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >健康检查 - 从Readiness和Liveness 探针说起

健康检查 - 从Readiness和Liveness 探针说起

作者头像
东风微鸣
发布2022-04-21 14:06:00
3.6K0
发布2022-04-21 14:06:00
举报
文章被收录于专栏:东风微鸣技术博客

前言

本文主要是详细介绍K8S中的健康检查的2类方式, 即: 存活(liveness)探针和就绪(readiness)探针, 前者关乎pod是否要重启, 后者关乎service 端点列表是否要拿掉该pod. 介绍完之后并附上最佳实践案例, 涵盖: web server, tomcat等中间件, redis等缓存服务器, mysql等开源数据库, spring微服务...

同时从K8S的健康检查展开, 延伸到传统运维场景下的健康检查, 其实这2类探针也存在, 但我们用的够好够细了么?

使用范围

存活(Liveness) 和 就绪(Readiness) 探针(Probe)是 Kubernetes的功能, 使团队能够使其容器化的应用程序更可靠、更健壮。但是,如果使用不当,可能不但不会得到期望中的好处, 还会使基于微服务的应用程序不稳定.

每个探针的用途都非常简单. 概述如下:

  • 存活(Liveness) 探针 - 探测应用是否处于健康状态,如果不健康则删除并重新创建容器. 即在什么情况下重启pod是合适的?
  • 就绪(Readiness) 探针 - 探测应用是否启动完成并且处于正常服务状态,如果不正常则不会接收来自 Kubernetes Service 的流量. 即在什么情况下, 我们应该从服务端点列表删除pod, 使其不再响应请求?

结合探针的作用, 可以在pod内执行以下几种测试:

  1. HTTP GET 请求 - 对特定 HTTP endpoint 的请求返回200-399 之间的响应则认为 成功.
  2. 执行命令 - 在容器内执行自定义的命令, 返回码为 0 则成功.
  3. TCP 套接字检查 - 在容器上成功打开特定的TCP 套接字则认定成功.

存活(Liveness)

因此,要使用存活(Liveness)探针,我们必须从三个可用的选项中确定一个合适的测试,如果测试失败,则需要执行pod重启.

首先, 务必保证有存活(liveness)探针的pod就是需要重启的pod. 就是说: 这个探针就是用来探测这个pod的存活状态的, 而不是探测其他pod, 甚至多个pod, 或者其他事务的状态的.

其次, 存活(liveness)探针也不能太过简单, 否则的话可能永远不会给出容器健康状况不佳的有意义的指示.

最后, 存活(liveness)探针并不是管理和监控基于微服务的复杂应用程序的唯一工具, 但是它是最基本的保障. 如果有更复杂的需求, 可以通过日志监控和metrics监控来实现, 比如: EFK 和 Prometheus.

还是以之前的旅行预订网站 web 应用程序来作为示例. 这个web应用有多个微服务, 包括:

应用程序服务响应 URL endpoint(如 /flights、/trains和 /hotels)上的请求。这些 URL 中的每一个都会导致一个事务,该事务需要与查找座位或房间可用性的另一个容器化应用程序进行交互。他们还可以执行诸如获取用户配置文件和查找其经常旅行点等任务。简而言之,这不是一个微不足道的事务,它涉及多个下游接口。如果我们使用上述 URL endpoints之一作为存活(liveness)探针的一部分,则结果可能是在一个下游服务发生故障或响应缓慢后重新启动这个容器。其实这个微服务可能运行的好好的,但我们错误的配置导致它重新启动。

或者,我们寻找不同的endpoint 来指示 pod 运行状况。添加新 URL(如 /health,用于验证该微服务是否正在运行和服务请求),只有在微服务无法响应简单请求时才会重新启动 pod。

🔖 书签:

  1. 如果微服务的url endpoint(如: /seats)可以清晰表明该微服务的状态, 就用它!
  2. 更通用的做法, 是配置一个专用的健康检查的URL. 这个URL无法响应时, 该微服务肯定有问题. (如: /health/status 等)

但是, 事情没有这么简单. 在找到了合适的endpoint后, 还必须确定存活(liveness)探针测试的合适参数, 以确保它在正确的环境中运行. 配置URL 响应测试所需的参数涉及以下内容:

  • initialDelaySeconds - 容器启动前启动的秒数
  • periodSeconds - 前后2次执行探针之间的延迟
  • timeoutSeconds - 探测超时和容器化应用程序假定失败后不活动秒数。
  • failureThreshold - 在存活探针重新启动容器之前允许探针失败的次数(或就绪探针将pod标记为不可用)。
  • successThreshold - 探针在开始失败后必须报告成功的次数,以便重置探测过程。

initialDelaySeconds参数必须设置为应开始运行状况检查探针的适当值。由于 /health 探针与其他资源消耗较多的 URL 在同一应用程序服务器平台上运行,初始延迟必须足够长,以确保运行状况检查 URL 处于活动状态。将此值设置得过高将留下一段时间,在此期间容器应用程序处于活动状态,并且探针未处于活动状态。

应谨慎对待periodSeconds参数,因为这个配置的是 Kubernetes 平台探测pod以查看其是否成功运行的频率。设置过于激进会导致不必要的工作负载,而探针之间的间隙过大会导致探针操作之间的长时间延迟。

探针时序图

下面的示例通过时间线演示了执行的探针。第一个探针成功,但第二个、第三个和第四个探针失败。假设failureThreshold的默认设置为 3 ,则pod将在第四个探针失败后重新启动.

🔖 书签: 配置如下:

  • initialDelaySeconds - InitialDelay
  • periodSeconds - period
  • timeoutSeconds - timeout
  • failureThreshold - 3

假设一个pod启动失败,由于存活(liveness)探针的作用,在pod重新启动之前所能经过的最短时间是

代码语言:javascript
复制
time = initialDelaySeconds + (failureThreshold – 1) * periodSeconds + timeoutSeconds

在正常稳定状态操作下,假设pod在一段时间内运行成功,则initialDelaySeconds参数将变得无关紧要。在这种情况下,故障和pod重新启动之间的最短时间间隔是:

代码语言:javascript
复制
time = (failureThreshold – 1) * periodSeconds + timeoutSeconds

如下图所示,故障点可以发生在探测之前,也可以发生在探测成功之后。如果周期时间很长,对pod的干扰很小,那么pod重新启动之前的时间可能会导致在重新启动之前添加几乎一个额外的periodSeconds时间间隔。

必须谨慎使用failureThreshold参数。如果参数设置得过高,则存在在pod发生故障且未重新启动时浪费时间的危险。如果此参数设置得太低,则如果pod承受较大的负载,则存在过早重新启动pod的危险。如果出现这种情况并重新启动pod,则系统会丢失部分服务于客户请求的工作负荷(比如本来4个pod, 重启了1个, 就只有3个在服务了),并将更多的工作负载放在剩余的 Pod 上,这将使其整体性能进一步下降。

就绪(Readiness)探针

上面所述的关于存活探针的所有内容都同样适用于就绪探针。明显的区别是探针执行操作时的最终结果,在就绪探针的情况下,操作是从可用服务端点列表中删除 pod。在正常情况下,端点会报告支持它的所有 Pod,如下所示:

代码语言:javascript
复制
oc get ep/node-app-slave -o json
{
"apiVersion": "v1",
"kind": "Endpoints",
...
"subsets": [
{
"addresses": [
{
"ip": "10.128.2.147",

运行就绪探针失败后, 地址行更改为:

代码语言:javascript
复制
oc get ep/node-app-slave -o json
{
"apiVersion": "v1",
"kind": "Endpoints",
...
"subsets": [
{
"notReadyAddresses": [
{
"ip": "10.128.2.147",

存活探针和就绪探针之间的一个明显区别是,在就绪探针采取行动后,pod仍在运行。这意味着successThreshold参数可以发挥更大的作用。即使将pod从端点列表中取下,就绪探针将继续探测pod。如果pod以某种方式设法自我纠正(可能是由于它暂时承受着严重的工作负载,并且无法对探针做出响应),则pod可能会开始成功响应探针。成功阈值的默认值仅为 1,因此只需一个成功的探测响应,就取消隔离期并将 pod 重新添加到服务端点列表中。因此,就绪探针在给pod一些喘息空间以从不堪重负中恢复过来方面表现特别好。

再次,必须提出这样的问题——"考虑到应用程序的总体架构和预期的工作负载(应用程序必须在此工作负载下运行),当pod不堪重负时,我们希望采取什么操作?" 类似地,不必要的pod重启会给系统内的其他pod带来额外的工作负载,临时将一个pod“停用”可能只是表明应用程序的功能或整个体系结构需要重新考虑其在负载下的行为。

使 Pod 退出服务(Service)

对于就绪探针,failureThreshold参数定义探针在从端点列表中删除pod之前必须失败的次数。考虑就绪探针的failureThreshold为 5 和默认successThreshold为 1 的情况。在下图中,pod连续三次未能响应探测,随后出现一次成功响应(探针 5)。此成功响应在故障时重置计数器,然后探针10 从端点表中移除pod之前,又发生了五个故障探测(探针 6 到 10)。

将 Pod 重新加到服务(Service)

对于就绪探针,successThreshold参数与failureThreshold一起工作,以定义将 pod 重新加到端点列表的情况。显然,successThreshold参数对存活(liveness)探针没有影响。考虑就绪探针的failureThreshold为 5 和successThreshold为 3 的情况。在下图中,pod 在探针 5 处出现第五次响应失败,导致pod从端点列表中移除。请注意,在从探针 1 到探针 5 的时间段内,即使该pod难以成功响应, 它仍保留在端点列表中。在pod 运行状况改善并在探针 7 处成功响应之前,探针 6 上又发生一次探针故障。由于成功阈值设置为 3,因此在将pod加回到端点列表之前,在探针 8 和 9 处需要另外两次成功的探测响应。

一个pod可以恢复健康但仍不能处理请求的最小时间是:

代码语言:javascript
复制
time = (successThreshold – 1) * periodSeconds

示例

前面说了那么多废话, 现在上一点干货.

NGINX

代码语言:javascript
复制
                  livenessProbe:
                    httpGet:
                      path: /
                      port: 8080
                    initialDelaySeconds: 30
                    timeoutSeconds: 3
                  readinessProbe:
                    httpGet:
                      path: /
                      port: 8080
                    initialDelaySeconds: 3
                    timeoutSeconds: 3

NGINX的存活(liveness)探针配置和就绪(readiness)探针配置类似, 只有初始延迟时间不一样, 都是检测 8080端口的/ 页面状态.

  • 存活探针: 初始化延迟30s
  • 就绪探针: 初始化延迟 3s

Tomcat

针对tomcat标准容器, 就只配置了就绪探针: 就是查看tomcat的Catalina type Server stateName的状态是否为STARTED

代码语言:javascript
复制
                  readinessProbe:
                    exec:
                      command:
                        - /bin/bash
                        - '-c'
                        - >-
                          curl --noproxy '*' -s -u
                          ${JWS_ADMIN_USERNAME}:${JWS_ADMIN_PASSWORD}
                          'http://localhost:8080/manager/jmxproxy/?get=Catalina%3Atype%3DServer&att=stateName'
                          |grep -iq 'stateName *= *STARTED'

Spring Boot 微服务

对于实现了actuator的微服务, 2类探针可以这么配置:

代码语言:javascript
复制
                  livenessProbe:
                    httpGet:
                      path: /health
                      port: 8080
                    initialDelaySeconds: 10
                    timeoutSeconds: 3
                  readinessProbe:
                    httpGet:
                      path: /health
                      port: 8080
                    initialDelaySeconds: 180
                    timeoutSeconds: 3

Redis

代码语言:javascript
复制
                  readinessProbe:
                    exec:
                      command:
                        - /bin/sh
                        - '-i'
                        - '-c'
                        - >-
                          test "$(redis-cli -h 127.0.0.1 -a $REDIS_PASSWORD
                          ping)" == "PONG"
                    initialDelaySeconds: 5
                    timeoutSeconds: 1
                  livenessProbe:
                    initialDelaySeconds: 30
                    tcpSocket:
                      port: 6379
                    timeoutSeconds: 1

MySQL

代码语言:javascript
复制
                  readinessProbe:
                    exec:
                      command:
                        - /bin/sh
                        - '-i'
                        - '-c'
                        - >-
                          MYSQL_PWD="$MYSQL_PASSWORD" mysql -h 127.0.0.1 -u
                          $MYSQL_USER -D $MYSQL_DATABASE -e 'SELECT 1'
                    initialDelaySeconds: 5
                    timeoutSeconds: 1
                  name: mariadb
                  livenessProbe:
                    initialDelaySeconds: 30
                    tcpSocket:
                      port: 3306
                    timeoutSeconds: 1

mysql的存活(liveness)探针配置如下: 检测3306 端口是否正常, 不正常就重启pod.

  1. 启动延迟30s
  2. 检测方式: 检查tcp套接字: 3306端口
  3. 超时时间为1s

mysql的就绪(readiness)探针配置如下: 检测是否能执行最简单的sql SELECT 1, 不能执行的话就提出服务端点列表(类似于踢出F5的pool)

  1. 检测方式: 用mysql命令登录并执行SELECT 1 SQL
  2. 启动延迟5s
  3. 超时时间为1s

高级配置

对于一些更为复杂的健康检查需求, 我们可以通过编写自定义检查脚本来实现.

这里在容器里封装了2个专门用于检测状态的脚本:

代码语言:javascript
复制
                  livenessProbe:
                    exec:
                      command:
                        - /bin/bash
                        - '-c'
                        - /opt/eap/bin/livenessProbe.sh
                    initialDelaySeconds: 60
                  readinessProbe:
                    exec:
                      command:
                        - /bin/bash
                        - '-c'
                        - /opt/eap/bin/readinessProbe.sh

比如, 对于MQ类的容器, 自定义脚本可以包含以下判断内容:

  • 端口已监听
  • MQ已启动
  • 运行一个简单的生产 - 消费者最小化应用来判断是否对应的queue, exchange或topic是否可以处理消息

K8S健康检查小结

存活(liveness)和就绪(readiness)探针在可靠、高效地提供应用程序服务方面可以发挥作用。通过准确考虑用于探测的内容以及我们想要对故障和恢复采取什么操作,可以很好地利用探针来帮助管理微服务应用程序的继续交付。

对传统运维的健康检查的思考

从K8S的健康检查展开, 我们延伸到传统运维场景下的健康检查, 其实这2类探针也存在, 但是我们可以用的更细化, 更加自动化.

拿典型的一种架构来举例: F5 + 应用服务器 + Oracle 数据库

F5就相当于K8S中的Service, F5的健康检查就类似于: 就绪(readiness)探针. F5作为商业产品, 健康检查的功能更加丰富. 我们的常用有2种:

  1. 检测指定的端口是否正常;
  2. 要求应用服务器必须添加个页面, 如/ok.html, 只要访问正常就认为正常.

当然, 回顾以上K8S健康检查的内容, 举一反三, 其实F5的健康检查配置可以更加细化, 针对不同的应用类型或系统来定制. 在这一层面, 我们可以做的更多的点是: 细化

针对应用服务器, 我们确实通过类似httpGet的方式来访问特定的应用页面, 以此来判断应用是否正常. 判断的结果也往往是相当准确的, 但是相比K8S, 我们发现传统应用异常, 并没有进行后续的自动化处理, 如自动重启, 而是仍然采用人工分析处理的方式. 那么我们应用服务器方面, 可以从K8S健康检查学到的点是: 自动化重启 应用服务器节点以缩小 MTTR.

以上.

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-01-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 东风微鸣技术博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 使用范围
  • 存活(Liveness)
    • 探针时序图
    • 就绪(Readiness)探针
      • 使 Pod 退出服务(Service)
        • 将 Pod 重新加到服务(Service)
        • 示例
          • NGINX
            • Tomcat
              • Spring Boot 微服务
                • Redis
                  • MySQL
                    • 高级配置
                    • K8S健康检查小结
                    • 对传统运维的健康检查的思考
                    相关产品与服务
                    容器服务
                    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档