2022-基于eBPFKubernetes问题排查全景图

Kubernetes成为云原生事实标准,可观测性挑战随之而来

当前,云原生技术以容器技术为基础,通过标准可扩展的调度、网络、存储、容器运行时接口来提供基础设施。同时,通过标准可扩展的声明式资源和控制器来提供运维能力,两层标准化推动了开发与运维关注点分离,各领域进一步提升规模化和专业化,达到成本、效率、稳定性的全面优化。

在这样的大技术背景下,越来越对的公司引入了云原生技术来开发、运维业务应用。正因为云原生技术带来了越发纷繁复杂的可能性,业务应用出现了微服务众多、多语言开发、多通信协议的鲜明特征。同时,云原生技术本身将复杂度下移,给可观测性带来了更多挑战:

K8s 可观测性挑战

混沌的微服务架构,多语言和多网络协议混杂

业务架构因为分工问题,容易出现服务数量多,调用协议和关系非常复杂的现象,导致的常见问题包括:

  • 无法准确清晰了解、掌控全局的系统运行架构;
  • 无法回答应用之间的连通性是否正确;
  • 多语言、多网络调用协议带来埋点成本呈线性增长,且重复埋点ROI低,开发一般将这类需求优先级降低,但可观测数据又不得不采集。

下沉的基础设施能力屏蔽实现细节,问题定界越发困难

基础设施能力继续下沉,开发和运维关注点继续分离,分层后彼此屏蔽了实现细节,数据方面不好关联了,出现问题后不能迅速地定界问题出现在哪一层。开发同学只关注应用是否正常工作,并不关心底层基础设施细节,出现问题后需要运维同学协同排查问题。运维同学在问题排查过程中,需要开发同学提供足够的上下游来推进排查,否则只拿到“某某应用延迟高”这么笼统的表述,这很难有进一步结果。所以,开发同学和运维同学之间需要共同语言来提高沟通效率,KubernetesLabelNamespace等概念非常适合用来构建上下文信息。

繁多监测系统,造成监测界面不一致

复杂系统带来的一个严重副作用就是监测系统繁多。数据链路不关联、不统一,监测界面体验不一致。很多运维同学或许大多都有过这样的体验:定位问题时浏览器打开几十个窗口,在Grafana、控制台、日志等各种工具之间来回切换,不仅非常耗时巨大,且大脑能处理的信息有限,问题定位效率低下。如果有统一的可观测性界面,数据和信息得到有效地组织,减少注意力分散和页面切换,来提高问题定位效率,把宝贵时间投入到业务逻辑的构建上去。


为了解决上述问题,我们需要使用一种支持多语言,多通信协议的技术,并在产品层面尽可能覆盖软件栈端到端的可观测性需求,通过调研,我们提出一种立足于容器界面和底层操作系统,向上关联应用性能监测的可观测性解决思路。

问题解决思路

Kubernetes可观测性全景视角

有了上述产品能力,基于阿里巴巴在容器、Kubernetes方面有着丰富且极具深度的实践,我们将这些宝贵生产实践归纳、转化成产品能力,以帮助用户更有效、更快捷地定位生产环境问题。使用这个排查全景图可以通过以下方法:

  • 大体结构上是以服务和Deployment(应用)为入口,大多数开发只需要关注这一层就行了。重点关注服务和应用是否错慢,服务是否连通,副本数是否符合预期等
  • 再往下一层是提供真正工作负载能力的PodPod重点关注是否有错慢请求,是否健康,资源是否充裕,下游依赖是否健康等
  • 最底下一层是节点,节点为Pod和服务提供运行环境和资源。重点关注节点是否健康,是否处于可调度状态,资源是否充裕等。

全景图

网络问题

网络是Kubernetes中最棘手、最常见的问题,因为以下几个原因给我们定位生产环境网络问题带来麻烦:

  • Kubernetes的网络架构复杂度高,节点、Pod、容器、服务、VPC交相辉映,简直能让你眼花缭乱;
  • 网络问题排查需要一定的专业知识,大多数对网络问题都有种天生的恐惧;
  • 分布式8大谬误告诉我们网络不是稳定的、网络拓扑也不一成不变的、延时不可忽视,造成了端到端之间的网络拓扑不确定性。

