关于容器:使用-eBPF-零代码修改绘制全景应用拓扑

69次阅读

共计 9763 个字符,预计需要花费 25 分钟才能阅读完成。

本文为 DeepFlow 在首届云原生社区可观测性峰会上的演讲实录。回看链接 [1],PPT 下载 [2]。

很快乐有机会在第一届可观测性峰会上向大家介绍咱们的产品 DeepFlow,我置信它会是明天 eBPF 含量最高的一个分享。DeepFlow 的能力很多,而我明天的分享会聚焦于一个点上说透,心愿大家由此感知到 eBPF 带给可观测性的改革。那么我明天要分享的内容就是,DeepFlow 如何利用 eBPF 技术,在不改代码、不改配置、不重启过程的前提下,主动绘制云原生利用的全景拓扑。全景利用拓扑能解决咱们很多问题:观测任意服务的全景依赖关系、观测整个利用的瓶颈门路、定位整个利用中的故障地位。

在开始之前,我大略也介绍一下本人的背景:从清华毕业以来,我始终在云杉网络工作,咱们从 2016 年开始开发 DeepFlow,咱们基于 eBPF 等翻新技术买通云基础设施和云原生利用的全栈环节,零侵扰的实现利用的可观测性。明天的分享分为四个局部:第一局部介绍传统的解决方案如何绘制利用拓扑;第二局部介绍如何用 eBPF 齐全零侵扰的实现利用拓扑的计算;第三局部介绍如何利用 eBPF 实现过程、资源、服务等标签的注入,使得开发、运维、经营都能从本人相熟的视角查看这个拓扑;最初第四局部介绍一个全链路压测的 Demo 和咱们在客户处的几个实战案例。

01|传统解决方案的问题

首先咱们晓得,在利用拓扑中,节点能够展现为不同的粒度,例如按服务、按实例、按利用等不同粒度展示。例如对于服务粒度,一个节点代表一个服务,它由多个实例组成。节点之间的连线代表调用关系,通常也对应了一系列的指标,示意服务之间调用的吞吐、异样、时延等性能。在云原生时代,云基础设施、微服务拆分等因素会带来很多挑战,导致绘制一个全景的利用拓扑变得十分艰巨。

传统的解决方案咱们很相熟,通过埋点、插码的形式,批改代码来输入相似于 Span 的调用信息,通过聚合 Span 失去利用拓扑。即便是采纳自动化的 Java 字节码注入等技术,尽管看起来不必改代码,但还是要批改启动参数,意味着服务要从新公布,至多要重启服务过程。

插码计划的艰难 – 难以降级

在云原生场景下,应用这样的办法来获取利用拓扑变得更加艰难。随着服务拆得越来越渺小,每个服务的开发人员的自由度变得越来越大,因而可能会呈现各种离奇的语言、框架。绝对于 Java agent 而言,其余语言根本都会波及到代码批改、重编译重公布。当然个别咱们都会将这部分逻辑实现在一个 SDK 中,然而 SDK 的降级也是一个苦楚甚至失望的过程,业务方都不违心降级,降级意味着发版,发版可能就意味着故障。

那有办法能防止批改代码吗?云原生时代咱们还有一个选项 —— 应用服务网格(Service Mesh)。例如 Istio 在 K8s 及非容器环境下可构建一个服务网络。

网格计划的艰难 – 难以全笼罩

但服务网格的问题在于并不能笼罩所有协定,例如 Istio 次要笼罩 HTTP/gRPC,而其余大量各种各样的 Protobuf/Thrift RPC,以及 MySQL/Redis/Kafka/MQTT 等中间件拜访都无奈笼罩到。另外从因果关系来讲,咱们能够因为抉择了服务网格而顺带实现一部分可观测性,但必定不会因为要去实现可观测性而引入服务网格这样一个带有侵入性的技术。

除此之外,在云原生时代,即便咱们去改业务代码、上服务网格,依然无奈获取到一个残缺的利用拓扑。比方云基础设施中的 Open vSwitch,K8s 中的 IPVS,Ingress 地位的 Nginx 网关,这些都是看不到的。

