今日总结 – 终极指南:企业级云原生 PaaS 平台日志分析架构全面解析

早些时候 Erda Show 针对微服务监控、日志等内容做了专场分享,很多同学听完后意犹未尽,想了解更多关于日志分析的内容。Erda 团队做日志分析也有一段时间了,所以这次打算和大家详细分享一下我们在做的一些事情,希望对大家有所帮助。

日志分析平台其实是 Erda 微服务治理子平台下面的一个功能模块,那么今天我将从三个方面来展开分享:

  • 日志分析平台出现的必要性;
  • 日志分析平台架构设计;
  • Erda 目前是怎么做的、做了哪些工作以及未来的发展方向。

日志分析平台的必要性

“微服务”这一概念大概在 2013 年出现,从这一概念初期到现在,大部分应用的业务场景皆是分布式、容器化的部署架构,或者至少是多服务架构,每个服务基本上是非单点的,并且会做单服务多实例的高可用部署。

在这种场景下,我们需要重点解决关于日志的几个问题。

需要解决的问题

1. 接口报错了,如何在应用的多个容器中快速的找到详细的异常日志?

第一个要解决的问题是关于异常日志的定位效率问题。比如,前端在请求某个页面,接口报错了,随后反馈给开发人员,常规的接口报错通常不会直接给用户暴露特别详细的异常信息,只会有一个状态或是简要的错误概述,这时需要开发者通过日志找到具体的异常信息(比如堆栈等)。

一般来说,通过接口路径我们可以定位是哪个服务的报错,但进一步讲,我们如何确定是这个服务下的哪个实例的报错呢?如果说我们采用这种比较原始的方式,可能需要开发者分别查看每个实例(容器)的日志,这样会直接对开发效率产生影响。

2. 如何方便的查看已经宕机的应用容器的日志?

另外一个需要解决的问题是日志存储的持久性问题。比如说在 K8s 平台下,某个应用服务的某个 pod 挂掉了被重新调度到了其他节点,或者本地存储的容器日志由于时间的滚动而滚动没了,这时如果我们想去回头看一下之前的日志,在机器上已经不太容易找到了。

3. 如何能及时的发现某个应用容器发生了异常?

前两个问题属于被动型的需求,也就是说前端业务上已经暴露出一些问题,然后我们去回溯、查找一些日志的详细记录的需求。因为是用户反馈,这个流程链上的故障处理时间是相对较长的,那么应该如何缩短故障处理时间?

很自然我们会想到主动告警,在还没有大面积前端接口被大量用户发现前,后端出现异常时,系统能够更及时的进行告警,并通知相关人员及时处理,减少故障时间。这时我们就非常需要一个系统可以持续监听所有容器的日志,协助开发者发现其中的异常并主动告警。

如果说没有日志分析平台,其实以上三个问题并不是不能解决,但是会极大程度的影响效率。那么假如有了这样的日志分析平台,由它来提供集中式查询、持久化存储以及主动告警等功能,我们可以快速且高效的解决这三个问题。

日志分析平台能提供什么

说到日志分析平台的必要性,我们务必要了解一下它能为我们提供什么样的服务,下面我们就来详细看一下:

1. 集中式、一站式查询

在查询方面,日志分析平台应该是集中式、一站式的查询,不再需要登录不同机器或者容器去低效地手动查看日志,而只需要在一个统一的页面上输入一些查询语句,就能轻松查询所有容器的日志了。

2. 持久化,历史可追溯

在存储方面,可以给日志分析平台配备有预期的专门存储配额,以便能够更好地应对宕机、升级、调度等导致日志跨节点的情况,保持查询历史日志时的简单性。

3. 智能化,主动发现问题

智能化告警通常也是一个必要功能,这里的智能化有两层意思:

你可以主动配置一些规则,比如说根据代码或已经发生的一些异常日志,可以知道特定异常是什么样子,随后配一个规则,系统就会持续对输入的日志做一些规则检测,如果发现匹配项,就会进一步通过你提前配置的告警渠道,通知到具体的人;
自动发现“异常”,其实有点类似目前的机器学习、深度学习,也就是说,即使你没有配置任何规则,但是系统可以通过对日志流的监听和学习,去发现异常的日志,然后通知你去关注,这是更智能化的一些东西。

日志分析平台架构设计

我们已经知道,日志分析平台可以给我们带来便利及效率的提升,那么如果我们想实现这样一个平台,需要如何进行架构设计呢?

想要做架构设计,首先要了解业务场景和需求,然后结合被处理数据的特点,才能够推断平台架构设计应该具有哪些能力。之后我们再根据这些能力去寻找、设计相匹配的方案,并在这些方案中挑选真正可落地的去执行。

数据特点

1. 时序数据

