DeepFlow 在小米落地现状以及挑战 精华
编者按:本文整理自小米集团高级工程师谭槊在《蓝鲸 X DeepFlow 可观测性 Meetup》 中的分享实录,详细阐述了将DeepFlow 融入小米现有的可观测体系中的一线落地经验,用 DeepFlow 零插桩、全覆盖的能力解决了现有痛点,还解决了传统主机下 cBPF 如何关联流与进程、 LVS NAT 造成的服务拓扑断链等难题,并展望了与 DeepFlow 合作共建的未来,构建小米全新的可观测体系新阶段。
大家好,我是来自小米的谭槊,今天非常高兴来参加 DeepFlow X 蓝鲸的线下 Meetup。我先做一下自我介绍,我是目前在小米监控系统组的高级工程师, 21 年加入小米。今天来这边分享的目的是简短地介绍一下目前 DeepFlow 在小米在业务中的切入点。因为我是一线研发,所以我大致讲一下在落地的过程中遇到了哪些挑战,以及遇到这些挑战后,我们和社区是如何努力去解决这些问题的。最后我讲一下在小米内部落地的一些业务。
我今天的分享分五部分展开:第一章会说一下小米可观测性的现状和规划,这一部分大致介绍一下我们的团队,以及我们是干什么的。我们团队在项目中会有一个主线作为年度目标,以及大致讲一下团队项目的全景图。第二章是为什么我们要引入 DeepFlow,在我们团队已经有一个很明确的主线的情况下,引入 DeepFlow 的动机和动力是什么?第三章 DeepFlow 在小米内部的部署架构介绍,我这边是从研发角度上而不是从产品角度上(来介绍部署架构),研发层面上我们是通过技术上部署(和架构调整),来介绍如何把 DeepFlow 从架构上和我们小米内部已有的一套可观测性架构进行融合。第四章讲我们已经把 DeepFlow 部署起来了,在推广它的时候遇到了一些挑战,过程不是一帆风顺的,我们针对遇到的挑战有技术上的一些解法,最后会给大家看一下,目前给我们的用户,也就是给业务方带来的可观测产品,目前产品不是很多,会有一个长期的如何跟 DeepFlow 展开深入合作的规划路线图。
我还补充一下,目前小米和 DeepFlow 合作的方式是以社区共建的形式合作的,我们这边也投入人力,然后在社区中走的都是社区的正规流程,提 FR、PR,然后我本人也提供过多个 FR 和多个 PR。
小米可观测性的现状与规划
第一章介绍我们团队,我们组为小米集团提供日志、指标、链路等可观测性的数据,这是可观测性数据的三个维度,通过平台将这些数据结合,帮助业务发现、定位和解决问题。先介绍一下我们的历史成果,以往我们主要面向的用户群体是 SRE,我们的第一阶段叫 SREOps,这个是我们提供的覆盖全集团的主机基础指标监控能力。这里面主要就是技术(编者按:基础设施)的指标,包括 CPU,内存,这块我们已经把它做完了,全集团已经铺开了,所有的机器都装了我们的采集器。这是第一阶段。
第二阶段主要是做可观测性,集中突破 DevOps,我们的目标用户从 SRE,也就是专业的运维同学,变成一线业务研发同学,这个阶段是当前的重点阶段,也是我们现在做的一块。目前这个平台已经差不多做完了,但是还没有向集团全部推出去,这是我们目前的目标。然后未来愿景,也是我们今年的具有挑战性的下一个目标,就是在全集团实现 DevOps 能力,覆盖任何应用,覆盖任何链路。
首先讲下 Falcon,如果是做可观测性的话,应该对 Falcon 这个产品比较了解。这是小米内部孵化的,也是我们团队目前在维护的一块,它重点面向的核心用户群体是我们的 SRE 。Falcon 提供的都是主机粒度的一些指标,比如 CPU、内存,磁盘、网络 IO 之类。目前部署范围是全部的主机,包括国内、欧洲、新加坡、印度、美国等多个机房,超过上万台主机。目前这个产品功能已经非常完善了,我们就不在上面继续进行深入迭代了。
除了我们自己做的 Falcon 之外,还有一些基于开源的知名项目(作为)我们的核心项目,我们做了一些日志链路和指标的一些单品,所谓单品即它们是各自为一个平台,没有一个统一的平台,相当于我们给业务方提供的散点指标数据,但是并没有提供一套完整的平台帮业务解决、发现问题或者定位问题。
日志相关的组件就是 Loki 和 ES,Loki 主要是面向于成本需求比较高的业务,ES 面向功能和性能要求比较高的业务。链路我就不多说了,就 OpenTelemetry 部分,我们跟他们架构是一样的,功能也是一样的。
指标相关的组件除了 Falcon 以外,Falcon 我们前面也说了它是主机维度监控,而小米最近也在做云原生的发展,所以也引入了 Prometheus 来弥补 Falcon 在云原生上的短板。
后面会重点介绍一下,这是我们今年在做的 DevOps 的能力,也就是 Hera 可观测性平台。Hera 可观测平台做了一件事情,在我们之前已经有日志、链路和指标这三个维度的基础之上,把这些指标进行融合,提出了一个应用为中心的维度,我们会有一个应用中心(作为可观测的入口)。
为什么要以应用为中心?因为现在主流的 DevOps 的展开都更加贴近业务方,应用对于业务方来说是更加亲近的,相当于我们把所有数据进行了应用维度的融合,右边是我们对接的平台,还是分两部分,一个是小米内部的容器平台,另一个就是小米内部的主机部署平台,因为小米内部在做云原生的时候迁移过程比较艰辛,导致它目前主机部署和云原生部署两套方案是并存的。我们以往在主机平台和容器化平台看指标监控的时候,或者看日志的时候,是要切换到不同平台看的,目前我们以应用为中心,相当于把这两个平台的细节对用户屏蔽了,用户现在就直接在我们应用中心去看监控数据,以应用为维度去观测我们服务的可靠性。
这边功能展开有应用状态、调用异常慢查询、服务大盘,最后还有告警。应用状态,(简单讲就是)应用有时候会存在一些大量的 (HTTP)5XX 或者慢请求,应用会进入异常状态,我们的业务方会收到报警。然后调用异常是基于 Request Scope (来区分)的,也就是 OTel 的那一套,(以及)火焰图(这一套逻辑)。业务可以根据 trace 单个的请求,比说单次的慢查询或者慢请求,假设超过两秒钟,我们会进行尾采样,然后把它放到调用异常里面去,以事件的形式提供给用户,然后用户可以通过 Request ID 把整个链路完整地串联起来。
慢查询主要是以 DB 为维度的,我们可以看到那种请求比较慢的 SQL,比如说运行超过十几秒甚至更多的SQL,这个慢查询扫描到的话会结合 DBA 的平台给出慢查询优化的建议。然后服务大盘是自动生成的,主要是一些七层协议,像 HTTP,像我们内部的 RPC 框架 R.E.D.指标,也就是黄金指标的监控。服务大盘虽然我们会自动给它生成一个,但是有的用户对 SLA 的定义是不一样的,所以这会是一个自定义大盘,我们的可观测性平台目前功能是这些,重点就以应用为中心,目前是在向外推广的阶段,也是我们现在的工作重心。
有一个比较简单的使用案例,我们的用户收到服务异常的告警,比如说 SLA 下降,他会打开并查看监控,然后可以看到下降的到底是哪几个接口,同时我们在日志和链路的追踪里面,可以关联到我们的异常事件,这下面有一个 Trace ID,我们点开后就展开看火焰图的 Span,就可以定位到那种耗时比较大的 Span。比如在这个场景下,我们发现一个 MySQL 的请求执行超过了 2 秒,就结合 DBA 系统得出故障分析,从我们的定位到发现问题到解决问题,最后到我们写出报告,整个时间周期是 20 分钟。
而且这个系统上手成本也很低,因为它比较简单,我们的核心目标就是帮助业务方可以快速地、简单地定位到问题并且快速解决,保证业务方的服务稳定性好。
然后说一下我们团队目前的规划,前面总结一下,首先是定义了 L1、L2、L3、L4 这四个工作阶段,我们这个跟行业界内的定义有一点小小区别,但是目前从上到下的规划是越来越自动化、接入成本越来越低,现在我们重点就是在 L3 这个 DevOps 上面。
为什么要引入 DeepFlow?
前面我们就说了,现在工作重点是推 Hera,然后实现 DevOps。那现在就说为什么我们要引入 DeepFlow?
在推 Hera 的过程中,我们会发现有几个问题,
首先最大的痛点是 Hera 探针接入成本比较高,覆盖的应用不全,如果我们要向全集团全部的业务去推进 Hera 的话,那它必须要形成完整的覆盖度。但我们在推的时候有一些很难推,有些业务可能有需求排期或者需求倒排之类的(编者按:探针的插码可能被业务团队放到业务需求之后),接入成本高。那如果在我们的 Hera 探针接入后,我们是不是就不需要 DeepFlow 的自动化采集?其实并不是,我们在接入 Hera 探针后, DeepFlow 还是可以对我们 Hera 的探针进行功能上的补全的。后面我也会详细说一下,目前主要是这两个痛点。
首先是 Hera,我们采取的是 OTel 探针,OTel 探针做可观测性的话会比较了解,我们是基于社区版本做了一个简单的改造,对小米内部的一些功能做了适配。我们可以看到有两种接入方式,一个是 Golang 的应用,一个是 Java 的应用,其实它们两个接入方式是不一样的。
如果是 Go 应用的话,我们内部的话可能会有一个微服务框架,可以通过中间件的方式,把 OTel SDK 给加进去,这样它会在一些核心的地方,比如说网络请求加入一些自动上报的逻辑。但有的没有用框架,那就得手动地写代码了,你得在网络调用地方手动地去写上报逻辑。
然后下面是 Java 应用, Java 应用比较简单点,它可以通过 Agent 的字节码注入技术,自动地把 OTel 探针注入到 Java 应用中去。
然后接入成本就是可能要改启动命令,虽然成本比较低,但也涉及到业务的发版。
这边大致是 Hera 如果不用 DeepFlow,而用探针的接入方式来做接入。Java 的我们加一个命令行加入 Agent,这样启动的时候就可以自动地实现探针的功能了。
然后这是 Go,你可以看到它的整个流程是比较复杂的,首先要代码改造,业务方代码改造后他们一定不会全量上线的,可能要灰度验证一段时间,最后到上线需要至少一周。第二就是改造成本过高,业务方研发会降低优先级,前面也说了,小米内部有一些盈利的业务,他们可能不会优先考虑到接探针,他们先要完成他们的活动任务,这就会降低优先级,我们推得就比较困难。第三就是很多业务研发对指标链路上报的原理不太熟悉,特别 Golang 需要手动去加探针,需要拉群沟通协作,然后可能我们需要安排一个人力,专门协助他们去接入 Hera,对团队的整体的负担比较大。
(右边的扇形图)最后给一个结论,我们现在大概接入 Java 的应用大概有 5000 个,接入 Golang 的应用只有 300 个,这个之间的比例关系就可以看出来,它接入的数量肯定是跟接入成本是相关的。
前面说接入的痛点后,我再说一下,其实我们已经接入了 OTel 探针,实现了全链路追踪的能力,那 Hera 全链路追踪能力的应用还存在什么问题?
首先进程内的探针只能获取一头一尾,无法获取 trace 到网络的链路,这边有个例子,请求从 Client 出去,跨专线、跨机房的业务,它会走专线,先到域名解析,然后要进入容器网络,进容器网络、出容器网络,然后可能走专线的话要经过网关,然后到专线,到另一个机房的网关,然后再进七层代理,七层代理前面可能还有个 LB,最后到 Server 的容器网络,最后进入 Server。
整个过程中有很多中间环节,但是目前我们加 OTel 探针的形式,只能获取客户端发送 Request 到 Server 收到 Response 中间的 Span,
所以我们看到有个2秒的时延,但是我们并不知道这个2秒到底是因为 Server 的不稳定,还是 Client 不稳定,还是因为中间网络链路的不稳定而导致的,这是我们现在的问题。
这边有个图,可以看到有个2秒钟的一个 Span,但它下面没有细节,你只能告诉用户就这个请求不稳、很慢,但你不能告诉他哪里慢,这个就容易造成两方的拉扯,服务端和服务依赖方(编者按:基础设施)两方拉扯,(最后发现)其实两边都没有问题,而是网络的问题。
网络问题其实在业界中也是会频繁发生的,我们在 Hera 业务使用的时候也发生过。首先是海外专线因为施工被挖断,导致业务出现大量的超时。还有机房的网络割接,小米经常在凌晨的时候会做一些网络割接,这个过程虽然很快,但中间可能会出现一些临时性的网络抖动,可用性就会造成波动,凌晨的时候有很多业务方收到告警了,说服务的稳定性、可用性下降。第三个就是交换机故障,导致后面的服务全部访问超时全挂了。第四个就是域名解析负载高,响应慢导致业务超时,这都是我们遇到过的一些问题,但这些 Hera 并不能回答到底是什么原因引起的。
我们说重点,为什么要选择 DeepFlow。首先 DeepFlow 是真正的零侵扰的自动化采集,用户不需要修改任何代码发布版本,整个接入过程中是完全无感的。
我们之前要推业务方,一个模式就是我们会跟对方拉群沟通,然后跟对方说怎么排期,或者帮助他们去解决问题,甚至拉很多会去沟通接入的收益。但现在不需要了,现在我们如果想去跟他们覆盖 Hera 的能力的话,我会直接地拉他们的产品运维、一线运维或者他们的 leader,我们就告诉他们说要在你们这个试点用 DeepFlow 了,他们如果对性能不满意的话,我们会甩一个压测文档,我告诉他们整个接入过程是无感的,不需要他们投入任何人力,只需要运维看一下有没有问题就行了。这个接入过程非常顺畅,接入也很快,可以一下接入大量的业务。
第二点就是我们当时调研的时候,其实 DeepFlow 是有竞品的,像 Pixie 或者是其他的,我们都当时都调研了一遍,我们为什么选择 DeepFlow 去适配 Hera 作为基础采集功能,是因为 Hera 的 L7 的看板,跟 DeepFlow 提供的官网的看板是一模一样的,没有任何区别,包括我们协议的解析。可以这样说,DeepFlow 向下兼容了 Hera 的看板,里面包括 Dubbo、HTTP、Redis、MySQL 的黄金指标,我们在 DeepFlow 中都可以找到,是和 Hera 完全一样,就不用做任何改造了。
第三点,这个是一个比较偏小米集团的功能诉求,我们对比其他的几个竞品 cBPF 这方面做得不是特别好,我们对比了一下 eBPF 能力,固然很多产品都做得很强,但 cBPF 的能力能做到 eBPF 80% 的能力的产品其实很少。
所以说我们当时选择 cBPF 能力比较强的 DeepFlow,因为适配内核和兼容小米当前的主机环境,这个我们后面也会说的。小米有一些比较偏传统的业务,它的主机内核版本很老,有 3.0 以下版本的内核。
然后是刚刚解释的无法回答用户是否因为网络问题引起的故障的案例,我们现在可以回答了。首先 DeepFlow 是原生支持网络 Span 的,这是 DeepFlow 的核心特性,它可以零侵扰地生成网络 Span,采集的点非常细。我们当时也调研了,从容器网卡出来到交换机,到路由到 NAT,每一层的网络 Span 都可以生成。不过对于小米内部其实我们不需要这么精细,这个功能已经超出了我们预期很多了。其实我们只需要知道客户端网卡到服务端网卡之间的网络 Span,然后这个 Span 我们的业务研发同学看不懂,你只要告诉他是网络问题,然后去找网络组就可以了。所以结论就是,我们只需要一个客户端网卡到服务端网卡中间的一个网络 Span 就可以解答我们用户的问题了。
第二点也是非常重要的,也是当时我们选型的目的,Hera 当前的数据源,也就是我们的 ES,还有和我们的链路追踪的 OTel 的 ES 数据源,和 DeepFlow 的 Clickhouse 里面 Span 是天然打通的。在我们调研之前,社区都已经给出方案了,开发成本是很低的,之前也咨询过 DeepFlow 团队提供了两套方案,第一套方案是直接把 ES 数据导到 Clickhouse 里去,但这个方案对我们的侵扰太大了,本身我们的内部的 ES 也有很多同学在维护,所以我们选取了
第二套方案,我们通过 DeepFlow 提供的 API 的能力,把 DeepFlow 的 Span 以 W3C 那种标准的协议格式导到我们 Hera 的当前链路的数据中去,然后我们通过 Trace ID 以及 Parent Span ID 关联。由于 OTel 是一个标准的协议,所以是天然打通的,开发成本很低,我们当时试了一下,这个功能还没有正式地去推,但是我们已经在调研中了,目前我们调研发现整个接入过程应该是很快的,开发成本很低。
还要感谢的就是 DeepFlow 社区支持力度很大,团队也非常专业。我们提的一些 FR 都是以双周为一个节点进行推进的,这是我们取得的一些成就。后面也会说一下,首先是加强 cBPF 能力,满足业务需求的前提下,我们的理论覆盖率,意思就是到底有多少个主机能够覆盖到我们 Hera 的特性,通过 DeepFlow 的覆盖能力实现 Hera 的功能,最开始 30% 是因为我们只有 30% 支持 eBPF,然后我们有 cBPF 能力加强后,60% 的机器就可以实现 Hera 的无侵扰的部署能力了。但它仍然不是100%,后面还有一些更老的内核的主机,比如说像 3.x 老内核主机,可能在 cBPF 的能力上面也有缺陷。我后来又经过跟社区一起努力,从 60% 又提到 80%,这个时候其实离全量覆盖很近了。
最后还有 20% 是最老的 2.6 版本内核。其实我们也适配了,但它是存在一些技术问题的,比如像 Cgroups 的隔离性,它做得不是特别好。后来我们出于安全的考虑就没有去推这20%,当然社区也在出方案,我们最后还是会全量覆盖。最后优化应用的拓扑图的展示,为用户提供更清晰的拓扑信息。
DeepFlow 在小米的部署模式
接下来讲一下我们大致在小米中的部署框架,大家使用 DeepFlow 产品的时候知道, DeepFlow 的 Agent 采集器部署是分两种方式去部署的,一个是云原生部署,一个是传统主机部署,就是云主机或者物理主机的方式。小米内部我们前面也说了,有两套平台,一个是主机应用平台,一个是容器应用平台。所以说我们部署方式也分了两套。
首先是传统主机的部署架构,我们做了一个比较巧妙的设计,我们之前也说到有个 Falcon,即 SREOps 的产品,我们的采集器其实已经覆盖集团所有主机了。这个时候我们要推 DeepFlow,如何把它也向全集团去推呢?其实我们可以搭我们的 Falcon Agent 的顺风车,我们把 Falcon 的 Agent 进行了改造,把 DeepFlow 的功能融合进去了。这边可以看到绿色的方框内是我们采集对象的主机,上面有 DeepFlow Agent,它对接的是 cBPF 和 eBPF 的探针,然后 Falcon Agent 采集的是主机的基础指标,包括 CPU、内存。最下面我们还有个插件,就是之前 DeepFlow 采集的 Flow Metrics 和 Flow Log 这些信息,它是没有应用信息的,我们通过这个插件跟我们的应用发布系统联动,用户发应用的时候会在主机上留应用元信息,包括应用的细节,比如进程也即 PID 的映射,然后这个插件就是把这个映射同步给 DeepFlow 的集群,这样就可以给 DeepFlow 的流打上我们的应用信息,也满足了 Hera 的以应用为核心的需求,最下面有一个 Super Agent,其实就是把三个 Agent 进行融合,进行统一化的部署。然后右边做一个简单的管控面,这个管控面是我们内部用的,我们可以看到有多少个机器覆盖了 DeepFlow 的 Agent,有多少个开启采集配置,采集配置下发分两部分,一个是静态配置的下发,需要重启 Agent,还有一个是 DeepFlow 本身的动态配置下发,比如说它采集规则还有其他比较灵活的配置,也集成到配置下发这个功能模块里面了。
最后是我们的 Agent 编译部署平台,我们有一个全量更新的过程,通过发布工单,比如发布到全集团的机器,然后一个一个地去更新,比如 DeepFlow 有功能要更新或者有 bug 要解决,我们就通过工单系统一次性把它全量升级。另外还有自动化的发布脚本,小米集团所有新采购机器预装的时候,我们会执行这个脚本,它从 FDS 里面拉 Super Agent 的二进制包,然后把 Super Agent 部署到新机器上面去。
最下面(红色箭头)是一个数据链路,这个数据面相当于 DeepFlow 通过 Super Agent 传到 DeepFlow 集群里面去,这是传统主机部署。后面有容器平台与部署,这个就是开箱即用了,就是社区的 Helm 部署,我们直接执行一下 10 分钟就可以搞定。
这个服务端的架构中间绿色部分就是开源社区提供的能力,我们提供了几个用户的终端,也就是 Hera 的界面。首先就是我们刚才说的 L7 协议的,比如 Dubbo 或者 HTTP 的一个 R.E.D. 的黄金指标,我们是通过 Grafana, 再通过 DeepFlow 的插件,直接以看板的形式暴露给用户的。
然后下面是链路,其实我们前面也说到了,首先我们的链路是基于 OTel 探针的,不是替换,我们是加强 OTel 探针采集的 Span,OTel 探针会通过 MQ 把我们的 Span 数据传到 ES 里面去,同时我们会有个服务,在给用户链路火焰图的时候,会同时从 ES 里面去查 Span,包括业务自己上报的 Span 和 DeepFlow 生成的网络 Span 和系统 Span,我们会把它融合在一起形成融合视图,最后展现给用户。
然后这边有一个比较有意思的功能,有一个 DeepFlow 同步模块,因为 DeepFlow 的数据都存在 Clickhouse 里,它会定期同步应用到应用的拓扑关系,并导到队列的一个 T+1 作业里面去,会生成一个静态拓扑图。
静态拓扑图这个功能,大致用于观察应用到应用之间实时的状态,它的主要作用是解答一下应用在系统架构层面上有什么样的拓扑关系。这个时候我们会导到 T+1 的作业,导入到 Doris 里面去暴露给用户,这样用户就可以看到自己应用上下连着哪些应用,或者是整个集团下面有哪些应用,以一个全局的视角。这个前面可能也还有个 Redis 缓存,对我们经常查的一些应用进行加速,然后下面有一个应用队列,我们之前也说了 Hera 是以应用为核心,所以它会定期从 Clickhouse 里把我们打标应用的元信息同步到 ES 里面去,这样在我们 Hera 平台里面搜索的时候,用户就可以看到,即使没有接入探针的应用,它也可以在 Hera 平台里面搜索出来。当然我们可以通过过滤器把它过滤掉。
DeepFlow 在小米的落地
后说说我们遇到的挑战和解法。首先这个是我们核心的目标,尽可能在不插码的前提下,让更多的用户体验到 Hera 的完整功能。可能不是 100%,但是 80% 到 90% 是一个目标,这个目标的实现过程中我们遇到很多挑战,DeepFlow 社区的专业团队的支持很多,都高效解决了,
这边主要是两个挑战,一个是小米重度依赖 cBPF 能力,另一个就是拓扑图隐藏 LVS。
首先就是依赖于 cBPF 能力,因为小米的内核版本比较老,很多机器装不了 eBPF 的探针,所以我们使用了 cBPF 采集,但 cPPF 采集在社区最开始的一个版本里不支持进程粒度的拓扑关系。我举个例子,左边和右边各一个主机A、B,小米内部的应用是要混部的,因为要提高主机的资源利用率,我们在左边主机 A 里面混部 A 和 B 两个应用,右边主机 B 混部 C 和 D 两个应用,这时候我们通过 DeepFlow 的 cBPF 能力检测到 HTTP 5XX 的 status code ,那应用肯定是有问题的,但这个时候我们定位不到是哪个应用到哪个应用的问题,比如实际上是应用 A 到应用 D 有异常,应用 B 到应用 C 没有异常。业务去排查问题就会一脸懵,到底是哪个有问题?这也不能满足我们以应用为中心的诉求,这些问题在 eBPF 里面没有遇到,但在 cBPF 里面遇到过。
我们做了一个解法,当时跟社区提了一个 FR,这个应该是社区的第一个 FR,跟 DeepFlow 共同制定了一个方案,我们会定期同步 Socket 与 Process 的关联关系,DeepFlow 给的数据是一个 Flow,Flow 其实是个五元组,包含目的端的 Port IP 和我们的源端的 Port IP,我们通过流的五元组定义一个 Socket,然后 Socket 在 Linux 下可以跟 Process 进行关联,把流和应用 ID 关联在一起,后面我们根据流量的五元组信息锁定 Socket,从而锁定应用进程。
最后是我们前面提到的 DeepFlow 插件,我们会从发布系统中获取进程与应用关联,这样我们就可以把五元组,也就是 Flow 信息跟我们的应用进行关联,从而推算出比较有用的应用信息。表格里的是我们后来通过 FR 加入的功能,左边是我们的源应用,右边是我们的目的应用,取代了之前 host IP 到 host IP 这样的一个拓扑关系图,这样就可以回答用户应用到应用的关联了。
然后其他的优化做了哪些?首先是 Process 过滤,在 Linux 里面进程还是比较多的,有一些无效的噪音(编者按:非业务应用进程),比如说脚本或者内核进程,这些就是无效的 Process。我们通过正则对一些无效的噪音进行过滤,降低了我们的上报频率,减少开销。后面是子进程打标签,之前说过我们是通过流关联到进程,从而关联到应用。但很多架构,比如说 python 多进程架构,或者像 nginx,它不是单进程架构,它是个多进程架构,有父进程还有子进程,所以有时候关联的是子进程,但并不是真正要关联的应用。因为应用的标签是给父进程打元数据,记录的是应用元数据到父进程的 PID,这个时候流的子进程信息是没有用的。所以我们也做了树状分析,我们通过父进程不断 fork 子进程,然后我们给子进程打上和父进程同样的应用标签,这样就不会让用户产生疑问。
后面还有一个问题,经常创建短连接的应用,Socket 的创建数量会比较多,会导致我们在内存中的 Process 到 Socket 的映射表基数膨胀,最后导致了 OOM,这里面我们做了一些优化,通过过滤小于 10 秒的短连接,我们把基数进行控制,因为大部分在我们集团内部的一些框架,比如说 GRPC ,或者是 Dubbo 也好,或者是 HTTP 也好,它和 MySQL 和 Redis 都是基于连接池的,所以一般来说大部分都是长连接,只有极少数是短连接。所以过滤掉短连接其实对黄金指标的监控影响也不是特别大。
最后一个是比较难理解的,在 DeepFlow 的 Flow 中,有客户端到服务端的概念,到底哪个 IP 是客户端,或者哪个应用是客户端?这个方向比较难判,之前出现过乱序的现象,因为在网络层其实没有客户端、服务端这个概念,DeepFlow 解法是通过抓 SYN 报文,判断是谁先发起握手的,先发起握手的就更像是客户端。但是在我们部署 Agent 的时候,可能这个连接它已经建立很久,它可能是个长连接,所以我们会捕获不到 SYN 报文。这个时候我们通过一些动态的算法,分析 TCP 里面流量的一些行为,然后不断地给这个方向进行投票,如果它得分比较低的时候,我们就把这个错误的方向给过滤掉了,我们只过滤那种得分比较高的,比如满分是 255 分,我们只过滤 200 分以上的流量。这样的话它在概率上就是接近 100% 的正确率。
挑战二是这个是拓扑图如何隐藏 LVS 。我们还是从应用到应用的监控来分析,不同的应用之间可能存在 LB,就是 LVS,然后 LVS 大家也知道它有个特点,它有个 VIP。我们这边看的就是 Client 连接中间 LVS 的时候,连接的是个VIP,然后 LVS 出来的时候又有一个 VIP',甚至可能还有多个不同的 VIP',因为它可能有多网卡,最后到我们的 Server 端。如果是正常的情况下,我们用户是其实是想知道 Client 到 Server,也就是应用 A 到应用 B 的调用关系的,但是因为有这个 LVS 的情况,导致我们整个的链路中断了,形成这样的效应,拓扑图上面全都是我们的客户端,然后下面全都是 VIP,我们的服务端就看不到了,因为中间链路断开了。因为是从客户端为视角开始做遍历的,怎么看不到客户端 —— 服务端的拓扑图了,这个对用户造成非常大的干扰,生成大量无意义的无效的拓扑信息。
而解法的话,我们通过两个方法解决,首先我们通过 TOA 获取真实的客户端 IP,中间这种服务端通过流量分析,抓的就是 VIP',也就是 LVS 出网卡的 IP 到 RS 的流信息。但是我们如何穿透 LVS?其实我们可以通过这个技术,在我们集团内部的 LVS 模块,当然也不仅是我们集团内部,很多公有云也是一样的,它会在发送 SYN package 的时候,或者第一次推 PSH 包的时候,把客户端的真实的 IP 和 Port 放到 TCP Option 里面去,可以从 TCP Option 里面解析它,来获取真实的客户端 IP 和真实客户端的 Port,这个就解了如何穿透 LVS 获取真实客户端 IP 的技术难题。还有一个技术难题,就是我们知道客户端的真实 IP,但是我们存在混部的现象,得到的是主机的 IP,不知道到底是哪个应用。
所以下面我们还做了另一个优化,我们通过 Server 获取 PID,同时通过这个方法推导出客户端上的 PID。我们知道客户端上的 PID 后,就自然知道客户端上的应用了。具体我们可以看最上面一条链路,我们如何锁定一个PID?比如在我们的服务端安装了一个 DeepFlow Agent,抓了一个流,这个流的 PID 其实是可以知道的,因为有五元组信息,我们可以锁定 Socket,然后同时锁定到 PID。但是我们顺着链路往回溯我们客户端的 PID 的时候,中间断开了,因为我们不知道 VIP 到 VIP' 的映射关系,在主机 A 有两个 Socket,所以我们不知道是哪个 Socket 发起这个连接,所以也不知道是哪个 PID。这个时候我们跟 DeepFlow 合作,做 LVS 平台注入的功能,把 LVS 中间拓扑信息注入到 DeepFlow 中间去,这样整个过程就可以串联在一起, DeepFlow 会自动地把这两个完全不相干的 Socket 通过拓扑关系把它关联在一起。
我们遇到很多挑战,通过技术的方式已经攻破了,但中间还遇到一些其他的挑战,目前还在解决的过程中。首先是 Dubbo 的线程池监控,我们做的 cBPF 是不侵入用户的进程的,它没办法通过 Uprobe 侵入到用户的进程中去。所以我们无法知道 Dubbo 线程池的监控,而 Dubbo 有一些线程池相关的都是应用级别的,所以我们不能到应用中去获取这些信息。后面第二个就是 OTel 探针, Span 的程序运行上下文缺失,OTel 探针在异常的时候,会把调用堆栈给打印出来,这个东西是要基于进程内部的方式,你得通过 eBPF 侵入到进程中去做,我们 cBPF 没有这个能力。
然后第三个就是业务日志,业务日志打印的东西都是高度自定义化的,这也需要我们侵入到业务进程中去做的,目前我们也没有办法去做。还有就是只对长连接进行标注,Socket 太多无法全部上报,我们前面也说了 Socket 如果全上报的话,那就太大了,内存就会爆掉,我们就只对长连接进行标注,这个也导致一部分的连接无法在系统中监控到,这个问题不大。我刚才也说了,大部分就是 95% 的应该都是长连接。最后还存在一个问题,对于部分大数据业务场景吞吐高的,会达到 Agent 的抓包上限,因为本身 cBPF 探针的原理其实和抓包原理是一样的,有个 buffer ,如果吞吐量比较高的话,抓包达到上限它就会丢包,这样就会导致结果不是特别准。
最后说一下当前的一个落地场景,我们第一个落地的产品是 Hera 的静态拓扑图,前面是我们说的是系统架构层面上,不是实时的,而是一个 T+1 的延时作业。我们主要是干什么用的?首先是回答各个部门之间有多少个应用。比如一级部门下面有二级部门,二级部门下面可能还有不同的业务线,业务线各个应用有多少个?我们要提供一个全景的视图,第二个是回答部门和部门之间存在多少个调用关系,这个调用关系的话,看部门之间,比如说不同业务线之间是不是有耦合现象。第三个就是回答应用之间的相互依赖关系,这个就是精确到之前说的部门维度,这时候就到服务应用的维度了,服务之间是不是存在依赖关系?然后第四个就是回答各个应用之间是否存在流量?这个是服务下线用的,经常会有人问我们这个服务能不能下了,我们把这个静态拓扑给他一看,说这个已经有三天没有流量了,然后他们就可以把这个服务给下掉了。
这边分两个(视图),一个是部门视图,一个是应用视图。如果你不断放大 scope,就是你想看的应用遍历层级,会发现应用越来越多,所以我们把它聚合成一个部门视图,这中间这几个圆,可以点击它展开成我们的应用视图,上面都是我们的二级部门,然后是我们不同的业务线,业务线就是最上面的蓝色和红色之间是有调用关系的,中间有一个是未接入 Hera 的应用,这个就是我们通过 ePPF 要通过 DeepFlow 探针自动采集到的,这时候我们就知道有多少个应用没有接入到 Hera ,可以推我们的业务方去把这些东西接探针。
右边是我们应用视角的链路拓扑,这个本身其实没有接 DeepFlow,之前我们是看了两个服务之间调用关系,接入 DeepFlow 后就我们会发现这几个服务他们还不是这么简单。它下面还会依赖 Redis,依赖 nacos,还有 ES 的能力,这样相当于把那些没有接入探针的应用,我们都把它给扫描出来了,就形成了一个全景图。
最后我们深知在这个 DeepFlow 的能力耕耘上面还是做得不够,我们还是希望它能做更多的事,这是我们大致的规划。首先是平台层面上,我们的目标目前是 80%(的可观测覆盖率),这个目标其实已经快达成了。然后容器平台是我们下个季度要去推的,这个应该推得很快,估计下个季度就可以把它全部覆盖了。然后三个核心维度的话我们主要去加强使用链路的功能,前提是一定要先接入 OTel 探针,然后我们通过加强网络 Span 的形式,把这个功能加强。
然后指标看板其实是可以完全覆盖的,用户在不接入 OTel 探针情况下,我们会给他一个体验版,最初的一个版本原型,可以看到大致的监控大盘,服务的接口的 SLA,都可以通过 Grafana 暴露出来。然后中间日志的话我们就先不去 touch 了,暂时搞不了。左边是我们的暴露给用户的核心能力,上面就是应用状态。
然后在这边有一个调用异常,也是我们加强的能力,这个不是覆盖,也是加强的,之前可以看到应用的调用异常,现在我们可以看到网络的调用异常。慢查询是可以完全覆盖的,因为 DeepFlow 天然支持 MySQL 的协议解析,你不需要接探针就可以看到慢查询。后面是一个服务大盘,我们说的 SLA 的一些黄金指标,就是 HTTP Dubbo 接口的 R.E.D.指标,我们也可以完全地展示给我们用户,然后报警这一块我们目前在调研,因为之前 DeepFlow 没有 Prometheus 的能力,我们整个报警是基于 Prometheus 去做的。所以我们在调研,可能这一块也可以做了。整个目标就是 Hera 不接入探针和接入探针,能覆盖到 90%。通过 DeepFlow 的 Agent,然后加 OTel 探针的能力覆盖到 90%,这是我们最终的目标。
这边有一个 Roadmap,这个 Roadmap 其实我们和 DeepFlow 团队合作应该是从今年年初或者去年年底开始的,我们前期有个预研和体验阶段,还存在两个团队之间沟通的阶段。这个我们从一、二、三月份,从最开始的预研到我们刚才说的遇到一些挑战,都把它解决了。
同时我们也推出一个静态拓扑图的产品功能,这个是我们到 3 月份为止实际上的功能试点,我们剩下的重心就要把它全量铺开,然后开始在全集团的主机上进行覆盖,我们会在容器平台上进行覆盖,所谓覆盖就是去部署探针,中间可能会涉及到机房的建设,集群的建设,资源的问题。这是我现在在做的事情,下周回去就开始做了。到8月中旬为止。我们把功能全部给铺开,最后我们产出一个完整的产品,给用户创造一个价值,给他一个真正的、DeepFlow 完整能力,我们暴露给用户这个完整产品的话,可能在 10 月份和 12 月份进行一次密集的迭代,把我们刚才要做的功能全都给迭代上去。
PPT获取地址
https://pan.baidu.com/s/1-M30trA5zYG8Zav96z19zw?pwd=0610
提取码: 0610
观看回放视频
https://www.bilibili.com/video/BV12u411h7bn/?vd_source=8217e32e9012f691b56ca71735c1a472
小米在调研方面值得学习
不愧是研发,分享的都是干货
通过这篇对小米的研发水平改观了不少