Kubernetes环境下场景的网络问题有:

  • conntrack记录满问题;
  • IP冲突;
  • CoreDNS解析慢、解析失败;
  • 节点没开外网(对,你没听错
  • 服务访问不通;
  • 配置问题(LoadBalance配置、路由配置、device配置、网卡配置
  • 网络中断造成整个服务不可用。

网络问题千千万万,但万变不离其宗的是网络有其表征其是否正常运行的”黄金指标“:

  • 网络流量和带宽;
  • 丢包数(率)和重传数(率
  • RTT。

下面的示例展示了因网络问题导致的慢调用问题。从gateway来看发生了慢调用,查看拓扑发现调下游productRT比较高,但是product本身的黄金指标来看product本身服务并没有问题,进一步查看两者之间的网络状况,发现RTT和重传都比较高,说明网络性能恶化了,导致了整体的网络传输变慢,TCP重传机制掩盖了这个事实,在应用层面感知不到,日志也没法看出问题所在。这时候网络的黄金指标有助于定界出问题,从而加速了问题的排查。

网络重传延迟高

节点问题

Kubernetes做了大量工作,尽可能确保提供给工作负载和服务的节点是正常的,节点控制器7x24小时地检查节点的状态,发现影响节点正常运行的问题后,将节点置为NotReady或不可调度,通过kubelet把业务Pod从问题节点中驱逐出去。这是Kubernetes的第一道防线,第二道防线是云厂商针对节点高频异常场景设计的节点自愈组件,如阿里云的node repairer:发现问题节点后,执行排水驱逐、置换机器,从而做到自动化地保障业务正常运行。即便如此,节点在长期使用过程中不可避免地会产生各种奇奇怪怪的问题,定位起来比较费时耗力。常见问题分类和级别:

常见问题与分类

针对这些繁杂的问题,总结出如下排查流程图:

排查流程图

以一个CPU打满为例:

1、节点状态OKCPU使用率超过了90%

节点 CPU 过高

2、查看对应的CPU的三元组:使用率、TopN、时序图,首先每个核的使用率都很高,进而导致整体CPU使用高;接下来我们自然要知道谁在疯狂地使用CPU,从TopN列表来看有个Pod一枝独秀地占用CPU;最后我们得确认下CPU飙高是什么时候开始的。

TopN

服务响应慢

造成服务响应非常多,场景可能的原因有代码设计问题、网络问题、资源竞争问题、依赖服务慢等原因。在复杂的Kubernetes环境下,定位慢调用可以从两个方案去入手:首先,应用自身是否慢;其次,下游或网络是否慢;最后检查下资源的使用情况。如下图所示,Kubernetes监测分别从横向和纵向来分析服务性能:

  • 横向:主要是端到端层面来看,首先看自己服务的黄金指标是否有问题,再逐步看下游的网络指标。注意如果从客户端来看调用下游耗时高,但从下游本身的黄金指标来看是正常的,这时候非常有可能是网络问题或者操作系统层面的问题,此时可以用网络性能指标(流量、丢包、重传、RTT等)来确定。

  • 纵向:确定应用本身对外的延时高了,下一步就是确定具体哪个原因了,确定哪一步/哪个方法慢可以用火焰图来看。如果代码没有问题,那么可能执行代码的环境是有问题的,这时可以查看系统的CPU/Memory等资源是否有问题来做进一步排查。

服务响应慢

下面举个SQL慢查询的例子(如下图。在这个例子中网关调用product服务, product服务依赖了MySQL服务,逐步查看链路上的黄金指标,最终发现product执行了一条特别复杂的SQL,关联了多张表,导致MySQL服务响应慢。MySQL协议基于TCP之上的,我们的eBPF探针识别到MySQL协议后,组装、还原了MySQL协议内容,任何语言执行的SQL语句都能采集到。

MySQL 探针

第二个例子是应用本身慢的例子,这时候自然会问具体哪一步、哪个函数造成了慢, ARMS应用监控支持的火焰图通过对CPU耗时定期采样(如下图,帮助快速定位到代码级别问题。

应用本身问题

应用/Pod状态问题

Pod负责管理容器,容器是真正执行业务逻辑的载体。同时PodKubernetes调度的最小单元,所以Pod同时拥有了业务和基础设施的复杂度,需要结合着日志、链路、系统指标、下游服务指标综合来看。Pod流量问题是生产环境高频问题,比如数据库流量陡增,当环境中有成千上万个Pod时,排查流量主要来自哪个Pod就显得特别困难。

Pod 异常场景和排查

接下来我们看一个典型的案例:下游服务在发布过程中灰度了一个Pod,该Pod因代码原因响应非常慢,导致上游都超时了。之所以能做到Pod级别的可观测,是因为我们用ebpf的技术来采集Pod的流量、黄金指标,因此可以通过拓扑、大盘的方式方便地查看PodPodPod与服务、Pod与外部的流量。

RT 较高导致延迟