上面出场的就是咱们明天要讲的配角,eBPF,它是一个十分炽热的新技术。咱们来看看它是不是能解决咱们明天聚焦的问题,是否将利用拓扑画全、画准,能为开发、运维等不同团队的人提供一个对立的视图,打消他们的 Gap。咱们晓得 eBPF 有很多很好的个性,它不须要业务改代码、不须要服务批改启动参数、不须要重启服务过程,它是编程语言无关的,而且能笼罩到云基础设施和云原生利用的整个技术栈。DeepFlow 基于 eBPF 技术也享受到了很多这方面的红利,咱们的客户做 POC、社区的用户试用都十分丝滑,不必去思考运维窗口、施行周期,DeepFlow 的社区版只需一条命令,五分钟即可开启全景、全栈的可观测性。

DeepFlow 软件架构

这里也用一页 PPT 来简略介绍一下 DeepFlow 社区版的软件架构。咱们开源至今还不到一年,目前在社区受到了不少关注。上图两头蓝色的局部是 DeepFlow 的两个次要组件:Agent 负责采集数据,利用 eBPF 的零侵扰个性,笼罩各种各样的云原生技术栈;Server 负责富化数据,将标签与数据关联,并存储至实时数仓中。在北向,DeepFlow 提供 SQL、PromQL、OTLP 等接口,通过 DeepFlow 本人的 GUI 展示所有可观测性数据,也兼容 Grafana、Prometheus、OpenTelemetry Collector 等生态。在南向,DeepFlow 可集成 Prometheus 等指标数据、SkyWalking 等追踪数据、Pyrosope 等 Profile 数据。

AutoTracing + AutoTagging

明天咱们要聚焦的一点,就是 DeepFlow 如何应用 eBPF 生成全景利用拓扑。DeepFlow 的两个外围能力 AutoTracing 和 AutoTagging 为利用拓扑的生成奠定了松软的根底。在没有任何代码批改、不重启任何业务过程的状况下,咱们实现了全景利用拓扑的绘制。首先,咱们可通过 eBPF 从网络包、内核 Socket Data 中获取原始比特流;接下来咱们剖析 Raw Data 中的 IP、端口等信息,应用 eBPF 将原始数据与过程、资源、服务等信息关联,以便绘制不同团队不同视角的利用拓扑,这也是明天分享的第三局部;而后咱们会从原始数据中提取利用调用协定,聚合调用中的申请和响应,计算调用的吞吐、时延和异样,以及其余零碎和网络性能指标;最初,基于这类 Request Scope 的 Span 数据,咱们能够聚合生成全景利用拓扑,也能够通过关联关系的计算生成分布式追踪火焰图。

明天咱们次要讲的是利用拓扑的绘制,对于应用 eBPF 实现全自动的分布式追踪这个话题,DeepFlow 社区的博客 https://deepflow.io/blog 上有很多材料。

02|eBPF 零侵扰计算全景利用拓扑

Universal Application Topology

首先让咱们看一个效果图,这是 DeepFlow 展现的一个全景利用拓扑。这个拓扑可能大家比拟相熟,它是 OpenTelemetry 的一个 Demo,它 Fork 自 Google Cloud Platform 的一个我的项目,它是一个小型的电商利用。从图中能够看到,DeepFlow 能够获取所有服务之间的调用关系以及相应的性能指标,这都是通过 eBPF 实现的,没有做任何的代码批改和过程重启,展示这些后果之前咱们敞开了所有 OTel Instrumentation。

在这一节,咱们将聚焦四个问题:第一个问题是如何采集原始数据;第二个问题是如何解析利用协定,eBPF 做了什么;第三个问题是如何计算全栈性能指标;第四个问题是如何适配低版本内核,许多用户的内核版本可能是 3.10。