我们知道日志属于时序数据,只新增、不删除。它有几个字段比较关键:timestamp,tags,fields

  • timestamp:时间字段对时序型数据是用来进行比较和关键的字段;
  • tags:tags 代表一组字段,通常对于时序数据来讲,作为标签类型的字段一般都是可以搜索的,也就是这些字段需要建立索引,如:服务名、容器名、容器 IP 等;
  • fields:fields 也代表一组字段,这些字段相对于 tags 的不同在于,fields 字段是通常存储那些不需要搜索的内容,比如:假如对于具体的日志内容你不打算去搜索,就可以用 fields 类型字段存储。

日志时序数据的特点提示我们,可以考虑使用时序数据库来存储日志,比如 cassandra。

2. 时效性强

对于日志数据来讲,我们一般只关心一段时间的数据,对于很早之前的数据,比如一个月、两个月之前,甚至半年之前的数据,我们基本上是不会去关心的。因为一般有故障的时候,我们可能才需要去看一下具体的日志信息,而出现故障时不大可能会拖到很久之后才去解决和复盘这个问题。

3. 数据量大

数据量大有两个含义:一是说数据的单条日志可能比较大,比如像 Java 应用的一个异常堆栈,尤其那种 Caused by 嵌套了好几层的,可能单条日志就会有几百行;另外一个是说,日志的条数多,随着业务和应用的增多,加上某些应用还可能会开启 DEBUG 级别的日志,整体的日志量也会比较大,而且可能出现短时的峰值。

以上是日志数据的特点,然后我们对从我们日志分析平台这个角度来看看,我们对系统有什么需求。

业务需求特点

1. 查询速度快,秒级响应

首先,我们希望它能够快速查询,输入查询关键字,就能够秒级响应查询结果。

2. 时间段范围查询

通常,查询会按照一个明确的时间范围操作,这有一个好处:后端存储的选择会更多一些。

3. 高基数值点查询

什么是高基数值呢?像用户 IP、Trace ID 这类数据,几乎每个用户请求的值都不一样,这就属于高基数。关于这类数据的查询也是一个强需求,比如前端 web 接口报错,而响应里加了 Trace ID 这样的字段,此时就可以通过 Trace ID 字段去查看整个过程中记录的异常日志或关键日志,这也是一个比较常见的需求。

4. 标签查询

标签查询一般可以认为是对服务名、容器 IP 这样的字段查询需求,这也属于强需求之一。

5. 全文检索查询

全文检索查询是否属于强需求之一,其实是个值得权衡的问题。如果客户端在采集端已经做了一些预处理,如:把整行的日志 content 在采集时拆分成了具体的时间级别、异常类型等单个关键字段,这样来讲,全文检索查询可能就不是一个强需求了,但同时,备选方案的范围可能会更大一些。这里需要提醒的是,没有全文检索支持,并不代表不能模糊检索。借助列存储的高压缩率和高 IO 效率,在内存中进行模糊过滤的效果也很赞!

6. 聚合统计

聚合统计中最简单的是 Count 统计,更复杂一点的有基于更多字段维度的复杂聚合图表支持,这些功能在一些产品中也有提供,但需根据个体具体需求来判断该项是不是强需求。

7. 主动告警

主动告警意味着系统不仅具备被动查询功能,同时也能够及时发现问题并告警,这样才能减少故障时间。

介绍完业务需求方面的 7 个特点后,在设计架构时,就能够助力我们迅速 get 到需要考虑哪些方面了。

架构要求

1. 软硬成本

当然,成本是一定要的,不管是做什么设计,肯定需要考虑成本,这其中包括软硬的成本。

硬件成本指的是我们的机器数量:CPU、内存、磁盘等这样的资源。这里面存在一个问题,因为对于日志而言,我们讲数据量大,单条的体积可能也比较大,如果确定不需要全文检索,或只检索其中很少的几个关键字段,对于那些较长的字段,仅仅只是想随着搜索条件把它展示出来,这个时候我们可能就会考虑,对于不需要索引的这些数据,是不是可以通过一些更廉价的存储方式(比如像 OSS)存下来,这样可以节省整体的存储成本。

另一方面需要考虑软件成本,拿刚才 OSS 存储的例子,如果我们想用很高效的存储方式来存储索引的数据,而那些不需要查询的字段用 OSS 存储,这时的架构方案可能会稍微复杂一些,开发复杂度和难度,以及人力投入也会相对高一些,软件的整体成本也会相应增加。

2. 存储要有过期机制

数据的实效性对存储机制也提出了要求,对于数据的过期机制,需要考虑,如何保证和限制执行数据过期删除时的性能消耗不会对整个系统的吞吐有过大影响。

3. 异步处理,吞吐要大,不能被业务流量打垮

数据量大的场景下,要求日志系统在接受采极端数据的时候,需要考虑异步处理等手段,保证不能被业务流量打垮。如果说业务系统有问题了,日志系统也因此出现问题,导致不能使用日志系统来查询、排查业务问题,那这个平台存在的意义就会受到挑战。一般来说我们会用 MQ 这样的中间件来做异步的削峰填谷处理。

