构建统一的云原生应用可观测性数据平台
2022-04-11本文为云杉网络原力释放 - 云原生可观测性分享会
第三期直播实录。回看链接,PPT 下载。
特别说明:当前 Blog 中的 MetaFlow
已经改名为 DeepFlow
;MultistageCodec
已经改名为 SmartEncoding
。
DBAPlus社群的朋友们,还有云杉直播间的朋友们大家好。我是云杉网络向阳,在公司负责DeepFlow的产品研发。伴随着我们客户的业务逐步云化,DeepFlow从最初的云网监控逐步走向了今天的云原生应用可观测性平台,基于我们在混合云场景下的一些实践,今天给大家分享一下在构建统一的云原生应用可观测性数据平台中的一些思考和经验。
云原生可观测分享会
今天我的分享分为四部分,第一部分介绍可观测性数据平台建设遇到的一些挑战,引出两个主要痛点。第二部分介绍我们如何用AutoTagging技术解决数据孤岛的问题,实现任意观测数据之间的关联,释放数据的切分、下钻查询能力。
第三部分介绍我们如何用MultistageCodec降低资源开销,可以将数仓(例如我们用到的ClickHouse)的性能提升10倍。最后再来总结一下如果我们得到的一些在组织内部推进建设一个统一数据平台的落地思路,以及DeepFlow的一些落地案例。
0x0:可观测性数据平台的挑战
统一的可观测平台数据
我们首先来看一下可观测性数据平台的要素。Peter Bourgon有个很好的总结,从数据类型的角度分为Metrics、Tracing、Logging。今天这个总结也算是业内家喻户晓了。我们也看到了有一批开源生态围绕这这些数据在为可观测性方案添砖加瓦。
其实这三个类型的数据,也将江湖上的方案划分为了三个派别:指标优先、追踪优先、日志优先。这使得每个开源组件能在自己擅长的领域内做到最好,但也导致了三类数据之间沟壑明显,无法关联。
挑战:数据孤岛、资源开销大
这里也就引出了我们今天要讲的两个主要内容:数据孤岛的问题、资源开销的问题。三类数据无法关联、无法流通,使用困难。追踪和日志数据体量很大,资源开销难以承受,经常需要削足适履,做采样,抹掉高基数字段等。
0x1:解决数据孤岛:AutoTagging
那我接下来分享的内容就是我们的AutoTagging技术了,它解决了数据孤岛的问题,而且给我们提供了强大的数据切分、下钻能力。
OpenTelemetry方法
先看看他山之石,开源社区如火如荼的OpenTelemetry。其实我刚才也讲到了,可观测性方案是分门派、分信仰的。
例如刚才王赟老师讲到的SkyWalking,以及这里的OpenTelemetry大侠就都来自‘追踪派’,它以Tracing为核心维护了一个Context,使得Metrics、Log生成时都能打上同样的Tag以及TraceID、SpanID。
OpenTelemetry方法1
我们来看这张图,Metrics通过Examplars关联至Trace,而Log和Trace之间也通过TraceID、SpanID进行关联,核心是TraceID,辅助是Context中的Tag。
但这样的关联并不完善,从PPT标记的位置也可以看出,这样的关联仅限于Tracing与其他两种数据的交叠部分。有一些常见的问题无法回答,我们来看一下以下几个场景。
数据打通并不简单
首先看看Trace和“非Request Scope”的Metrics如何关联?这个图把指标分为了两种:请求相关的、非请求相关的。前者例如某个请求的应用时延、网络性能,后者例如某个实例的CPU、内存、GC、内部数据结构,还包括实例所在虚拟机、宿主机的性能指标。
这两部分数据不能通过TraceID关联,但我们可能要回答一些问题,例如响应某个请求的实例在某个时间的指标曲线是怎样的。例如从一个Span能否跳转到指标曲线。
数据打通并不简单1
再来看看第二个场景,Metrics内部的关联。指标可能来自不同的数据源,这些数据源打着不同的Tag,并不能做到无缝关联。例如某个服务的Pod的请求速率、IO速率、网络流量速率分别是多少,再比如Pod所在的虚拟机或KVM宿主机的CPU、内存是多少。
举个例子就是说,某个Service的Pod里面有可能有一些QPS来自SkyWalking,IOPS来自Telegraph,他们能关联起来吗?从纵向来讲,对某个Pod所在的虚机运行的KVM宿主机上,我们关不关心他的CPU和内存呢?同样也是关心的,所以这些也是靠我们的Tap去关联起来的。
数据打通并不简单2
继续看看第三个场景,Metrics和非Aggregatable的日志之间如何关联,例如我们在看到QPS下降时,能否快速关联到进程相关的Pod、虚拟机、KVM日志。这个时候是某一个进程的QPS降低了,或者某个服务它的QPS降低了,那它和进程、所在的服务器的VM,以及Note它的一些日志是不是有什么关系?我们也希望能够去快速的关联起来。
数据打通并不简单3
第四个场景,日志之间如何关联?日志一般携带主机名、进程名信息。Loki做的比较好,能自动将K8s中的日志关联上Pod、Namespace、Node等标签,但也依然难回答一些跨进程的问题。例如应用日志中的错误与Ingress日志有关联吗?但是如果说我们所有的数据都能打上一个完整的标签,这个应该是更好的,将日志的整个检索带上了一个新的层面。
数据打通并不简单4
继续看第五个场景,非Request scope的Log与Trace之间如何关联?例如系统日志异常与Request时延增大是否有关联,能否快速跳转?那其实我们通常会有这样的系统日志的一个异常和request的时延增大,这是不是有问题?某一个request的时延增大,那它所在的workload,它所在的VM是不是有异常?这些问题我们都要回答,在后面会说。
数据打通并不简单
最后我们看看Trace之间的关联的关联。比如一个简单的场景,访问一个服务的耗时究竟由哪哪些部分组成?瓶颈是在应用程序,还是在中间链路上?如果是在链路上,那么哪部分的耗时最大?Sidecar、Node、KVM、NFV网关等。因为它不同于一个传统的网络环境,两个机器之间、两个网线插到交换机上,只要通了就完事了。我们更多的是去关注代码,在云原生场景下,我们要去做到全链路的追踪,上述路径也是需要我们去关注的。同样,后面我会详细解答,我们怎么把这些路径上请求的日志和Trace关联上的。
我们需要那些tag
回顾一下刚才的这些场景,我们可以发现其实是缺少了标签使得不同数据源之间的数据无法关联。那我们到底需要哪些标签呢?看看OpenTelemetry是怎么看待这个问题的。OTel中的标签叫做属性(attribute),并且将标签分为静态的、表示资源的属性,和动态的、表示请求的属性。
资源属性我们看到有描述服务的,例如Service Name等;描述代码的,例如依赖库版本;描述实例的,例如区域等。请求属性有和请求协议相关的属性,以及和业务相关的属性。其实和请求相关的也有静态属性,例如HTTP Path关联的API名称。属性还是挺多的,但在一个混合云的场景下,解决我们刚才列出来的问题还不够。
混合云环境
我们看一下混合云环境下的资源属性还有哪些。应用程序运行在POD,伴随着一些Sidecar;POD运行在虚拟机中,虚拟机运行在宿主机上。两个应用进程之间通信可能还需要经过中间的LB、NAT网关等网络服务。从虚拟机的角度,就能涉及到十多个标签。
云原生属性
那么对于云原生应用呢,还有很多丰富的服务相关的标签。比如K8s中的集群、节点、命名空间、服务、Ingress、Deployment、POD。再比如K8s中大量的自定义Label,包括版本version、环境env、组、owner;以及与CI/CD相关的stage、commitId、deployId等。这里我列出来的知识自定义标签中的很小一部分。在DeepFlow的典型客户中,两个微服务通信涉及到的标签可能多达上百个。
AutoTagging
说了这么多以后,引出我们今天的第一个主角:AutoTagging。刚才可以看到,我们需要完成数据的关联、数据的切分、数据的下钻,需要依赖上百个标签。这些标签都期待开发者在代码中注入是不现实的,会带来沉重的开发负担。
其实这些标签已经存在于某个地方了,奔着一个信息只需要一个源的偷懒原则,开发者当然希望这些分散在各处的标签能自动追加到所有的观测数据中。“偷懒”是进步的原动力,DeepFlow产品发展了数年,已经能支持市面上常见的公有云、私有云、容器,自动同步其中的资源和服务标签,并自动与观测数据关联起来。
目前DeepFlow支持的数据围绕Trace展开,每个请求的详细日志、请求聚合后的RED指标,覆盖网络和应用。对于一个请求都有客户端和服务端。我们会自动的将同步到的标签注入请求日志和指标数据中。自动注入在混合云场景下也会碰到一些挑战,在一个多租户、多VPC的环境中,为所有请求标注正确的客户端和服务端信息需要考虑到VPC、隧道ID、对等连接、路由等信息,这需要对SDN网络有深入的理解,这部分是DeepFlow擅长的。
但如果我们仅考虑一个单租户的环境,仅仅只是将标签关联至请求的某一端会简单很多,只需要考虑利用IP地址、hostname做映射查找即可。
AutoTagging1
这里也给大家看一张我们产品的效果图,左下角是我们通过BPF获取到的流量、eBPF获取到的系统调用自动绘制的服务调用拓扑,当然也包括完整的RED指标。
我们可以按不同的标签聚合生成访问拓扑,例如服务、容器POD、容器节点、子网等。点击每个节点我们能看到它的标签列表,以及利用这些标签绘制的知识图谱。利用这些标签我们可以快速在指标、追踪、流日志之间无缝跳转,也可以在搜索条件中追加这些标签对数据进行进一步的切分和下钻。
AutoTagging2
再来看这张图,我们应该能回答刚才提出的一些列数据关联、数据切分、数据下钻的问题了。我们主要的技术展示了虽然只有两页,但应该也能感受到我们是用什么样的方法去做的这件事。我们主要通过控制器和云API、K8S apiserve,以及现在推进的服务注册中心进行信息的同步,将我们所有提到的资源的标签、容器服务的标签、自定义的标签,乃至于像服务注册中心中某一个API打了一个标签。
以及我们其实主要是通过eBPF的方式拿到的追踪数据,如果在HTTP的header里面,或者在任何其他的应用协议头部里面注入的字段,这些标签我们都能拿到,且能实现什么样的效果呢,就是我刚才提到的6根红线,或者比这更多的数据关联,我们是能够无缝实现的。这只是数据关联,其实它背后还有更多的能力,就是这每一份数据都有更好的切分和下钻能力。
AutoTagging3
当我们去做到了AutoTagging,还是会带来一个问题,标签太多了,数据存储压力上来了。有什么好的办法对冲吗?我们不能因为自动标签的注入默认带来资源消耗低飙升。刚才也说到了,通常两个服务之间的通信可能会有上百个标签注入进来,如果把这上百个标签都注入进来,后面将带来十万多个数据,这个资源消耗是非常可怕的。所以,单单只做自动化标签多注入只解决了一类问题,而且还会引出一些别的问题,就是资源消耗的飙升。还好我们是有解决方案的,下面要讲的这个解决方案也是我们在实践过程中一步一步去沉淀出来的。下面我分享下DeepFlow中的MultistageCodec编码技术。
0x2:降低资源开销:MultistageCodec
MultistageCodec
这是一个DeepFlow中数据从采集到存储到查询的流程。我们的Agent在采集到数据时,通常是从流量或eBPF系统调用中获取的请求数据,原始数据几乎不含有Tag,除了开发者注入到请求Header中的标签以外。我们的Controller会和云API、K8s apiserver进行同步,获取所有资源、服务、自定义标签,并将其编码后下发给Agent和Ingester。
Agent传输、Ingester存储都使用编码后的整形标签,最终经过Querier的查询计算还原为字符串标签。我们的存储使用ClickHouse,这也使得我们能告别高基数的烦恼,“时间线”数量不再是我们需要考虑的一个问题。在这个流程中,实际上编解码是分多个阶段进行的。下面我们依次来看一下。
采集时的编码
第一个阶段是采集时期的编码。Controller并不会将所有的标签下发给Agent。它只会将标签的基下发。这样Agent只需要为数据追加很少的标签即可。在混合云场景下,为了标识资源我们可以用VPC ID作为基,它能和IP地址联合决定客户端、服务端对应的实例和服务。今天我们分享的内容主要是为资源和服务打标记,实际上我们还能给API自动打标签,比如根据API路径匹配关联URL,此时就还需要下发API的标签。
不管怎么说,我们希望Agent需要做的工作尽量上,这样我们可以最大限度的降低采集侧的CPU、内存消耗,以及传输数据的带宽消耗。我们在生产环境中发现有些K8s的标签会非常长,key和value高达上百个字节。可以想象如果我们将上百个标签注入每个请求传输到后端,消耗的带宽会非常可观。
存储时的编码
第二个阶段是存储时期的编码。同样Controller会将标签编码为整形后发给Ingester。Ingester在收到Agent发过来的数据后,会进行一轮Tag的Enrich,基于Agent注入的标签基,扩展为更为丰富的标签集合。但需要注意的是,我们并不需要存储所有的标签。
标签的存储是为了方便检索和聚合,我们只需要保证每个切分粒度上都有标签存在即可。举例来讲我们可以将Region、AZ、Host、VM、Node、Namespace、Service、Deployment、POD等固定的、系统级别的标签存储即可,而其他的自定义的标签一般是依附在这些系统级别标签之上的,存在一一对应的关系。
另外,自定义标签动态性高,且无法预知Schema,也不适合全部存储。根据我们的实践,一般每一个请求涉及到的系统级别的标签在40个左右,自定义标签在60个左右。通过只存储系统标签,我们能将压力进一步降低。
查询时的编码
第三个阶段是查询,我们怎么能通过易于使用的方式,支持通过字符串查询、聚合,并且也支持没有存储的自定义标签的查询和聚合。这里我们依赖ClickHouse的字典能力。举个例子,我们可以创建一个Pod名称和ID对应关系的字典表,这个表可以通过文件、MySQL同步到CK中,也可以直接在CK中创建。
在一个CK集群中,让每个节点都从统一的MySQL同步字典是个好办法,这样每个节点上就都会有一个字典副本。如果观测数据中存储的是pod_id,那么我们仅需要在查询中使用dictGet函数就能实现名称的翻译。如果数据库不适用CK,也可以用Join来实现。因为字典表通常都比较小,放在右侧Join对性能的影响也非常小。直接用CK字典会比Join有更好的性能。再比如根据K8s label(自定义标签)进行过滤或分组的场景,也可利用类似的dictGet来进行转换。
采集、存储、查询
我们再来回顾一下这三级编解码,可以想象得到它能为我们节省大量的资源消耗,性能提升应该十分可观。一方面采集侧CPU、内存可以降低,传输带宽可以降低,最主要的还是后端存储开销的降低。我们在谈论可观测性时经常会谈到采样、避免高基数等。ClickHouse采用稀疏索引,很好的避免了高基数问题。我们在此之上的多级编解码又能将存储开销显著降低,而且由于查询阶段扫描的数据量变小了,经常能获得更好的查询性能。
性能提升
那我们再来看看这个机制的实际效果。我们首先对比一下三种存储方式:直接存索引(即我们采用的方式)、将Tag存为LowCard字段(即CK在存储前将字符串转换为整数,相当于CK做了额外的Tag索引)、直接存字符串。我们生成了一批长度为16字节的字符串标签,这个长度其实比一般生产环境中的标签要短得多。
我们看到如果直接存标签,磁盘和CPU的开销都非常大(假设直接存索引的开销为1),而且磁盘开销会随着标签基数的上涨有增长。那么如果我们在存储期做一个边界码呢,中间的结果可以看到相比直接存字符串他能显著降低磁盘消耗,且能够将CPU消耗降低至1/2。
最后看看我们的MultistageCodec,相比于其他两种方案都能做到一个数量级的性能提升,效果立竿见影。如果再考虑到还有60%的自定义标签是我们在查询期翻译的,那优化的幅度更大。通常这些自定义标签的长度也会更长。
生产环境数据
下面我们来看生产环境的实际表现。一句话来说的话,我们在Server端的资源消耗不到被监控对象的1%。这个环境中我们监控了600个16C的容器节点,上面大概运行了8000个POD,右边的图可以看到每秒总的写入速率能到百万行,每行数据都是一个宽表,大概是100到150列,这里面包含我们写入的系统级标签和关联的指标数据、请求属性等。这个环境我们总共用了6个16C的虚拟机来承载,但他们的负载之和不到60,还有很大余量。
0x3:统一数据平台的落地思路及案例
好了,技术细节到这里,我们再来看看一些落地实践。
落地及推广
首先第一个问题是分享一下如何在组织中推广这样的机制。我们解决的是开发者的问题,自动的向观测数据中注入丰富的标签,帮助开发者解决数据孤岛、数据切分、数据下钻的问题。但我们并不产生标签,只是标签的搬运工。其实这些标签是广泛存在的,就像原力一样,只不过现在开发者们需要重复的向观测数据中注入。
如果开发者在服务上线时利用CICD向K8s中注入label,在服务注册时向服务注册中心中注入服务信息,在发起和处理请求时在HTTP等标准协议头中注入希望被观测的标签,这些标准化的动作将会使得可观测性更为轻松。今天我们主要展示的是注入上线期能决定的标签,其实这套框架也可以扩展到服务注册、请求处理过程中。我们希望引导开发团队使用这样的标准化注入方式,降低消耗在观测数据产生过程的编码时间。
27.jpg
让观测更自动,让开发者更自由!
刚才我们介绍的AutoTagging和MultistageCodec是DeepFlow中的两项技术,我们希望这样的技术让观测更自动,让开发者更自由。我们应该有一个自动化的机制来尽量减少标签的注入,来实现一个有丰富维度的Metrics、Tracing、Logging的关联、切分、下钻。这也是DeepFlow的信仰,希望让观测更加自动,来减少开发者的一些工作负担。希望能够让开发者更自由的去选择使用的框架、使用的观测性方案。
零侵扰
上面这张图是DeepFlow作为一个可观测性平台的整体方案。目前我们主要专注在Tracing上,能以零侵入的方式利用eBPF、BPF获取全局的应用流日志、网络流日志;并从这些日志中聚合出指标,绘制流量拓扑。整个DeepFlow主要由三个组件组成:采集器、数据节点、控制器。
采集器可运行在企业混合云环境中,包括公有云、私有云工作负载,NFV网关,以及各种应用Stack环境下。通过eBPF,我们能获取到所有的请求,并在本地处理后以极低的带宽消耗发送至后端的数据节点。数据节点可水平扩展,并可通过对象存储转储能数据。控制器支持对接20多个主流的公有云和私有云平台,以及容器发行版,同步刚才我们谈论的标签信息。
目前DeepFlow的数据因为有丰富的资源和TraceID、SpanID标签,也支持和其他追踪、日志、指标数据进行关联。实际上我们的产品也在不断迭代,未来这些监控体系也将以数据源的方式能直接注入到DeepFlow中,使得能享受到我们的自动标签和高性能编码技术,构建统一的云原生应用可观测性平台。
落地案例
这是我们目前在金融行业的一些混合云落地案例,就不展开说了,同时我们的产品也和主流云厂商有紧密的合作,这些云上的头部客户也是我们的客户。
联系我们
好了,今天的分享就是这些。左边是我的企业微信号,欢迎大家加我。刚才我所分享的所有技术,以及DeepFlow核心的其他技术都将会在4月24号正式宣布开源,届时欢迎大家来参加我们的直播介绍。
MetaFlow是一个通用的可观测性平台,依靠eBPF技术实现自动的分布式链路追踪、自动的标签标注,而且开放了数据源、存储、GUI的接口方便社区扩展,欢迎大家关注。另外DeepFlow不断发展过程中,我们也在尝试提供SaaS以服务于公有云客户,右边是我们SaaS服务的二维码,目前在测试阶段,完全免费试用,欢迎大家试用并多提意见。