数据采集:DeepFlow 同时用到了 eBPF 和它的前身,有 30 年历史的 Classic BPF(cBPF)。在云原生环境中,利用过程运行在容器 Pod 内,容器可能存在于多个节点上,并通过网关连贯到数据库等其余服务。咱们能够应用 eBPF 技术来笼罩所有的端节点,并应用 cBPF 笼罩所有的两头转发节点。从利用过程(端节点)层面,咱们应用 kprobe 和 tracepoint 笼罩所有的 TCP/UDP socket 读写操作;并应用 uprobe 来挂载到应用程序内的外围函数上,比方 OpenSSL/Golang 的 TLS/SSL 函数,来获取加密或压缩之前的数据。除此之外,在两个服务之间还有许多两头转发门路,例如 IPVS、iptables、OvS 等,此时须要应用 cBPF 来获取网络包数据,因为这部分流量不会有用户态应用程序去读写,会间接在内核里查表转发。

eBPF Probes

这里列举了 DeepFlow 中次要应用到的 eBPF Probe,包含最右边的 kprobe,以及两头最高性能的 tracepoint,以及最左边解决加密和压缩数据的 uprobe。其中 tracepoint 满足了 DeepFlow 中的绝大多数需要。

协定解析:在获取原始数据方面,咱们应用 eBPF 和 cBPF 来捕捉字节流,但此时咱们无奈看到任何可了解的信息。接下来,咱们要做的就是从这些字节流中提取出咱们关怀的利用协定。大多数协定都是明文的,例如 HTTP、RPC、SQL 等,咱们能够间接遵循协定标准来解析它们的内容。对于一些非凡的协定,例如 HTTP2 之类的压缩协定,咱们须要进行更简单的解决。咱们能够应用 tracepoint 或 kprobe 来提取未压缩的字段,但此时对于曾经压缩的头部字段,还原它们是一项艰难的工作,因而咱们会抉择应用 uprobe 作为补充来采集压缩协定的数据。另外对于加密流量也无奈从内核函数中获取明文,咱们通过 uprobe 间接获取加密之前的数据。最初,对于公有协定,它们没有可遵循的通用标准,或者尽管遵循了 Protobuf/Thrift 等规范但无奈提供协定定义文件,此时咱们提供了基于 WASM 的插件化的可编程接口,在将来也有打算提供基于 LUA 的插件机制。

在协定解析层面还须要思考的一个事件是流重组。例如一个 HTTP2/gRPC 申请的头部字段可能会分为屡次零碎调用读写,或者分拆为多个网络包收发,此时咱们须要还原残缺申请或响应头,一遍重组一遍尝试解析。

eBPF + WASM

特地提一下咱们对公有协定的辨认,通过联合 eBPF 和 WebAssembly 的能力,提供一个灵便的插件机制。插件在 DeepFlow 中解决两个问题:提供对公有协定的解析能力、提供对任意协定的业务字段解析能力。商用软件供应商或业务开发人员能够轻松增加自定义插件来解析协定,将可观测性从 IT 层面晋升到业务层面。这样的形式使得咱们能够自定义提取出一些业务指标或业务标签,例如订单量、用户 ID、交易 ID、车机 ID 等信息。这些业务信息对于不同的业务场景都是独特的,咱们将这个灵活性给到了业务方,使得业务方能够疾速实现零侵扰的可观测性。

RED Metrics

性能指标:咱们能够通过数申请和响应的个数来获取吞吐量,同时还能够依据响应状态码、耗时等信息计算 Error 和 Delay 指标。吞吐和异样的计算绝对简略,只须要基于单个申请或单个响应进行解决即可。最艰难的是对时延的计算,咱们须要应用 eBPF 技术来关联申请和响应这两个动作。这个过程又分为两步:从 Socket/Packet Data 中基于 <sip, dip, sport, dport, protocol> 五元组聚合出 TCP/UDP Flow;而后在 Flow 上下文中匹配利用协定的每一个 Request 和 Response。而对于第二步,一个 Flow 中个别会有多个申请和响应,匹配逻辑咱们以 HTTP 协定为例解释:

