在大规模 Kubernetes 集群上实现高 SLO 的方法
蚂蚁金服高级开发工程师 范康
导读:随着 Kubernetes 集群规模和复杂性的增加,集群越来越难以保证高效率、低延迟的交付 pod。本文将分享蚂蚁金服在设计 SLO 架构和实现高 SLO 的方法和经验。
Why SLO?
SLI 定义一个指标,来描述一个服务有多好算达到好的标准。比如 Pod 在 1min 内交付。我们通常从迟延、可用性、吞吐率及成功率这些角度来制定 SLI。
SLO 定义了一个小目标,来衡量一个 SLI 指标在一段时间内达到好的标准的比例。比如说,99% 的 Pod 在 1min 内交付。当一项服务公布了其 SLO 的以后,用户方就会对该服务的质量有了期望。
SLA 是 SLO 衍生出来的协议,常用于 SLO 定义的目标比例没有完成时,服务方要赔多少钱。通常来说,SLA 的协议会具体白纸黑字形成有法律效率的合同,常用于服务供应商和外部客户之间(例如阿里云和阿里云的使用者)。一般来说对于内部服务之间的 SLO 被打破,通常不会是经济上的赔偿,可能更多的是职责上的认定。
What we concern about Larger K8s Cluster?
第一个问题就是集群是否健康,所有组件是否正常工作,集群中 Pod 创建的失败数量有多少,这是一个整体指标的问题。
第二个问题就是集群中发生了什么,集群中是否有异常发生了,用户在集群中做了些什么事情,这是一个追踪能力的问题。
第三个问题就是有了异常后,是哪个组件出了问题导致成功率降低,这是一个原因定位的问题。
首先,我们要定义一套 SLO,来描述集群的可用性。
接着,我们必须有能力对集群中 Pod 的生命周期进行追踪;对于失败的 Pod,还需要分析出失败原因,以快速定位异常组件。
最后,我们要通过优化手段,消除集群的异常。
SLls on Large K8s Cluster
我们先来看下集群的一些指标。
第一项指标:集群健康度。目前有 Healthy/Warning/Fatal 三个值来描述,Warning 和 Fatal 对应着告警体系,比如 P2 告警发生,那集群就是 Warning;如果 P0 告警发生,那集群就是 Fatal,必须进行处理。
第二项指标:成功率。这里的成功率是指 Pod 的创建成功率。Pod 成功率是一个非常重要的指标,蚂蚁一周 Pod 创建量是百万级的,成功率的波动会造成大量 Pod 的失败;而且 Pod 成功率的下跌,是集群异常的最直观反应。
第三项指标:残留 Terminating Pod 的数量。为什么不用删除成功率呢?因为在百万级别的时候,即使 Pod 删除成功率达到 99.9%,那么 Terminating Pod 的数量也是千级别的。残留如此多的 Pod,会占着应用的容量,在生产环境中是不可接受的。
第四项指标:服务在线率。服务在线率是通过探针来衡量的,探针失败,意味着集群不可用。服务在线率是会对 Master 组件来设计的。
最后一项指标:故障机数量,这是一个节点维度的指标。故障机通常是指那些无法正确交付 Pod 的物理机,可能是磁盘满了,可能是 load 太高了。集群故障机并须做到“快速发现,快速隔离,及时修复”,毕竟故障机会对集群容量造成影响。
The success standard and reason classification
The infrastructure
Weekly Report 子系统给出当前集群本周 pod 创建/删除/升级的数据统计,以及失败案例原因汇总。
Terminating Pods Number 给出一段时间内集群内新增的无法通过 K8s 机制删除的 pods 列表和 pods 残留原因。
Unhealthy Nodes 则给出一个周期内集群所有节点的总可用时间占比,每个节点的可用时间,运维记录,以及不能自动恢复,需要人工介入恢复的节点列表。
日志和事件采集模块采集各 master 组件以及节点组件的运行日志和 pod/node 事件,分别以 pod/node 为索引存储日志和事件。
数据分析模块分析还原出 pod 生命周期中各阶段用时,以及判断 pod 失败原因及节点不可用原因。
最后,由 Report 模块向终端用户暴露接口和 UI,向终端用户展示 pod 生命周期以及出错原因。
The trace system
接下来,以一个 pod 创建失败案例为例,向大家展示下 tracing 系统的工作流程。
Node Metrics
Unhealthy node
接下来描述故障机的处理流程。
某类 Volume 挂载失败
NPD(Node Problem Detector),这是社区的一个框架
Trace 系统,比如某个节点上 Pod 创建持续报镜像下载失败
SLO,比如单机上残留大量 Pod
我们开发了多个 Controller 对这些某类故障进行巡检,形成故障机列表。一个故障机可以有好几项故障。对于故障机,会按照故障进行不同的操作。主要的操作有:打 Taint,防止 Pod 调度上去;降低 Node 的优先级;直接自动处理进行恢复。对于一些特殊原因,比如磁盘满,那就需要人工介入排查。
Tips on increasing SLO
接下来,我们来分享下达到高 SLO 的一些方法。
第一点,在提升成功率的进程中,我们面临的最大问题就是镜像下载的问题。要知道,Pod 必须在规定时间内交付,而镜像下载通常需要非常多的时间。为此,我们通过计算镜像下载时间,还专门设置了一个 ImagePullCostTime 的错误,即镜像下载时间太长,导致 Pod 无法按时交付。
第二点,对于提升单个 Pod 成功率,随着成功率的提升,难度也越来越难。可以引入一些 workload 进行重试。在蚂蚁,paas 平台会不断重试,直到 Pod 成功交付或者超时。当然,在重试时,之前的失败的节点需要排除。
第三点,关键的 Daemonset 一定要进行检查,如果关键 Daemonset 缺失,而把 Pod 调度上去,就非常容易出问题,从而影响创建/删除链路。这需要接入故障机体系。
第四点,很多 Plugin,如 CSI Plugin,是需要向 Kubelet 注册的。可能存在节点上一切正常,但向 Kubelet 注册的时候失败,这个节点同样无法提供 Pod 交付的服务,需要接入故障机体系。
最后一点,由于集群中的用户数量是非常多的,所以隔离非常重要。在权限隔离的基础上,还需要做到 QPS 隔离,及容量的隔离,防止一个用户的 Pod 把集群能力耗尽,从而保障其他用户的利益。