嘉宾 | 蒋玉芳 整理 | 张雨生
出品 | CSDN云原生
2022年4月26日,在CSDN云原生系列在线峰会第2期“可观测性与APM峰会”上,谐云产品总监、可观测性产品负责人蒋玉芳介绍了国内外云原生可观测性技术趋势,并结合新的可观测利器——eBPF,分享了基于eBPF技术的可观测方案实践。
要点简述
CNCF2021年度调查报告显示:Kubernetes已跨越鸿沟,进入主流市场。随着容器基础设施的表面和底层不断成熟,2022年将成为边缘、可观测性和安全等新兴云原生领域的标志性一年。而eBPF得益于其相对较高的安全性和性能,正在成为新的可观测性利器。
eBPF是一种高级虚拟机,可以在内核中运行沙盒程序,而无需改变内核源码或加载内核模块,并具有相对较高的安全性以及性能。
基于eBPF实现Kubernetes可观测,出发点是希望尽可能解决两类问题:一是尽可能让运维人员快速知道故障域,二是尽可能提供更多的指标给开发/运维完成快速故障定位。
CNCF执行董事Priyanka Sharma表示:“Kubernetes在不断扩大的云原生社区中的使用率正在接近100%,这意味着那些投资于云原生的人对Kubernetes有强烈的兴趣,并对未来感到兴奋。我们的数据还显示了云原生是多么普遍,无论是内部部署还是托管服务。我相信,随着容器基础设施的表面和底层不断成熟,2022年将成为边缘、可观测性和安全等新兴云原生领域的标志性一年。”
云原生可观测性需求的趋势已成,而目前又有哪些技术方案呢?首先,云原生可观测性方案分成两个阶段。
阶段一是采用Prometheus+日志的可观测方案。目前大部分客户所处于的阶段,在这个阶段,云原生技术对于用户的覆盖度不广,其所需要解决的问题多为 K8s平台的资源使用和组件本身出现的问,基于此用户选择Prometheus满足这类诉求。当引入云原生技术后,可观测性范围也发生了变化,与传统环境不同的是,在操作系统层之上设有云原生基础设施层,基于云原生基础设施层之上才是应用层,若采用微服务架构,其上还会存在业务单元层(微服务之间的调用形成业务单元),同时贯穿研发和运维流程还有Kubernetes调度平台层。目前Prometheus依赖cadvisor对docker本身实现资源类监控,与此同时,它有相应的组件exporter和kube-state-metric exporter来共同暴露出K8s调度平台的指标。所以使用Prometheus实现的是在云原生基础设施层docker资源以及K8s调度平台本身的可观测。而从下图可以看出,在链路追踪或者业务追踪层面,它是属于盲区的。同时在云原生基础设施层面也有盲区,对于容器网络的真实情况、mesh底层的一些情况以及存储是否影响到业务等方面,Prometheus目前的能力还是缺失的,其监控域覆盖范围不足。
阶段二则是采用Prometheus+日志+APM的方式以扩大可观测域。APM解决的主要是顶层或应用层这两个范围内的问题,例如完成微服务代码级监控以及业务单元链路的监控等。而目前这类方案有很多,比如SkyWalking 、PINPOINT、JAEGER和ZIPKIN等都可以解决以上的问题。但有了APM之后,我们还存在一定的盲区,即对于云原生基础设施层的网络、存储,甚至关于docker本身的计算竞争层面,我们还是处于一个黑盒的状态。
同时在这个阶段,侵入式APM也带来了一些痛点。
由于其与微服务代码耦合在一起,我们不确定其本身是否会影响业务的稳定性
当研发人员发现应用出现某个问题,并且通过日志排查不出问题时,会怀疑是否是APM探针影响了应用,这时候会将问题反馈给运维人员,导致团队职责界定难
由于需要重启后才可以拥有APM的能力,其整体的推广周期和制作成本较高
同时,阶段二明显是一种各观测层独立建设系统的方式,这种方式也带来了一些问题。在整个建设过程中,我们都需要有一个专家或大脑指导我们应该如何去看数据,应该先看什么系统,再看什么系统。整体的排障流程都需要有一个大脑牵引,引导更好地使用相关的工具。在这种情况下,我们比较依赖专家经验,以关联独立系统的数据,同时需要在独立的系统中不断来回切换寻找线索,因此,专家成本以及时间成本相对较高。
为了解决以上的问题,我们依据opentelemetry标准建设了统一的可观测平台。opentelemetry不仅提供了采集能力,还提供了一套标准来关联数据,比如定义Tracing数据、定义Metrics数据和定义Logging数据,与此同时,还定义了这些数据之间的关系,比如基于Tracing可以扩展request-scope的指标,可以扩展request-scope的日志。而这些关系的定义可以帮助我们更好地整合独立的工具。
此外,目前的可观测性还存在很多遗留问题,而遗留的问题归根结底是现有的可观测对于网络和操作系统可观测能力的缺失。
容器网络性能类的问题,比如无法确定交易超时是否是无法建立连接导致的,以及交易延时抖动是否是因为网络丢包和重传等
Kubernetes域名解析类问题,比如不明确延时抖动是否和DNS解析有关
网络流量类问题,比如无法确定pod性能不达标是受哪个异常网络流量的pod 影响
内核类问题,比如不明确接口慢是否是vfs层读写性能相关,比如如果出现问题无法判断swap、内核内存使用带来的影响
eBPF是一种高级虚拟机,可以在内核中运行沙盒程序,而无需改变内核源码或加载内核模块,并具有相对较高的安全性以及性能。而其在可观测性方面的能力如下图所示,可以覆盖到内核的各个子系统层面。
在系统调用子系统层面,它可以监听操作系统的一些调用
在进程子系统层面,它可以跟踪CPU任务的队列情况、调度情况和同步情况
在内存子系统层面,它可以监测物理内存的情况、内核内存的情况和页表错误的信息等
在网络子系统层面,它可以追踪整个网络的协议栈
在设备子系统层面,它可以对字符设备和块设备进行覆盖
在文件层面,它有能力获取一定的数据,以实现可观测性的一些功能
利用这些能力,我们可以做调度层面的可观测、内存层面的可观测、网络层面的可观测、file IO的可观测、块设备的可观测和kernel profiling。
那eBPF实现可观测有哪些优势呢?
代码无侵入:eBPF程序运行在内核层,无需开发修改一行代码即可实现可观测能力。
安全性能高:eBPF程序相较于cBPF程序有更高的安全性,eBPF虚拟机会进行安全检查,确保应用不会进入死循环、不会访问非法内存,而尽可能确保程序不会对内核产生崩溃性影响。
性能高:eBPF新的设计针对现代硬件进行了优化,所以eBPF生成的指令集比旧的BPF解释器生成的机器码执行更快。
方便运维升级:程序启动不会中断内核以及程序的执行,可以访问运行管理以及代码级的instrument可以实现灵活可插拔的可观测能力。
接下来将分析eBPF程序的工作过程。
其一,eBPF程序主要由用户态程序和内核态程序组成。用户态程序主要负责触发内核态程序的注册以及获取内核态程序采集的原始性能数据并分析成指标、trace 数据暴露给后台;内核态程序则主要负责在内核态采集debug信息以及程序的性能数据。
其二,内核态采集程序被注入eBPF虚拟机后会由 Verifier 组件进行严格的安全检查,尽可能保证代码不crash,保证程序能在不影响内核的情况下正常退出,大大提高程序的安全性。
其三,内核提供了用于用户态程序读取采集数据的数据结构,用户态程序可以通过DMA的map对象获取eBPF的数据进行,减少上下文切换,以提高性能。
目前eBPF可观测性方面已经有一些落地的工具。
bcc项目:既提供了一套eBPF的SDK,也提供了上百个小工具方便我们追踪。
bpftrace项目:它是一种用于实现eBPF程序的高级追踪语言框架,它可以方便我们使用类脚本语言实现eBPF程序。bpftrace提供了丰富的默认脚本让我们可以直接获取内核数据。
sysdig项目:一款强大 Linux 追踪工具,同时支持BPF和eBPF,对于内核版本依赖少。
pixie项目:云原生的在线debug诊断工具,默认提供了很多eBPF的script采集脚本,也提供了自己实现px的高级语言也集成了bpftrace向终端用户去扩展更多的采集能力。
除了工具,国内外大厂都有一些落地的实际案例。例如Facebook常态化的 BPF程序40多个,而一些性能影响较大的工具类BPF有100多个;字节跳动基于eBPF实现了一套系统监控;阿里云基于eBPF 技术实现了Kubernetes监控等。
在2021年K8s进入主流以前,CNCF等组织主要任务是共同推进云原生的一些技术,而当进入后 K8s 时代,Linux Foundation也更多的需要关注了K8s以及云原生技术带来的一些问题,所以我们会发现去年有一个新的基金会eBPF Foundation成立,来更多地推动和推进eBPF相关的技术。
基于eBPF实现可观测出发点是希望尽可能解决两类问题。
其一是对于运维人员,我们希望尽可能让其快速知道故障域,比如是微服务的哪一个组件有问题?是中间件调用有问题?还是容器网络需要进一步排查?异或是资源需要进一步排查?
第二是尽可能提供更多的指标给开发/运维完成快速故障定位,比如我们会提供一些网络指标、DNS的指标和资源错配/资源限制的指标来回答。
所以从数据覆盖面来讲,我们解决的是两部分的问题。
第一部分是我们依赖eBPF技术补充前面提到的云原生可观测性盲区,即关于云原生基础设施层,以及应用层面的调用问题。
第二部分是利用eBPF增强底层K8s资源使用的能力,主要是增强指标力度,让其能够更加细腻地分析问题;而在应用层面,我们依赖我们动态APM探针的能力以实现分析应用具体问题能力。总体来说,我们在该平台提供一个从上至下的分析能力,如下图所示。
接下来将分析基于eBPF的云原生可观测方案,为了实现前面提到的可观测性平台,我们的方案是基于eBPF的程序,我们用到的主要使用的tracepoint和 kprobe/kretprobe的能力,把内核层面的数据读取出来,放到ringbuffer里面,然后在用户态会有一个C/C++程序来读数据,进而进行预处理。预处理后再将数据发布给上层的Go端的客户态的程序,而Go端的客户态的程序主要进行一些k8smetadata的填充。最后通过otelexporter把数据暴露给可观测平台进行分析。
下面分享三个基于eBPF的实践。
第一个是实现使用eBPF tracepoint实现pod调用拓扑以及如何获取pod http接口的黄金指标。在请求的调用的过程中,系统调用层面会connect一个具体的地址,所以我们可以从系统调用获取到进程和地址的调用关系。在我们的数据预处理端以进程以及IP:port为key关联上container以及K8s相关的metadata作为label。我们目前采用一种分布式达标的方式,在每一个worker节点上都会有一个探针,这个探针会去获取当前集群的metadata数据并把它们保存在内存中,用来实现原始eBPF数据的丰富。这种方式的内存占比也是可以接受,虽然要获取到整个集群K8s相关的数据,但根据测试发现,我们整体label信息的保存也就30~40兆。另外有一个问题如果客户端未装探针,外部请求来到集群内,那么如何得到调用源?这个可以从服务端来分析这个调用,在服务端会通过accept系统调用实现一个连接,通过这个连接,可以获取到具体的调用源IP。下图是Kubernetes集群中拓扑实现的效果。
同样,在系统调用中我们也可以获取到请求的内容和响应。下图是客户端发送一个请求以及得到响应的系统调用。
我们目前的实现是基于tracepoint得到类似sendto、recvfrom等系统调用的具体内容,然后基于http的具体协议格式逐帧解析具体内容以此得到具体的请求 url、错误率以及具体内容,同时根据系统调用的间隔时间统计接口延迟。下图是一个workload的具体请求信息。
第二个是实践是基于eBPF kprobe实现了tcp相关4层网络指标获取,该实践适用于了解pod之间通信的网络性能质量:比如srtt指标是否有重传,也适用于了解pod请求不可达是否是tcp层丢包导致的。而后续可以利用kprobe实现二层、三层网络是否丢包等请求,比如contrack是否满、ip层是否过滤掉等具体请求,即更详细地去做网络层的追踪。下图是我们目前阶段实现效果。
目前eBPF技术可观测的推进都将基于开源,我们希望把我们之前的经验以及成果共享给社区,同时也希望联合社区一起推动可观测的发展。
目前我们开源之一就是kindling,通过这个开源项目大家可以通过Prometheus从我们探针获取到更多的数据,同时官方也提供grafana的Plugin把最佳实践的展示给大家,后续会把更多标准版的能力开放出来。
开源之二我们开源了一个太空舱的项目,我们希望联合大家共建一个云原生的运维界的cve库,通过该可观测的故障库,让大家知道云原生的故障会产生在哪些层面,以及目前自身的能力是否可以解决这些层面的问题。与此同时,让大家可以直观地看到自己目前的可观测能力处在哪个层面,这样有助于大家一起在可观测领域提升。
聚焦云原生新技术、新实践,帮助开发者群体赢在开发范式转移的新时代。欢迎关注CSDN云原生微信公众号~