对于串行协定如 HTTP 1.0,间接匹配邻近的申请和响应即可对于并发协定如 HTTP 2.0,须要提取协定头中的 StreamID 进行申请和响应的配对还有一种非凡状况即 HTTP 1.1 中的管道机制,他是一种伪并发协定,咱们能够利用它的 FIFO 特点实现申请和响应的配对

Network Metrics

然而,在云原生环境下,仅仅只统计应用层 RED 往往不够。例如咱们会发现客户端侧看到的时延是 3 秒,而服务端侧看到的时延是 3 毫秒;或者客户端和服务端侧都看不到有申请,但上游服务却报错了。针对这些场景,咱们基于 Flow 数据计算失去了网络层面的吞吐、异样、时延。业务开发发现时延高时,能够疾速查看网络层时延来判断到底是业务本身的问题还是基础设施问题;另外在发现申请报错时能够疾速查看是否建连或者传输异样了。

针对时延咱们分的更粗疏,通过从 Packet Data 中重建 TCP 状态机来更加精密的展示各个层面引入的时延。在生产环境中咱们会发现高时延的起因个别分为几个方面:

建连慢:因为防火墙、负载平衡、网关的影响,导致 TCP 建连过程慢,这一过程又进一步拆分为了到底是客户侧建连慢还是服务侧建连慢框架慢:因为业务代码在建连后的慢解决,客户端在建连后期待了一段时间才发送申请,这段等待时间咱们会刻画为客户端期待时延,它可能方面定位到底是框架 / 库层面的问题,还是业务代码的问题零碎慢:因为操作系统解决不及时,例如零碎负载低等,对申请的 TCP ACK 回复慢,从而导致 TCP 无奈高效增大窗口大小传输慢:网络重传、零窗等也是导致高时延的一些可能起因

在云原生环境下,还有一个特点是网络门路十分长,例如两个服务之间的通信可能顺次通过容器 Pod 网卡、容器 Node 网卡、KVM 主机网卡等。门路的复杂性也是引发传输慢的次要起因。因为 DeepFlow 同时应用 cBPF,因而能够从所有两头转发门路中观测到应用层和网络层的时延,而后通过比照逐跳时延来定位到底是哪一跳开始呈现了问题。

System Metrics

除了网络层面以外,造成慢调用的还有一个重要起因是 IO 慢。例如 Client 拜访 DB 时可能呈现时延抖动,而这些抖动通常是由 DB 的文件读写慢导致。再例如大数据场景下一批 Worker 中可能总有那么一两个 Worker 实现的慢,排查后会发现通常是因为文件读写慢导致。这里 DeepFlow 的做法是观测所有与利用调用相干的 IO 时延,并记录所有的慢 IO 事件。实现层面,文件 IO 与 Socket IO 事件可通过 tracepoint/kprobe hook 同样一组函数获取到,通过 FD 的类型能够进行辨别。依附这样的能力,咱们能疾速的定位到 deepflow-server 写入 clickhouse-server 偶发性慢是因为文件 IO 时延抖动造成,且能定位到具体的文件门路。

低版内核:最初咱们总结一下本节。咱们心愿在低版本内核中 DeepFlow 也能展示更多的能力。以 Kernel 4.14 为界,DeepFlow 在 4.14+ 的环境下能够基于 eBPF 实现全功能,包含加密数据的观测、利用过程的性能指标、零碎层面文件 IO 性能指标,以及全自动的分布式追踪能力。而在 4.14 以下的内核环境中,咱们基于 cBPF 也实现了大部分的能力,包含对于明文协定、公有协定的观测,对于压缩协定局部头部字段的观测,以及对于利用性能、网络性能指标的采集,对于性能指标的全栈门路追踪。

03|eBPF 主动关联服务和资源标签

讲到这里实际上咱们整个指标只实现了一半。咱们从原始数据中提取进去了指标、调用关系、调用链,但还须要以开发者相熟的形式展示进去。Packet 和 Socket Data 中只有 IP 和端口号信息,这是开发和运维都无奈了解的。咱们心愿所有的数据都能从实例、服务、业务等维度按需展现。
在这个问题上咱们也遇到了一些挑战:我会先介绍从哪里采集标签,以及采集什么样的标签;而后探讨轮询采集的形式会带来哪些问题;接下来我会介绍一下基于 eBPF 的事件触发的计划,来防止轮询的缺点;最初同样的也会介绍一下咱们在低版本内核环境下的一些能力。

