高洪涛——美国servicemesh服务商tetrate创始工程师。原华为软件开发云技术专家,对云原生产品有丰富的设计,研发与实施经验。对分布式数据库,容器调度,微服务,ServicMesh等技术有深入的了解。前当当网系统架构师,开源达人,曾参与Elastic-Job等知名开源项目。目前为Apache ShardingSphere和Apache SkyWalking核心贡献者,参与该开源项目在软件开发云的商业化进程。
随着多年微服务的发展,分布式追踪系统已经成为云原生技术栈中非常引人注目的一个领域。随着该技术的出现,你可以非常容易的去定位分布式系统中潜在的一些问题。在这篇文章之中,我会详细为大家介绍什么是分布式追踪系统,以及如何存储分布式追踪系统产生的数据。
我首先会沿着历史的脉络,介绍经典的大数据方案来解决分布式追踪系统的数据存储与分析的问题,而后会继续分析目前业界常用的混合方案来解决相关问题。最后面向未来,我将提出一种混合的一体化方案来解决此类问题。
什么是分布式追踪系统
在我们正式介绍分布式追踪系统之前,我们需要探究一下分布式对于整个业界到底意味着什么。我们可以下这样一个矛盾的结论:分布式把事情变得非常的简单,同时也把它变得很复杂。我们听过越来越多的案例,在使用分布式系统之后,虽然整个系统看起来结构清晰,路径明确,并带来了一定效率的提升。但越来越复杂的分布式结构增加了系统的复杂程度,同时给运维、管理、架构等等几乎所有方面带来了非常大的挑战。
我们倾向于将越来越多的组件引入到已经很复杂的分布式系统之中来解决以上这些问题。这些组件和管理它们的组件一起组成了更加复杂的分布式系统。这些系统最终会反噬我们,并给我们带来意想不到的问题。甚至于是非常重大的一些灾难。
如图是一个典型的电商类的系统。从这个结构图上看,这个系统东西向和南北向都是非常的复杂的。它由一个前端的系统来承接用户的访问,其中包含了移动端和浏览器过来的流量。这些流量通过API的网关到达了账户系统、库存系统和快递系统。前端系统同时与后端系统进行相连,后端系统由各个子域所组成,它们共同构成了一个非常复杂的网络拓扑结构。
在如此复杂的网络拓扑结构,我们不能单单以传统的运维方案去做监控,管理和观测。而是需要引入一定的现代技术,特别是跟踪技术,来将一条完整的调用链呈现到管理者和运维者面前。
通过跟踪技术,我们可以观测到系统的两个重要的指标,一个是请求失败,我们可以发现系统在哪个部分存在比较致命的问题,链路从何处断开的。另一个就是延迟。它是无处不在的,即使你花费巨大的代价,也不可以避免延迟。
现在,让我们深入到追踪系统的内部,观察追踪数据的数据结构。如图所示追踪系统所产生的是一些点,这些点可以代表一个时间片段,它的英文是Span。Span描述的就是一次调用所跨越的一个时间范围。
那么Span与Span之间是组成一个这样的树形的结构,这棵树反映的是服务之间的一个调用过程。而另一张图我们习惯于成为瀑布图,它更加能够反映Span之间的一个对应关系。
它与树型图最显著的区别是,瀑布图可以体现Span之间的隶属关系。我们看到其中 SpanA是一个父节点,其包含其他三个Span。而其他Span之间有一定的并行关系。我们从中可以看到SpanB与SpanC之间是并行的,与SpanD也是并行的。而SpanE与其他Span之间是个串行关系。这张图不仅可以告诉我们Span之间的对应关系,而且可以显示这次调用它到底是一种并行调用还是串行调用。
既然Span是跟踪系统的核心数据,同时这篇文章主要的目的是要探究如何去存储跟踪数据,那么探究如何去存储Span就是我们需要研究的必要课题。
让我们看看Span的一些具体结构,经典的Dapper论文所描述Span结构包括SpanId,父SpanId,还有它的Trace Id。而后是一组labels,这是一些key-value结构,类似于我们传统的数据表的一行数据,它与传统数据表不同点是:传统数据表的列是预定义的,而这种key-value结构是根据数据动态定义的,所以它的整个长度是任意的,这一点对存储来说是比较大的挑战。
另外Span中还要存储一些非结构化数据,所以它又带有NoSQL数据的特点。同时它又具有典型的时间维度的特征,而这又是典型的时间序列数据的特点。这就是跟踪数据的特点:一种混合的多模式结构。
经典的大数据存储方案
经典的跟踪系统存储其实就来自经典的跟踪系统论文:Dapper。这篇论文中还详细描述了Google所采用的一种跟踪系统的实现方案。这篇经典论文不仅描述了经典的以annotation为基础的数据结构,而且它同时还提出了使用BigTable来作为整个跟踪系统的存储底层。
既然提到了BigTable,那就让我们一起去探究目前BigTable的一些特性,看看为什么早期的跟踪系统采用这种存储结构。目前该产品已经云化了,我们可以很容易的去购买这个服务,去体验它的功能特性。
BigTable有三种比较主要的特性:
l 第一个它是NoSQL数据库。在上一节中我们提到,由于跟踪系统内部存在着大量的非结构数据,而这些数据来源于用户自定义。这里的用户其实包括两类,第一类就是跟踪系统的设计者,它会增加多种字段来构成数据的底层。再此之上就是跟踪系统的使用者,他们会根据自己的业务场景再添加另外一些动态的字段进来。故一个天然的NoSQL的非结构化数据库是对这种任意字段类型的数据结构是有益的。
l 第二个特性就是存储要支持高吞吐。在一个微服务场景之中,每一个子Span的粒度是代表一个服务内部的一个调用。但是这个调用可大可小,可以是对这个服务进程的调用,也可以是进程内部一个函数的调用。可以说,一次外部的业务调用可以产生海量的跟踪数据。这就是跟踪系统面临的典型挑战—数据放大。跟踪系统需要极大的带宽,同时对延迟也有非常敏感。综上,一个可以支持大数据的数据库对跟踪系统是非常有利的。
l 第三个特性性能线性增长。由于业务系统是逐步接入到跟踪系统之中的,就需要存储方案支持系统平滑的提高吞吐量和存储空间。不能因为新数据的接入,造成现有数据的写入和查询出现性能的剧烈下降。
以上就是BigTable作为第一代非常经典的分布式跟踪存储解决方案所提供的主要特性。
如图所示一个跟踪结构是如何进入到BigTable之中。第一个过程,跟踪系统会生成一个本地的日志文件,日志文件包括了所有的Span,而后由一个搜集器将这些数据拉取到一个与之最近的BigTable节点之中。而后由Dapper的写入器,将数据写入到 Big Table的每个Cell中。其中,每行代表一个Trace ,也就是一次调用产生的全部Span可以一次性提取出来。
我们都知道BigTable是个商用的云数据库。如果想自己去打造一个面向跟踪场景的经典存储方案,开源界也提供了有很多的选择,比如说Cassandra,HBase等。
但是经典的分布式跟踪系统非常大的问题就是投入产出比较低。因为我们知道跟踪系统属于二线系统,也是监控系统的一个延伸。虽然随着微服务的产生,此类系统的地位有了比较显著的提高,但其重要性依然低于一线生产系统。
那么采用这种经典的大数据方案的性价比是非常低的。你会投入很多的资源在跟踪系统中,但是产生的效果并不能够与你投入的资源相对称。甚至是说你投入的非常多,产生效果是非常差的。这个时候你会对它的可用性和实际作用产生深深的怀疑。
现代的混合方案
这部分让我们了解现代混合存储方案。相比于传统的大数据结构,现代混合存储结构更强调于性价比和易用性。目前主流的有两种典型的存储方案:
第一种就是关系型数据库,以MySQL为代表。
第二种就是搜索引擎,以ElasticSearch为主。
那么,首先让我们了解一下MySQL。当然这其中包括其他的一些关系型数据库。传统的关系型数据库是面向于查询优化的,所以它的写入性能相较于查询性能是较低的。故传统上它并不适合于做跟踪类的存储方案。
但是我们可以把关系数据库进行一些改造。这里有两个改造方面,第一点是使用一些Sharding中间件来增强MySQL吞吐量。如Apache ShardingSphere。
这样就满足了上文所提到的两个关键点:高的吞吐和性能线性。
高吞吐很容易理解,这是sharding的主要策略。那么性能线性如何理解呢?
一个Trace 内部的Span是有一定的关联关系的,但是Trace 和Trace 之间是相对于独立的。那么通过sharding策略,整体的数据会较为离散的。这就可以满足对性能线性增长的需求。因为我们知道影响sharding效果的一个最重要的原因就是关系的耦合。如果数据之间关系特别的紧密,那么你很难做到数据写入性能的线性增长。
最后,对于数据的任写入,我们可以通过预设冗余字段的方式来解决。当然任意数据并不能像大数据的存储方案一样可以无限写入任意数据。但这种预设方案在性能上反而有更大的优势。
刚才提到了两种增强关系数据结构的方案,那么我们为什么一定要选择这种关系数据库作为跟踪数据的存储方案呢?
第一点就是像这种数据库有大量的dba支持。所以我们很容易的将它的性能提到一个非常惊人的地步。甚至于有一些组织,比如说像TimeScale,就是利用关系数据库来做时序数据库的存储跟踪数据的。他们就是看中了这种关系数据库优秀的成熟度。
那么如果要用MySQL去存储关系数据,需要做额外哪些调整呢?
第一点,增强写入性能。最简单的方式是要增加buffer的大小。同时,对数据库Engine做一相关的优化。比如增加buffer pool的一个大小,然后我们需要对数据块的刷入策略进行一些调节。
第二点,增加数据的生命周期管理功能。因为一些老数据会出现随着时间的流逝而价值降低的现象。需要增加数据生命周期管理功能来释放磁盘空间。
第三点,分离流量。因为我们写入量是巨大的,但读取是相对少的。这与经典的关系数据库场景是非常不同的,我们需要把写入流量和读取流量进行分离,以免读取流量影响写入流量。
第二个常用的存储结构也是搜索引擎。以Elasticsearch为代表的搜索引擎对于日志搜集有比较好的支持,所以有相当一部分的跟踪系统都会采用这种搜索引擎来存储跟踪数据。那么跟踪数据本质上与log是非常相似的。因为log具有体量巨大,字段任意等跟踪数据的显著特点。它唯一与跟踪数据的区别是 log没有很强的关联性。故如Elasticsearch和Loki这类系统都可以满足存储跟踪数据的要求。
此类数据库具有两个相对优势的特性:
第一,支持大量的非结构数据存储。因为这种系统天生就是一个分布式数据库,它不像关系数据库需要一些中间件的加持。这种数据库天然可以存储大量的数据。而且他们对写入有特殊优化,这样就可以快速的存储数据。
第二,高效的数据分析。数据之间的关系可以很容易的在此类系统中进行分析。因为它动态产生索引结构,非常适合于这种交互式的跟踪数据分析场景。
如果你要使用Elasticsearch来存储跟踪数据。需要进行以下优化:
第一,需要实时的监控磁盘的使用情况。因为索引写到一定程度,Elastcsearch就会将一些索引转化为只读索引,这样的话会导致你的最新的高价值数据写不进去。
第二,由于你的写入量是非常大的,你要像关系数据库一样去增加它的Buffer,同时增加写入的队列的大小。
第三,Elasticsearch是分布式的数据库,它自带数据复制的功能。但是对于跟踪数据,数据复制往往是多余的。因为这是一个写多读少的一个场景,所以你不需要通过副本来提高读取性能。同时,跟踪数据本身的价值也而且随着时间流失而降低。故你也不需要对数据做高可用处理。综合以上原因,经典的优化方案都会关闭它的复制功能。
以上就是两种现代混合方案。之所以称为混合,就是当代的跟踪系统,如Apache SkyWalking,Zipkin等等都支持多种存储方案。用户必须根据自己的情况进行选择,且每个方案都各有利弊,而并没有一个一劳永逸的一体化解决方案。
面向未来的一体化方案
至此我们探究了什么是分布式跟踪系统,经典的跟踪系统数据存储的方案,以及现代这种混合的跟踪系统存储方案。我们会发现目前并没有一个非常完美的最佳实践来解决跟踪系统的存储问题。其主要原因就是并没有一个专用的跟踪系统存储的引擎,来帮助我们去同时解决那三个问题。
本文介绍的每种方案实际上只仅仅解决了部分的问题。传统的经典结构,貌似解决了所有的问题,但是其代价是非常高的。所以我们需要的一个最佳跟踪系统存储方案,除了典型的三个特点之外,还需要加上性价比这个非技术特性。只有高性价比的跟踪系统方案才能在生产实践中得到广泛的使用。
除了性价比之外,另一个附加特性也就是自我运维。跟踪系统本质是一个运维工具,它的存储系统如果需要运维人员花费更多的时间和精力来去管理和调优,那么必然会降低系统的使用率。因为专业的运维人员不希望特别关心工具自身的运维问题。但跟踪系统本身会产生大量的数据,造成它的维护难度并不亚于高流量的业务系统。所以一个典型的或完美的跟踪系统存储方案,要能够去自动识别和处理常见的运维问题,其最低限度是,保证系统能以一定的健康度来运行,而不至于完全的挂掉。
所以我们寄望存在一个从底层开始设计的面相跟踪场景的数据库。它应该从数据结构层到模型层完全按照跟踪系统的特点进行构建的,并符合我们本文描述的此类数据库的所有特点。很庆幸的是在我们这个时代有越来越多的独立的底层引擎所涌现出来,我们可以利用它们去构建这么一个数据库,而不需要完全从0开始。
同时由于RUM假说的出现,我们可以采用不同的数据库访问策略来实现跟踪这个特定领域的数据库。而这样一款兼备各种跟踪数据存储所需要特点的数据库其实也正在路上。
END
7月3-4日,高洪涛将作为特邀嘉宾携《面向云原生可观测性数据存储》演讲内容,出席2022K+全球软件研发行业创新峰会深圳站。带你了解主流可观测性数据存储方案的特点和使用案例,特别是可以了解到新一代云原生可观测性数据库BanyanDB是如何使用创新方案解决该领域主要问题的。
K+全球软件研发行业创新峰会旨在发现全球软件研发领域的创新工程和杰出团队,整合国际前沿技术实践,构建行业案例研究智库,通过软件研发技术的创新融合,帮助中国企业成功进行数字化转型与升级。本届峰会秉承“技术创新无边界”的主题,围绕工程创新、管理创新、产品创新、架构创新、效能创新、工具和平台创新六大创新方向设立分论坛,并融合十几个热门技术专题,分享最新的技术创新和实践案例,为大家带来一场前所未有的技术盛宴。