4. 即席查询能力(内存、缓存、并行、高效过滤等机制)

基于对查询速度的要求,能够秒级响应的存储方案会被优先选择。

5. 存储结构对时间范围查询友好

基于时间段的范围查询是最高频的场景之一,针对此类场景,我们可以考虑选择时序数据库,因其本身对时间序列查询做了成本上的优化,同时也是效率较高的方案。

6. 二级索引能力

高基数单点查询对索引能力提出了要求,这将限制我们对于时序数据库的选择。因为像 promethus 这样的时序数据库对高基数值的单点查询是存在问题的,这是由于它的存储的特点决定的。一般来说,如果我们想支持高基数值的单点查询,需要需要有一个二级属性能力的数据库。

7. 全文检索能力

如何支持模糊查询,也是我们要考量的一个因素。因为如果要做完整的全文检索能力支持,比如:分词、相关性算分排序等,我们的可选方案会被进一步限制。

8. 存储结构聚合操作友好(如列存储)

们知道对于聚合统计操作对话,列存储的聚合性能是比较高的,因为它有很高对压缩比,一次读盘可以读到很多有效的数据,整体对 IO 效率会很高。

9. 告警模块

最后一点就是架构里必须规划告警模块如何去做。

以上内容针对数据特点、业务需求提出的一些架构要求进行介绍,可以看出,核心取舍在于存储。下面一张图,展示了整个架构的处理流程和关键组件,接下来的内容将对存储部分的选型进行展开介绍。

存储方案选型

上图中关于存储部分,有几个开源的可选存储中间件:像 Cassandra、Hbase、ElasticSearch、ClickHouse、Grafana Loki等。下图将会针对这些中间件的优缺点进行对比分析:

上图的方案选型图表对各个方案的描述已经相对比较详细,在此就不再赘述,接下来我们看下在 Erda 中是如何做的。

Erda 日志分析平台实践

Erda 目前采用的其实是比较常见的实现方案:使用 Elasticsearch 作为底层存储。当然,其中也存在历史原因,Erda 的开源时间虽然并不是很长,但是其存在历史可以算比较久了。在当时看来,选择 Elasticsearch 也是比较合理的选择。当然,现状并不是终点,我们后面仍会持续探索在成本、效率方面更优的方案。

如果说选择 ES 这样的一个方案的话,具体应该怎么做呢?

刚才的方案选型图表中列出了使用 Elasticsearch 的大致核心思路,接下来我们具体深入看下如何去做。

之前提到,使用 Elasticsearch 方案的特点就是功能全和开箱即用,上图中列出了在 Erda 中所利用的一些关键能力来实现目前 Erda 想要提供的部分关键功能,如下图所示。

总的来说,Erda 目前采用的其实还是比较常规的方案,并在此基础上有一些小的优化,整个代码结构上也是做了一层抽象,并没有说以后就是绑死在 Elasticsearch 上面,后续我们还会考虑支持一些其他可替换方案。

Erda 日志分析平台未来的方向

对 Erda 日志分析平台而言,未来我们有几个努力的方向:

1. 存储更高效、可扩展

首先是存储方面,上文我们也提到,Erda 目前主要采用基于 Elasticsearch 的存储方案,但使用 Elasticsearch 有一个不可忽视的缺点,那就是它的整体资源占用成本相对较高,而像 Clickhouse、Grafana Loki 等,确实有各自的优势需要我们去借鉴。所以说 Erda 作为一个开源产品,后续可能会支持更多的底层存储,用户可以在这些方案之间根据自身的需求和成本来进行选择。

另外,自研存储也将会是我们的一个投入方向,因为监控领域除了日志,还有指标、Trace 数据。这些数据能否采用一个统一的存储内核来降低系统的复杂度,同时可以对不同数据类型做专项优化来平衡成本和性能,这些都是我们考虑自研存储的出发点。

2. 告警更便捷、更智能

目前在 Erda 平台上,如果想从日志分析出发去创建告警规则,实际使用的链路还是有点长,所以后续我们会优化这条链路上的产品和功能体验。

另外的一个方向就是智能化,基于日志的自动异常检测。在上文中有简单提到这点,就是说即使用户没有显式的去配置任何规则,系统也可以帮助用户去发现预期之外的一些异常。这里的异常,不一定非得是业务应用抛出的错误的堆栈,它是一个相对于“正常”的概念,即正常数据流中突然出现了一个非常不同寻常的数据,这可能会需要用到一些机器学习的模型来检测。


以上就是本次想要和大家分享的有关日志分析架构的一些内容,后续我们也将不忘初心,持续优化产品功能和用户体验,也非常期待有更多对此感兴趣的开发者参与进来与我们共建 Erda,每一条建议我们都会认真聆听,期待更多的声音帮助我们变得更好!

正文完