标签数据:首先仅通过 IP 地址是不能残缺关联客户端和服务端的服务信息的,这是因为理论环境中普遍存在 NAT,包含 SNAT、DNAT、FULLNAT 等。实际上通过单侧的 IP+Port 也难以精确关联,这是因为 Client Port Reuse 也是一个普遍存在的景象。因而,在 DeepFlow 中应用五元组来将通信端点关联至服务。具体来讲,咱们会通过 K8s apiserver 获取 IP 对应的容器资源标签;通过 CMDB 及脚本化的插件获取 PID 对应的业务标签信息;而后再依附上面要讲的一些机制将 IP+Port 的五元组与 PID 关联起来,最终实现资源、服务、业务标签的主动注入。

轮询计划:咱们首先能想到的是通过轮询 /proc/pid/net/ 文件夹来获取 PID 与 Socket 五元组的关联。每个 agent 获取本机的关联信息,并通过 server 替换失去全局的关联信息,从而使得每个 agent 能独立的为客户端和服务端标注双端的 PID 信息。

轮询计划也会碰到一些挑战,例如 LVS 场景下,/proc 下的 Socket 信息指向的是 LVS,但从业务上来讲咱们心愿获取 LVS 背地的 RS 的过程信息。DeepFlow 通过同步 LVS 转发规定解决这个问题。具体来讲,基于 LVS 规定和包头中嵌入的 TOA(TCP Option Address)字段,能够疾速的在 RS 上定位客户端的 PID,并通过 LVS 转发规定疾速的在客户端侧定位服务端的 PID。

触发计划:过后轮询总会存在工夫距离,因而永远无奈解决短连贯的监控问题。在这方面 DeepFlow 也做了一些工作,这就是上面咱们要介绍的触发式计划。

受 TOA 的启发,咱们基于 eBPF 实现了一个 TOT(TCP Option Tracing)的机制,即在 TCP 包头 Option 字段中嵌入额定的信息,示意发送方的 IP 和 PID。这样的话咱们就能将源发的过程信息告知对端了。为了实现这样的机制,咱们应用 eBPF sockops 和 tracepoint,一共 Hook 了五个函数。咱们会在每个 TCP SYN、SYN-ACK 包中注入 TOT 信息,使得连贯新建时即能标记过程信息。同时也会概率性的抽取 TCP PSH 包注入 TOT,使得对于长连贯,即便 agent 的启动工夫滞后于业务过程,也能及时获取到过程信息。

低版内核:同样这里也分享一下咱们在低版本内核上做的一些工作。首先轮询的计划依附扫描 /proc 文件夹实现,因而是能适配所有 2.6+ 的内核环境的。在 3.10 及以上的内核中,咱们也提供了一个精美的 ko 模块来实现 TOT 的注入,这个内核模块仅有 227 行代码,咱们也进行了开源,欢送大家应用。

04|Demo – 继续观测全链路压测性能瓶颈

OTel Demo

最初通过一个 Demo 介绍一下这些工作的成果。咱们依然是以 OTel 的电商 Demo 为例,依然是敞开了其中的所有 OTel Instrumentation。抉择这个 Demo 的理由在于,他是一个典型的微服务架构的利用,且尽力模仿了比拟实在的电商场景,微服务的实现语言涵盖了十二种之多,也蕴含了 PostgreSQL、Redis、Kafka、Envoy 等中间件。

首先咱们能够看到,不批改代码、不批改启动参数、不重启过程,咱们曾经能主动绘制微服务粒度的全景利用。当咱们注入一个 1.5K QPS 的压力时,能清晰的在拓扑中看到瓶颈链路。沿着 frontend 服务一路往下,也能疾速的定位瓶颈服务 ProductCatalog。接下来咱们分为三次,别离将 ProductCatalog 扩容至 2x、4x、8x 正本数,扩容的过程中也可清晰的看到瓶颈链路在逐步隐没,晓得最终所有服务的时延恢复正常。

除了这个 Demo 意外,这里也分享几个咱们在客户处的实战案例:

  • 某造车新权势客户,应用 DeepFlow 从数万 Pod 中在 5 分钟内定位 RDS 访问量最大的 Pod、所属服务、负责该服务的团队。
  • 某股份制银行客户,信用卡外围业务上线碰壁,压测性能上不去,应用 DeepFlow 在 5 分钟内发现两个服务之间 API 网关是性能瓶颈,进而发现缓存设置不合理。
  • 某互联网客户,应用 DeepFlow 在 5 分钟内定位服务间 K8s CNI 性能瓶颈,辨认因为环路造成的某个服务高低云拜访时延周期性飙升的问题,云厂商两周无解。
  • 某证券客户,应用 DeepFlow 在 5 分钟内定位 ARP 故障导致 Pod 无奈上线的问题,「霎时」完结业务、零碎、网络多部门「会商」。
  • 某基础设施软件客户,应用 DeepFlow 在 5 分钟内定位 Rust 客户端应用 Tokio 不合理导致的 gRPC 偶发性超大时延,终结了 QA 及多个开发团队之间踢来踢去的 Bug。
  • 某四大行客户,应用 DeepFlow 在 5 分钟内定位某个 NFVGW 实例对特定服务流量不转发导致的客户端频繁重试。

从这些案例中咱们能发现,依附 eBPF 技术的零侵扰个性,咱们能残缺的笼罩利用的全景调用拓扑,且能展示任意调用门路中的全栈性能指标。得益于这些可观测性能力,咱们能疾速的定位 RDS、API 网关、K8s CNI、ARP 故障、Rust Tokio 库、NFVGW 造成的故障。

Distributed Profile

这是最初一张 PPT,我想和大家分享一下 DeepFlow 对可观测性的更多思考。在传统 APM 中,咱们通常应用 Span 之间的关联关系以火焰图的形式展示一次分布式调用(Trace),也会讲所有的 Span 聚合为指标来展示所有服务之间的利用拓扑。咱们发现拓扑展示了所有调用的数据,而追踪展示了一个调用的数据,它们二者恰好是取了两个极其。DeepFlow 目前正在摸索,两头是否有一个折中的点,他们展现一组聚合的火焰图或拓扑图,有点相似于单个过程的 Profile,然而用于分布式应用的场景,咱们称它为 Distributed Profile。咱们置信这样的折中会带来效率的晋升,它不香所有调用聚合而成的拓扑,会有太多噪声;也不像繁多申请展现进去的 Trace,问题排查须要一个一个 Trace 的看。

而 eBPF,正是绝佳的实现 Distributed Profile 的技术手段,请期待后续咱们进一步的分享。

05|什么是 DeepFlow

DeepFlow[3] 是一款开源的高度自动化的可观测性平台,是为云原生利用开发者建设可观测性能力而量身打造的全栈、全链路、高性能数据引擎。DeepFlow 应用 eBPF、WASM、OpenTelemetry 等新技术,翻新的实现了 AutoTracing、AutoMetrics、AutoTagging、SmartEncoding 等外围机制,帮忙开发者晋升埋点插码的自动化程度,升高可观测性平台的运维复杂度。利用 DeepFlow 的可编程能力和凋谢接口,开发者能够疾速将其融入到本人的可观测性技术栈中。

GitHub 地址:https://github.com/deepflowio/deepflow

拜访 DeepFlow Demo[4],体验高度自动化的可观测性新时代。

参考资料

[1] 回看链接: https://www.bilibili.com/video/BV1B14y1f7UB/

[2] PPT 下载: http://yunshan-guangzhou.oss-cn-beijing.aliyuncs.com/yunshan-…

[3] DeepFlow: https://github.com/deepflowio/deepflow

[4] DeepFlow Demo: https://deepflow.yunshan.net/docs/zh/install/overview/

正文完
 0